项目添加ElasticSearch搜索服务的流程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

这里对项目中添加ES服务做一个总结,从0到添加ES到项目中。

一、框架分析

使用ES做查询的话,他最好的地方就是不再走数据库,这样减少了数据库访问资源,同时有倒排索引的存在,查询会非常的快。
图例解析
在这里插入图片描述

二、环境搭建

1.ElasticSearch的下载安装

传送门

2.Logstash的下载安装

传送门
这里环境的搭建个人人为是蛮麻烦的。所以单独为其写了博客。
当环境搭建好之后,本地应该有ES的服务端,包括IK分词依赖,Head插件。还有Logstash的服务端,包括LogStash-input-jdbc的插件。

2.数据的同步

这里在前面一篇里已经有了介绍,然后由于系统有多个模块,这里是想将多个模块的数据同步到一起,就是将多个表的数据同步到一个表,这里原理就是将多个表查询的字段设置一个别名,别名保持一致。即可将多个表同步到一个ES索引中,这样就可以查询的时候查询一个索引获取所有的数据。后来考虑到性能开销以及后续可能这个索引会很大,还是采用了多个索引的模式。即先建立一个数据模板,后续各个表查询别名还是一致,不过同步到的是多个索引中。
到这里环境就ok了,数据也同步好了,

三、查询

查询的话,贴一下主要代码

// 条件搜索
            SearchRequest searchRequest = new SearchRequest(indices);
            // searchSourceBuilder将查询转换为es的查询语句
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 使用BoolQueryBuilder对象(复杂查询)
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            // 分页
            searchSourceBuilder.from(paramDTO.getPageNo() * paramDTO.getPageSize());
            searchSourceBuilder.size(paramDTO.getPageSize());

            // 分词匹配查询
            //MatchQueryBuilder termQueryBuilder = QueryBuilders.matchQuery("title", keyWord);
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyWord, "title", "description")
                    .type(MultiMatchQueryBuilder
                            .Type.BEST_FIELDS);
            // 精准匹配(不分词)
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("delete_flag", 0);
            // 使用constantScoreQuery查询不计入得分
            ConstantScoreQueryBuilder constantScoreQueryBuilder = QueryBuilders.constantScoreQuery(termQueryBuilder);
            boolQueryBuilder.must(multiMatchQueryBuilder)
                    .must(constantScoreQueryBuilder);
            searchSourceBuilder.query(boolQueryBuilder);
            searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
            // es查询默认只返回10条,需要给定数量
            // searchSourceBuilder.size(1000);

            // 高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.field("description");
            highlightBuilder.requireFieldMatch(false);
            highlightBuilder.preTags("<span style='color:red;font-weight:900'>");
            highlightBuilder.postTags("</span>");
            searchSourceBuilder.highlighter(highlightBuilder);
            System.out.println(searchSourceBuilder.toString());
            // 执行搜索
            searchRequest.source(searchSourceBuilder);

            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 解析结果
            List<Map<String, Object>> list = new ArrayList<>();
            for (SearchHit hit : search.getHits().getHits()) {
                // 解析高亮字段
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField title = highlightFields.get("title");
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();// 原数据
                // 解析 将原来的字段替换为我们高亮的字段
                if (title != null) {
                    Text[] fragments = title.fragments();
                    String nTitle = "";
                    for (Text text : fragments) {
                        nTitle += text;
                    }
                    sourceAsMap.put("title", nTitle);
                }
                HighlightField description = highlightFields.get("description");
                if (description != null) {
                    Text[] fragments = description.fragments();
                    String nDescription = "";
                    for (Text text : fragments) {
                        nDescription += text;
                    }
                    sourceAsMap.put("description", nDescription);

                }
                sourceAsMap.put("score", hit.getScore());
                list.add(sourceAsMap);
            }

            // 对查询到的分数进行缩放处理
            Float[] orgData = new Float[list.size()];
            for (int i = 0; i < list.size(); i++) {
                orgData[i] = (Float) list.get(i).get("score");
            }
            Float[] newData = new Float[list.size()];
            if (paramDTO.getPageSize().equals(5)) {
                newData = dataZoom(orgData, 60, 100);
            } else {
                long pages = search.getHits().getTotalHits().value / paramDTO.getPageSize(); // 有多少页
                pages = pages == 0 ? 2 : pages;
                long avePages = 100 / pages; //每页的区间

                newData = dataZoom(orgData, (int) (100 - ((paramDTO.getPageNo() + 1) * avePages)), (int) (100 - ((paramDTO.getPageNo()) * avePages)));
            }

            for (int i = 0; i < list.size(); i++) {
                list.get(i).put("score", newData[i]);
            }
            date.setData(list);
            // 将总数放入
            date.setTotal(search.getHits().getTotalHits().value);
            return date;

数据的缩放

    /**
     * 对数据进行缩放处理
     *
     * @param: orgData 源数据  minSection 区间最小值 maxSection 区间最大值
     * @return: java.lang.Float[]
     * @author PengG
     * @date: 2020/12/7 10:59
     */
    private Float[] dataZoom(Float[] orgData, int minSection, int maxSection) {
        Float[] newData = new Float[orgData.length];
        for (int i = 0; i < orgData.length; i++) {
            // 数据归一化
            Float tmp = (orgData[i] - orgData[orgData.length - 1]) / (orgData[0] - orgData[orgData.length - 1]);
            // 数据缩放
            newData[i] = minSection + tmp * (maxSection - minSection);
        }
        return newData;
    }

总结

到这里项目中添加ES服务就结束了,其实这里一想还是很简单的,关键要知道有哪些东西,不要走弯路,像我中间就使用过canel同步过数据,结果整了很久效果还不是很理想,后来换了logstash之后,才发现人家配套的用起来真香。同时要结合项目需求,慢慢摸索这些中间件还是很耗时间的,后续有新鲜的东西再继续完善

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值