Elasticsearch实现复合查询,高亮结果等技巧

一.Es的配置

实现es的全文检索功能的第一步,首先从与es进行连接开始,这里我使用的是es的5.x java api语法.

public TransportClient esClient() throws UnknownHostException{
        Settings settings = Settings.builder()
                .put("cluster.name", "my-application") //节点的名字
                .put("client.transport.sniff", true)
                .build();
        
        InetSocketTransportAddress iAddress = new InetSocketTransportAddress( //连接es的ip地址和端口号
                InetAddress.getByName("127.0.0.1"),9300
                );
        
        //根据先前的配置生成client,后面的操作基本都是基于这个
        TransportClient client = new PreBuiltTransportClient(settings)
                .addTransportAddress(iAddress);
        return client;
    }

 

二.功能的实现

以下是全文检索的核心代码,包括我遇到的错误以及解决,包括如何对高亮失效,高亮不全等的解决.

1.查询条件

  TransportClient esClient = esClient();   //获取先前生成的client
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();  //生成复合查询构造器
        
        boolQuery.mustNot(
                QueryBuilders.matchQuery("",)  //字段必须不包含啥 
                );
        
        boolQuery.should(
                QueryBuilders.matchQuery(, )   //字段可以包含啥,相当于或者
                );

        boolQuery.must(
                QueryBuilders.matchQuery(,)  //字段必须包含啥
                );

 

2.高亮条件

//配置标题高亮显示

        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        highlightBuilder.field(title);      //高亮查询字段
        highlightBuilder.field(content);    //高亮查询字段
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");

        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

 

3.查询配置

// 根据字段进行排序,这里我根据时间进行倒排
FieldSortBuilder timeSort = SortBuilders.fieldSort("time").order(SortOrder.DESC); 
         
        //查询请求生成
        SearchRequestBuilder requestBuilder = esClient.prepareSearch(indexname)//索引名字
                        .setTypes(indextype)      //索引类型
                        .setQuery(boolQuery)      //配置查询条件
                        .addSort(new ScoreSortBuilder())   //根据查询相关度进行排序
                        .addSort(timeSort)                 //再根据时间进行排序
                        .setTrackScores(true)             //避免分页之后相关性乱了
                        .highlighter(highlightBuilder)     //配置高亮
                        .setFrom(from)                 //设置分页
                        .setSize();

 

4.获取查询结果对其高亮

    //获取查询结果
        SearchResponse searchResponse = requestBuilder.get();
        
        List<Map<String, Object>> course  = new ArrayList<>(); 
        if(searchResponse.status() != RestStatus.OK){
            return course;
        }
        for(SearchHit hit:searchResponse.getHits()){

            //获取高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField titleField = highlightFields.get("");
            HighlightField contentField = highlightFields.get("");
            
            
            
            Map<String, Object> source = hit.getSource();
            
            //千万记得要记得判断是不是为空,不然你匹配的第一个结果没有高亮内容,那么就会报空指针异常,这个错误一开始真的搞了很久
            if(titleField!=null){
                Text[] fragments = titleField.fragments();  
                String name = "";
                for (Text text : fragments) {
                name+=text;
                }
                source.put("", name);   //高亮字段替换掉原本的内容
                }
            
            
            course.add(source);
        }
        esClient.close();     //用完记得关闭
        return course;

 

三.结语

这样前端所获取结果的搜索内容将会被<span style="color:red;"></span>所包含,比如我前端是微信小程序,所以直接获取内容进行渲染的话,就是一堆字符串,所以用的是小程序的富文本标签<rich-text>.

如果你觉得文章内容对你有用的话,不用忘记评论,点赞.

posted @ 2019-09-10 11:29 海中灯塔 阅读(...) 评论(...) 编辑 收藏