zoukankan      html  css  js  c++  java
  • Elasticsearch java高亮显示

    Elasticsearch java高亮显示

    • 为什么要写
      1. 因为版本原因很多网上的案例变动较大
      2. 基于springboot 2.2.2 elasticsearch 7.10.1

    原理

    • elastic支持,请求格式如下:

      {
          "query": {
              "bool": {
                  "should": [
                      {
                          "match": {
                              "addName": "test"
                          }
                      },
                      {
                          "match": {
                              "fileName": "环境"
                          }
                      }
                  ],
                  "minimum_should_match": 2
              }
          },
          "highlight": {
              "fields": { 
                  "fileName":{} 
               } 
           }
      }
      
      

    基于API的实现

    1. 网上找到的常用版本

      public Object queryKeyWord(HttpServletRequest request,
                                  @RequestParam(value = "keyWord")String keyWord,
                                  @RequestParam(value = "page")int page,
                                  @RequestParam(value = "size")int size) throws IOException {
              // 在索引中进行查询
              SearchRequest searchRequest = new SearchRequest(esDocumentIndex);
              SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
      
              // 搜索名字
              TermQueryBuilder termQuery = QueryBuilders.termQuery("fileName", keyWord);
              sourceBuilder.query(termQuery);
              sourceBuilder.from(page);
              sourceBuilder.size(size);
             // sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
      
              // 添加高亮
              HighlightBuilder highlightBuilder = new HighlightBuilder();
              HighlightBuilder.Field highlightName = new HighlightBuilder.Field("fileName"); //把 fileName 域设为高亮
              highlightBuilder.field(highlightName);
              highlightBuilder.preTags("<span style='color:red'>");
              highlightBuilder.postTags("</span>");
              sourceBuilder.highlighter(highlightBuilder);
      
              // 发起请求
              searchRequest.source(sourceBuilder);
              SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 保存高亮
              ArrayList<Map<String,Object>> list = new ArrayList<>();
              SearchHits hits = searchResponse.getHits();
              for (SearchHit hit : hits) {
                  // 获取高亮域
                  Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                  HighlightField highlight = highlightFields.get("fileName");
                  // 获取原本的 SourceMap
                  Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                  // 这里一定要先判断域是否为空,因为可能查询不到结果
                  if (highlight != null) {
                      Text[] fragments = highlight.fragments();
                      StringBuilder new_name = new StringBuilder();
                      for (Text text : fragments) {
                          new_name.append(text);
                      }
                      // 覆盖原本的 SourceMap
                      sourceAsMap.put("fileName", new_name);
                  }
                  list.add(sourceAsMap);
              }
              return list;
          }
      
    2. 方法二

      实现DocumentRepository

      public interface DocumentRepository extends ElasticsearchRepository<DocumentPo,Long> {
      }
      
      

      构建查询

       // 构建查询条件
              NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
              // 添加基本分词查询
              queryBuilder.withQuery(QueryBuilders.matchQuery("fileName", keyWord));
              // 添加高亮
              HighlightBuilder highlightBuilder = new HighlightBuilder();
              HighlightBuilder.Field highlightName = new HighlightBuilder.Field("fileName"); //把 name 域设为高亮
              highlightBuilder.field(highlightName);
              highlightBuilder.preTags("<span style='color:red'>");
              highlightBuilder.postTags("</span>");
              queryBuilder.withHighlightBuilder(highlightBuilder);
              queryBuilder.withPageable(PageRequest.of(page, size));
      
              // 搜索,获取结果
             Page<DocumentPo> items = documentRepository.search(queryBuilder.build());
      

      发现高亮没有生效,跟踪源码发现在箭头区域给过滤掉了

      返回结果时

      解决办法

      自己重写这个方法,查看结构自己定义一个mapper转换,返回就行。

      但是查看search方法没有接收参数

      @NoRepositoryBean
      public interface ElasticsearchRepository<T, ID> extends ElasticsearchCrudRepository<T, ID> {
      
      	<S extends T> S index(S entity);
      
      	/**
      	 * This method is intended to be used when many single inserts must be made that cannot be aggregated to be inserted
      	 * with {@link #saveAll(Iterable)}. This might lead to a temporary inconsistent state until {@link #refresh()} is
      	 * called.
      	 */
      	<S extends T> S indexWithoutRefresh(S entity);
      
      	Iterable<T> search(QueryBuilder query);
      
      	Page<T> search(QueryBuilder query, Pageable pageable);
      
      	Page<T> search(SearchQuery searchQuery);
      
      	Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);
      
      	void refresh();
      
      	Class<T> getEntityClass();
      }
      
      

      继续向下找,发现search调用的是queryForPage

      @Override
      	public Page<T> search(SearchQuery query) {
      
      		return elasticsearchOperations.queryForPage(query, getEntityClass());
      	}
      

      继续找发现在下一步参数中多了一个resultsMapper,而出问题的方法也在这个参数对象中,于是我们只需要重写这个参数并调用这个方法就可以了。

      	@Override
      	public <T> AggregatedPage<T> queryForPage(SearchQuery query, Class<T> clazz) {
      		return queryForPage(query, clazz, resultsMapper);
      	}
      
      

      重写参数

      public class HighlightResultMapper implements SearchResultMapper {
          @Override
          public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> clazz, Pageable pageable) {
              long totalHits = searchResponse.getHits().getTotalHits();
              List<T> list = new ArrayList<>();
              SearchHits hits = searchResponse.getHits();
              if (hits.getHits().length> 0) {
                  for (SearchHit searchHit : hits) {
                      Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                      T item = JSON.parseObject(searchHit.getSourceAsString(), clazz);
                      Field[] fields = clazz.getDeclaredFields();
                      for (Field field : fields) {
                          field.setAccessible(true);
                          if (highlightFields.containsKey(field.getName())) {
                              try {
                                  field.set(item, highlightFields.get(field.getName()).fragments()[0].toString());
                              } catch (IllegalAccessException e) {
                                  e.printStackTrace();
                              }
                          }
                      }
                      list.add(item);
                  }
              }
              return new AggregatedPageImpl<>(list, pageable, totalHits);
          }
      
          @Override
          public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
              return null;
          }
      
      }
      
      

      更改调用过程

      // 构建查询条件
              NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
              // 添加基本分词查询
              queryBuilder.withQuery(QueryBuilders.matchQuery("fileName", keyWord));
              // 添加高亮
              HighlightBuilder highlightBuilder = new HighlightBuilder();
              HighlightBuilder.Field highlightName = new HighlightBuilder.Field("fileName"); //把 name 域设为高亮
              highlightBuilder.field(highlightName);
              highlightBuilder.preTags("<span style='color:red'>");
              highlightBuilder.postTags("</span>");
              queryBuilder.withHighlightBuilder(highlightBuilder);
              queryBuilder.withPageable(PageRequest.of(page, size));
      
              // 搜索,获取结果
            // Page<DocumentPo> items = documentRepository.search(queryBuilder.build());
      
              SearchQuery searchQuery = null;
              searchQuery=  queryBuilder.build();
              Page<DocumentPo> items = new ElasticsearchRestTemplate(restHighLevelClient).queryForPage(searchQuery,DocumentPo.class,new HighlightResultMapper());
      

    完!

    作者:Ants_double

    出处:https://www.cnblogs.com/ants_double/

    本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!

    如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [大拇指],谢谢!

  • 相关阅读:
    数位DP
    组合
    卢卡斯Lucas&扩展卢卡斯
    [HNOI2014]道路堵塞
    [模板]三维凸包(无讲解)
    [CF526G]Spiders Evil Plan
    [CCPC2019 ONLINE]H Fishing Master
    [CCPC2019 ONLINE]E huntian oy
    [CF1037H]Security
    [CF1037F]Maximum Reduction
  • 原文地址:https://www.cnblogs.com/ants_double/p/15048532.html
Copyright © 2011-2022 走看看