# elasticsearch插件

# 安装版本

我们是针对elasticsearch-6.x进行开发的插件,对elasticsearch的各种操作进行了封装,致力于开发者能快速进行项目检索内容的需求,示例demo使用的版本是elasticsearch-6.4.1开发,推荐可以选择这个版本安装,便于出现问题,我们能快速复现。

# 插件集成

# 添加插件依赖

<dependency>
    <groupId>top.ssrsdev</groupId>
    <artifactId>plugin-elasticsearch</artifactId>
</dependency>

# 配置ES服务

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/search-config.png

# 索引创建

  1. 新建一个索引文档映射实体类

public class ArticleDoc extends BasicDoc {

    /**
     * 内容
     */
    @FieldWeight
    @Index(type = EsDataType.TEXT, stored = true, analyzer = AnalyzerType.CONFIG)
    private String content;
}

  1. 新建一个索引服务项
public class ArticleDocIndex extends IIndex {

    public static final String ID = "com.ssrs.elasticsearch.service.impl.ArticleDocIndex";

    @Override
    public String getTypeName() {
        return "Article";
    }

    @Override
    public void build(Date date) {
        BulkService bulkService = new BulkService(ArticleDoc.class, BulkService.OP_INDEX, getTypeName());
        try {
            // todo 根据传过来的date,从数据库查询数据增量增加添加数据到elasticsearch
            bulkService.bulk();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void delete(Date date) {

    }

    @Override
    public String getExtendItemName() {
        return "文章创建索引";
    }
}
  1. 将上面的扩展服务项添加到plugin插件配置中去
<extend-item>
    <id>com.ssrs.elasticsearch.service.impl.ArticleDocIndex</id>
    <class>com.ssrs.elasticsearch.service.impl.ArticleDocIndex</class>
    <description>文章创建索引扩展服务项</description>
    <extend-service>com.ssrs.elasticsearch.service.IndexService</extend-service>
</extend-item>

  1. 重启项目,执行创建索引定时任务

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/search-createIndex.png

自动创建索引任务默认3分钟执行一次,可以根据项目需求自行调整。

  1. 索引创建完成

查看elasticsearch-head,acticle索引创建成功

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/acticle-index.png

查看索引库管理:

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/indexlibmanager.png

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/article-detail.png

# 内容检索

我们针对elasticsearch的各种检索操作都封装成了一个个QueryBuilder,位于com.ssrs.elasticsearch.search包下,可以使用这些QueryBuilder快速实现文档检索功能,大大减少了es的学习成本,即使没有接触过ES也可以根据这些QueryBuilderr来实现文档检索。

http://eightroes-doc.oss-cn-beijing.aliyuncs.com/img/search-package.png

示例demo(只是示例,具体实现根据自己的需求自行调整):

    public void query() {
        String q = "检索词"; // 检索词
        Boolean needAggs = true; // 是否需要聚合数据
        String type = "Article"; // 检索类型
        String beginTime = "2019-12-12 12:12:12"; // 开始时间
        String endTime = "2020-12-12 12:12:12"; // 结束时间
        // 分页
        int pageIndex = 0;
        int pageSize = 100;

        BoolQueryBuilder boolQB = new BoolQueryBuilder();
        try {
            // 分类检索
            QueryHelper.makeShouldBuilders(boolQB, "文章分类", "docTypeCode");
            // 检索词检索
            q = URLDecoder.decode(q, StandardCharsets.UTF_8.name());
            if (StrUtil.isNotEmpty(q)) {
                q = q.replace("\\s", "");
                String[] fields = QueryHelper.getFields("content");
                if (fields.length == 0) {
                    fields = new String[]{"title"};
                }
                boolQB.must(QueryBuilders.multiMatchQuery(q, fields, "or", WordsHitRatioConfig.getValue()));
            }
        } catch (UnsupportedEncodingException uee) {
            uee.printStackTrace();
            log.error("检索参数转码异常");
        }
        // 时间范围条件
        if (StrUtil.isNotEmpty("2020-") || StrUtil.isNotEmpty(endTime)) {
            DateRangeQueryBuilder drQB = QueryBuilders.dateRangeFilter("publishDate");
            if (StrUtil.isNotEmpty(beginTime)) {
                drQB.gte(beginTime);
            }
            if (StrUtil.isNotEmpty(endTime)) {
                drQB.lte(endTime);
            }
            boolQB.must(drQB);
        }

        Searcher searcher = new Searcher().from(pageSize * pageIndex).size(pageSize);
        // 聚合
        if (needAggs) {
            searcher.addAggs(new Searcher.Aggs("contentAgg", 999));
        }
        searcher.addSource("id").addSource("title").addSource("summary").addSource("content");
        // 高亮
        searcher.highlight(new Searcher.Highlight().addField(new Searcher.Field("title").setNumberOfFragments(2))
                .addField(new Searcher.Field("summary").setFragmentSize(50).setNumberOfFragments(2)));
        if (boolQB.isEmpty()) { // 如果没有任何检索条件,查询所有数据
            boolQB = new BoolQueryBuilder().should(QueryBuilders.matchAll());
        }
        searcher.setQuery(boolQB.build());
        // 排序
        searcher.addSort(new Searcher.Sort("_score", OrderType.DESC)); // 默认按照得分排序
        try {
            long begin = System.currentTimeMillis();
            String resultStr = new SearchService().doSearch(IIndex.getIndexAlias(), type, searcher.toString());
            long end = System.currentTimeMillis();
            JSONObject result = JSONUtil.parseObj(resultStr);
            result = QueryHelper.addCostData(result, "cost", end - begin);
            if (needAggs) {
                JSONObject aggs = result.getJSONObject("aggs");
                if (!ObjectUtil.isEmpty(aggs)) {
                    QueryHelper.findCodeName(aggs.getJSONArray("contentAggs1"), aggs.getJSONArray("contentAggs2"));
                }
            }
            // 打印结果
            log.info("result:{}", JSONUtil.toJsonPrettyStr(result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }