Elasticsearch:RestHighLevelClient实现搜索、分页、排序、高亮

ElasticSearch搜索引擎️

1.引入依赖

<dependency>
   <groupId>org.elasticsearch.clientgroupId>
   <artifactId>elasticsearch-rest-high-level-clientartifactId>
dependency>

2.自定义搜索DTO

/**
 * es搜索引擎参数
 *
 * @author xzx
 * @date 2022/10/4
 */
@Data
@Accessors(chain = true)
public class SearchReqDto {

   /**
    * 当前页码
    */
   private Integer pageNum = 1;
   /**
    * 页数
    */
   private Integer pageSize = 10;

   /**
    * 索引库名称
    */
   private String indices;
   /**
    * 关键词
    */
   private String keyword;

   /**
    * 排序字段
    */
   private String orderByColumn = "createdTime";
   /**
    * asc or desc
    */
   private String isAsc = "asc";
   /**
    * 高亮字段
    */
   private String[] highlightFields;
}

3.封装工具类、实现分页、高亮、排序

/**
 * elasticsearch配置类
 *
 * @author xzx
 * @date 2022/10/2
 */
@Configuration
public class ESConfig {

   @Value("${elasticsearch.url}")
   private String elasticsearchUrl;

   @Bean(name = "RestHighLevelClient")
   public RestHighLevelClient restHighLevelClient() {
      return new RestHighLevelClient(RestClient.builder(
              HttpHost.create(elasticsearchUrl)
      )
      );
   }
}
import java.io.IOException;

/**
 * elasticsearch 封装类
 *
 * @author xzx
 * @date 2022/10/4
 */
@Component
public class EsClient {

   @Autowired
   private RestHighLevelClient restHighLevelClient;

   /**
    * 搜索并完成分页、高亮、排序
    *
    * @param req
    * @param beanClass
    * @return responseResult
    * @throws IOException
    */
   public <T> ResponseResult findObject(SearchReqDto req, Class<T> beanClass) throws IOException {
      if (ObjUtil.isNull(req) || StringUtil.isBlank(req.getIndices())) {
         return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
      }
      if (StringUtil.isBlank(req.getOrderByColumn())) {
         req.setOrderByColumn("createdTime");
      }
      List<Object> resultList = null;
      Map<Object, Object> resultMap = new HashMap<>();
      SearchHits hits = queryBuilder(req);
      T bean = null;
      resultList = new ArrayList<>();
      //遍历查询结果并接收
      for (SearchHit searchHit : hits) {
         /**
          * 关键词为空或者没有高亮字段,不需要再处理
          */
         if (StringUtil.isBlank(req.getKeyword()) || ArrayUtil.isEmpty(req.getHighlightFields())) {
            bean = JSONUtil.toBean(searchHit.getSourceAsString(), beanClass);
         } else {
            bean = replaceAttr(searchHit, req.getHighlightFields(), beanClass);
         }
         if (ObjUtil.isNotNull(bean)) {
            resultList.add(bean);
         }
      }
      resultMap.put("total", resultList.size());
      resultMap.put("record", resultList);
      return ResponseResult.okResult(resultMap);
   }

   /**
    * 构造查询条件,获取原生返回数据
    *
    * @param req 查询条件
    * @return SearchHit
    * @throws IOException
    */
   public SearchHits queryBuilder(SearchReqDto req) throws IOException {
      SearchSourceBuilder builder = new SearchSourceBuilder();
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
      HighlightBuilder highlightBuilder = new HighlightBuilder();

      int pageNum = req.getPageNum() > 0 ? req.getPageNum() : 1;
      int pageSize = req.getPageSize() > 0 ? req.getPageSize() : 10;
      //设置分页
      builder.from((pageNum - 1) * pageSize);
      builder.size(pageSize);

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

      //模糊查询
      if (StringUtil.isBlank(req.getKeyword())) {
         boolQueryBuilder.should(QueryBuilders.matchAllQuery());
      } else {
         boolQueryBuilder.should(QueryBuilders.matchQuery("all", req.getKeyword()));
      }
      //对查询结果进行排序
      SortOrder order = SortOrder.ASC;
      if (SortOrder.DESC.name().equalsIgnoreCase(req.getIsAsc())) {
         order = SortOrder.DESC;
      }
      builder.query(boolQueryBuilder).sort(req.getOrderByColumn(), order);
      SearchRequest searchRequest = new SearchRequest(req.getIndices());
      searchRequest.source(builder);
      SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      return searchResponse.getHits();
   }


   /**
    * 将高亮字段替换
    *
    * @param searchHit 查询结果
    * @param attrs     字段名
    * @return T
    */
   private <T> T replaceAttr(SearchHit searchHit, String[] attrs, Class<T> beanClass) {
      T bean = null;
      Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
      for (String field : attrs) {
         HighlightField hField = highlightFields.get(field);
         if (hField != null) {
            //替换高亮字段
            Text[] fragments = hField.fragments();
            StringBuilder text = new StringBuilder();
            for (Text textGet : fragments) {
               text.append(textGet);
            }
            //对象的值只能读一次,否则会被覆盖
            if (ObjUtil.isNull(bean)) {
               //转换数据类型
               bean = JSONUtil.toBean(searchHit.getSourceAsString(), beanClass);
            }
            //设置对象的属性值
            ReflectUtil.invokeSetter(bean, field, text.toString());
         }
      }
      return bean;
   }
}

反射工具类ReflectUtil是我自定义的,原理是反射,可以引入hutool的工具包,同样也可以实现该结果

image-20221009160754939


你可能感兴趣的:(ElasticStack,elasticsearch,搜索引擎,大数据)