elasticsearch通用工具类

虚幻大学 xuhss 463℃ 0评论

Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475
  这几天写了一个关于es的工具类,主要封装了业务中常用es的常用方法。

  本文中使用到的elasticsearch版本6.7,但实际上也支持es7.x以上版本,因为主要是对springboot提供的:ElasticsearchRestTemplate 提供的API做的二次封装。目的是:让不懂es的开发人员新手也能轻松上手。

一、概述

整个工程分为es-api与es-server。

es-api为对外公共jar,包含了es映射实体;

es-server包含了具体的es工具类与Repository接口(下文会提到)。并通过necos配置中心统一管理es配置参数。

外部业务模块可引入es-api jar maven依赖,由Jar提供的入口,通过httpClient或feign调用(springcloud分布式项目)到es-server服务上的es工具类,得到需要的数据。

二、使用

这里仅以springcloud分布式项目简单为例

业务方用户服务user 引入es-api maven

/**
 * @author: shf
 * description: es-server feign接口
 */
public interface EsServerClient {
 @PostMapping(value = "/queryList", produces = {"application/json"})
 public  List queryList(@RequestBody T t);
}

在user服务中创建feignClient继承自es-api中的EsServerClient

@FeignClient(contextId = "esFeignClient", name = "es-server")
public interface EsFeignClient extends EsServerClient {
}

在user服务的代码中即可调用

@AutoWired
public EsFeignClient esFeignClient;

public void test() {
 //.......如业务方Dto与es映射实体转换 等省略
 //....
  EmployeeEs employee = new EmployeeEs();
 List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation("李四", EntityEs.SHOULD, 20F)).collect(Collectors.toList());
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList).put(EmployeeEs::getUserAge, employee.new RangeRelation(20, EntityEs.GTE, null, null, EntityEs.MUST)));
 //排序查询
 employee.setOrderMap(new EsMapUtil().put(EmployeeEs::getUserId, SortOrder.DESC));
 List employeeEs = esFeignClient.queryList(employee);
 //.....employeeEs与业务方Dto转换
}

三、具体实现

es-api 引入es依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
 <artifactId>spring-boot-starter-data-elasticsearchartifactId>
 <exclusions>
 <exclusion>
 <groupId>org.elasticsearch.clientgroupId>
 <artifactId>transportartifactId>
 exclusion>
 <exclusion>
 <groupId>org.elasticsearch.clientgroupId>
 <artifactId>elasticsearch-rest-high-level-clientartifactId>
 exclusion>
 exclusions>
dependency>
<dependency>
 <groupId>org.elasticsearch.clientgroupId>
 <artifactId>transportartifactId>
 <version>6.7.0version>
dependency>
<dependency>
 <groupId>org.elasticsearch.clientgroupId>
 <artifactId>elasticsearch-rest-high-level-clientartifactId>
 <version>6.7.0version>
dependency>

排除后重新引入对应的Es版本6.7,避免因版本不一致导致的一些坑。

es-server 服务 application.yml配置es

spring:
 elasticsearch:
 rest:
 #ES的连接地址,多个地址用逗号分隔
 uris: localhost:9200
 username: kibana
 password: pass
 #连接超时时间
 connection-timeout: 1000
 #读取超时时间
 read-timeout: 1000

一、映射实体

1、与ES mapping结构对应的映射实体:EmployeeEs

说明:

①设置的字段与该es对应的该索引完全对应,不存在多余字段。

②项目中引入了spring-boot-starter-data-elasticsearch,所以可直接使用注解形式设置索引信息与mapping结构信息,详见示例

③@JsonIgnoreProperties({"orderMap","pageNumber","pageSize","highlightFields","preTags","postTags","fieldQueryMap","scrollId","aggregationMap","multiLayerQueryList"})

作用:在保存文档到es时忽略父类EntityEs中的功能性字段,下文会提到

④@EsRepository(EmployeeEsRepository.class)

作用:通过注解过去该映射对应的Repository接口

f5f5c006d90902e178a2900e11ccf1c6 - elasticsearch通用工具类eea7a85266d5d32cb683305f612188b8 - elasticsearch通用工具类

/**
 * 员工对象
 * 
 * 注解:@Document用来声明Java对象与ElasticSearch索引的关系 indexName 索引名称 type 索引类型 shards 主分区数量,默认5
 * replicas 副本分区数量,默认1 createIndex 索引不存在时,是否自动创建索引,默认true

*/
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EsRepository(EmployeeEsRepository.class)
@JsonIgnoreProperties({"orderMap","pageNumber","pageSize","highlightFields","preTags","postTags","fieldQueryMap","scrollId","aggregationMap","multiLayerQueryList"})
@Document(indexName = "employee\_index", type = "employee\_type", shards = 1, replicas = 0, createIndex = true)
public class EmployeeEs extends EntityEs {

 @Id
 @Field(type = FieldType.Keyword)
 private Long userId;

 //@Field(type = FieldType.Text, analyzer = "ik\_max\_word")
 @MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik\_max\_word"), otherFields = @InnerField(suffix = "trueName", type = FieldType.Keyword))
 private String userName;

 @Field(type = FieldType.Keyword)
 private String userCode;

 @Field(type = FieldType.Integer)
 private Integer userAge;

 @Field(type = FieldType.Keyword)
 private String userMobile;

 @Field(type = FieldType.Date)
 private Date birthDay;

@Field(type = FieldType.Keyword)
 private String userSex;

 @Field(type = FieldType.Text, analyzer = "ik\_max\_word")
 private String remarks;
}

View Code

2、Repository接口:EmployeeEsRepository

/**
 * @author: shf
 * description: 可根据映射实体设置自动生成mapping结构;支持bean的增删改查操作
 * date: 2022/2/23 10:47
 */
@Component
public interface EmployeeEsRepository extends CrudRepository {
}

二、功能性实体类:EntityEs

说明:

①所有字段非es索引中的mapping属性字段,均为功能性字段,如排序、高亮、分页设置和一些常量设置等,详见贴码

②所有es映射实体类均需继承该实体

61c1e84a9f7f6fac98b482c9ba5228bf - elasticsearch通用工具类6f8a4d3d13e2a3c176490d0ffd75343c - elasticsearch通用工具类

/**
 * @author: shf description: 功能性字段(非mapping结构字段)
 * date: 2022/3/1 15:07
 */
@Data
public class EntityEs {

 /**
 * 组合多查询常量
 */
    /**
 * 文档 必须 匹配这些条件才能被查询到。相当于sql中的and
 */
    public static String MUST = "must";

 /**
 * 文档 必须不 匹配这些条件才能被查询到。相当于sql中的 not
 */
    public static String MUST\_NOT = "must\_not";

 /**
 * 如果满足这些语句中的任意语句,将增加 \_score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。相当于sql中的or
 */
    public static String SHOULD = "should";

 /**
 * 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档
 */
    public static String FILTER = "filter";

 /**
 * 至少匹配一项should子句
 */
    public static String MINIMUM\_SHOULD\_MATCH = "minimum\_should\_match";

 /**
 * 多字段排序查询
 */
    public EsMapUtil orderMap;

 /**
 * 分页查询
 */
    public Integer pageNumber;

 public Integer pageSize;

 /**
 * 游标分页ID
 */
    public String scrollId;

 /**
 * 游标分页ID有效期 单位:毫秒
 */
    public static Long scrollIdExpireTime = 1000 * 60 * 2L;

 /**
 * 游标分页ID最小有效期 单位:毫秒
 */
    public static Long scrollIdMinExpireTime = 1000L;

 /**
 * 高亮查询
 */
    public List highlightFields;

 public String preTags;

 public String postTags;

 /**
 * 字段查询
 */
 public EsMapUtil fieldQueryMap;

 /**
 * 聚合查询,当前只支持单个字段分组聚合count与sum,只针对keyword类型字段有效
 */
 public EsMapUtil aggregationMap;

 public static String COUNT = "count";
 public static String SUM = "sum";

 /**
 * 多层(bool)查询
 */
 public List multiLayerQueryList;

 /**
 * 范围查询常量
 */
 public static String GT = "gt";
 public static String GTE = "gte";
 public static String LT = "lt";
 public static String LTE = "lte";

 @Data
 public class RangeRelation {

 //String fieldKey;

 T fieldMinValue;

 String fieldMinMode;

 T fieldMaxValue;

 String fieldMaxMode;

 String queryMode;

 public RangeRelation(T fieldMinValue, String fieldMinMode, T fieldMaxValue, String fieldMaxMode, String queryMode) {
 this.fieldMinValue = fieldMinValue;
 this.fieldMinMode = fieldMinMode;
 this.fieldMaxValue = fieldMaxValue;
 this.fieldMaxMode = fieldMaxMode;
 this.queryMode = queryMode;
 }
 }

 @Data
 public class QueryRelation {

 T fieldValue;

 String queryMode;

 Float boostValue;

 public QueryRelation(T fieldValue, String queryMode) {
 this.fieldValue = fieldValue;
 this.queryMode = queryMode;
 }

 public QueryRelation(T fieldValue, String queryMode, Float boostValue) {
 this.fieldValue = fieldValue;
 this.queryMode = queryMode;
 this.boostValue = boostValue;
 }
 }

 @Data
 public class MultiLayerRelation {

 String queryMode;

 EsMapUtil map;

 List multiLayerList;

 public MultiLayerRelation(String queryMode, EsMapUtil map) {
 this.queryMode = queryMode;
 this.map = map;
 }

 public MultiLayerRelation(String queryMode, EsMapUtil map, List multiLayerList) {
 this.queryMode = queryMode;
 this.map = map;
 this.multiLayerList = multiLayerList;
 }
 }
}

View Code

三、小工具:EsMapUtil

说明:封装了一个map工具,编码简洁链式调用,应用了方法引用特性避免了字符串硬编码造成单词拼错的情况。

/**
 * @author: shf description: 函数式接口 便于方法引用获取实体字段名称
 * date: 2022/3/4 13:41
 */
@FunctionalInterface
public interface IGetterFunction extends Serializable{
 Object get(T source);
}

40328f8baf12574b67d68d4a61973f59 - elasticsearch通用工具类9e148a8391997032ee50e4afd13086c6 - elasticsearch通用工具类

/**
 * @author: shf
 * description
 * date: 2019/11/13 18:30
 */
public class EsMapUtil extends LinkedHashMap {

 public  EsMapUtil put(IGetterFunction fn, Object value) {
 String key = getFieldName(fn);
 super.put(key, value);
 return this;
 }

 public  EsMapUtil putStr(String key, Object value) {
 super.put(key, value);
 return this;
 }

 private static Map CLASS\_LAMDBA\_CACHE = new ConcurrentHashMap<>();

 /***
 * 转换方法引用为属性名
 * @param fn
 * @return
 */
 public  String getFieldName(IGetterFunction fn) {
 SerializedLambda lambda = getSerializedLambda(fn);
 String methodName = lambda.getImplMethodName();
 String prefix = null;
 if (methodName.startsWith("get")) {
 prefix = "get";
 }
 // 截取get之后的字符串并转换首字母为小写
 return toLowerCaseFirstOne(methodName.replace(prefix, ""));
 }

 /**
 * 首字母转小写
 *
 * @param s
 */
 public String toLowerCaseFirstOne(String s) {
 if (Character.isLowerCase(s.charAt(0))) {
 return s;
 } else {
 return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
 }
 }

 public static SerializedLambda getSerializedLambda(Serializable fn) {
 SerializedLambda lambda = CLASS\_LAMDBA\_CACHE.get(fn.getClass());
 if (lambda == null) {
 try {
 Method method = fn.getClass().getDeclaredMethod("writeReplace");
 method.setAccessible(Boolean.TRUE);
 lambda = (SerializedLambda) method.invoke(fn);
 CLASS\_LAMDBA\_CACHE.put(fn.getClass(), lambda);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 return lambda;
 }
}

View Code

四、Es通用工具类EsService

e92419df55ae0fdc808f7473d283bf8d - elasticsearch通用工具类82412e0d274539fc5b137af94dc2953d - elasticsearch通用工具类

/**
 * @author: shf description: es工具类,支持:分页(支持游标分页)、高亮(支持自定义标签)、范围查找、bool组合查询、多层bool套bool、多字段排序、加权重、聚合、二级字段查询
 * date: 2022/2/23 10:54
 */
@Component
@Slf4j
public class EsService {
 @Autowired
 private ElasticsearchRestTemplate restTemplate;

 @Autowired
 private ApplicationContext context;

 /**
 * 判断索引是否存在
 *
 * @return boolean
 */
    public  boolean indexExists(Class clazz) {
 return restTemplate.indexExists(clazz);
 }

 /**
 * 判断索引是否存在
 *
 * @param indexName 索引名称
 * @return boolean
 */
 public boolean indexExists(String indexName) {
 return restTemplate.indexExists(indexName);
 }

 /**
 * 创建索引(推荐使用:因为Java对象已经通过注解描述了Setting和Mapping)
 *
 * @return boolean
 */
 public  boolean indexCreate(Class clazz) {
 boolean createFlag = restTemplate.createIndex(clazz);
 boolean mappingFlag = restTemplate.putMapping(clazz);
 return createFlag && mappingFlag;

 }

 /**
 * 索引删除
 *
 * @param indexName 索引名称
 * @return boolean
 */
 public boolean indexDelete(String indexName) {
 return restTemplate.deleteIndex(indexName);
 }

 /**
 * 新增数据
 *
 * @param bean 数据对象
 */
 public  void saveBean(T bean) {
 EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
 CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
 crudRepository.save(bean);
 }

 /**
 * 批量新增数据
 *
 * @param list 数据集合
 */
 public  void saveList(List list) {
 if (CollectionUtils.isEmpty(list)) {
 return;
 }
 EsRepository esRepositoryAnno = list.get(0).getClass().getAnnotation(EsRepository.class);
 CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
 crudRepository.saveAll(list);
 }

 /**
 * 根据对象删除数据,主键ID不能为空
 *
 * @param bean 对象
 */
 public  void deleteByBean(T bean) {
 EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
 CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
 crudRepository.delete(bean);
 }

 /**
 * 根据对象集合,批量删除
 *
 * @param beanList 对象集合
 */
 public  void deleteAllByBeanList(List beanList) {
 if (CollectionUtils.isEmpty(beanList)) {
 return;
 }
 EsRepository esRepositoryAnno = beanList.get(0).getClass().getAnnotation(EsRepository.class);
 CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
 crudRepository.deleteAll(beanList);
 }

 /**
 * 删除所有
 */
 public  void deleteAll(T bean) {
 EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
 CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
 crudRepository.deleteAll();
 }

 /**
 * 修改数据
 *
 * @param t 修改数据对象,ID不能为空
 */
 public  boolean updateByBean(T t) throws IllegalAccessException {
 Class clazz = t.getClass();
 Field[] Fields = clazz.getDeclaredFields();
 String beanId = null;
 String beanIdName = null;
 for (Field f : Fields) {
 f.setAccessible(true);
 if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
 beanId = String.valueOf(f.get(t));
 beanIdName = f.getName();
 }
 }
 if (StringUtils.isBlank(beanId)) {
 log.warn("id不能为空");
 return false;
 }
 if (Objects.isNull(restTemplate.queryForObject(GetQuery.getById(beanId), clazz))) {
 log.warn("该文档不存在");
 return false;
 }
 Document annotation = (Document) clazz.getAnnotation(Document.class);
 UpdateRequest updateRequest = new UpdateRequest();
 //冲突重试
 updateRequest.retryOnConflict(1);
 updateRequest.doc(JSON.toJSONString(t), XContentType.JSON);
 //默认是\_id来路由的,用来路由到不同的shard,会对这个值做hash,然后映射到shard。所以分片
 updateRequest.routing(beanId);
 UpdateQuery query = new UpdateQueryBuilder().withIndexName(annotation.indexName()).withType(annotation.type()).withId(beanId)
 .withDoUpsert(false)//不加默认false。true表示更新时不存在就插入
 .withClass(clazz).withUpdateRequest(updateRequest).build();
 UpdateResponse updateResponse = restTemplate.update(query);
 if (!Objects.equals(updateResponse.getShardInfo().getSuccessful(), 1)) {
 return false;
 }
 return true;
 }

 /**
 * 根据bean ID 查询
 *
 * @param beanId
 * @param clazz
 * @param 
 */
 public  T queryBeanById(String beanId, Class clazz) {
 return restTemplate.queryForObject(GetQuery.getById(beanId), clazz);
 }

 /**
 * 数据查询,返回List
 *
 * @return List
 */
 public  List queryList(T t) throws IllegalAccessException, NoSuchFieldException {
 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
 Class clazz = (Class) t.getClass();
 Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
 Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
 List highlightFields = (List) clazz.getField("highlightFields").get(t);
 String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
 String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
 List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);

 String beanIdName = null;
 Field[] Fields = clazz.getDeclaredFields();
 for (Field f : Fields) {
 f.setAccessible(true);
 if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
 beanIdName = f.getName();
 break;
 }
 }
 //构建组合查询(支持权重)
 getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
 //处理多层bool查询
 getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);

 log.info("打印语句:{}", boolQueryBuilder.toString());
 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
 //支持多字段排序查询
 getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
 //支持多字段高亮查询并可自定义高亮标签规则
 getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);

 if (CollectionUtils.isEmpty(highlightFields)) {
 return restTemplate.queryForList(nativeSearchQueryBuilder.build(), clazz);
 } else {
 nativeSearchQueryBuilder.withPageable(PageRequest.of(0, 10000));
 ScrolledPage page = restTemplate.startScroll(EntityEs.scrollIdMinExpireTime, nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
 @Override
 public  AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
 List chunk = new ArrayList<>();
 for (SearchHit searchHit : response.getHits()) {
 if (response.getHits().getHits().length <= 0) {
 return null;
 }
 try {
 T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
 for (String fieldName : highlightFields) {
 Field f = clazz.getDeclaredField(fieldName);
 HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
 if (highlightField != null) {
 f.setAccessible(true);
 f.set(t, highlightField.fragments()[0].toString());
 }
 }
 chunk.add(t);
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } catch (NoSuchFieldException e) {
 e.printStackTrace();
 }
 }
 if (chunk.size() > 0) {
 return new AggregatedPageImpl<>((List) chunk);
 }
 return null;
 }

 @Override
 public  T mapSearchHit(SearchHit searchHit, Class type) {
 return null;
 }
 });
 return page.toList();
 }
 }

 /**
 * 分页查询
 *
 * @param t
 * @param 
 */
 public  List queryPage(T t) throws IllegalAccessException, NoSuchFieldException {
 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
 Class clazz = (Class) t.getClass();

 Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
 Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
 List highlightFields = (List) clazz.getField("highlightFields").get(t);
 String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
 String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
 Integer pageNumber = !Objects.isNull((Integer) clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
 Integer pageSize = !Objects.isNull((Integer) clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 10;
 List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);

 String beanIdName = null;
 Field[] Fields = clazz.getDeclaredFields();
 for (Field f : Fields) {
 f.setAccessible(true);
 if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
 beanIdName = f.getName();
 break;
 }
 }
 //构建组合查询(支持权重)
 getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
 //处理多层bool查询
 getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
 //支持多字段排序查询
 getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
 //支持多字段高亮查询并可自定义高亮标签规则
 getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);
 //分页查询
 nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));

 AggregatedPage page = null;
 if (CollectionUtils.isEmpty(highlightFields)) {
 page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz);
 } else {
 page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
 @Override
 public  AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
 List chunk = new ArrayList<>();
 for (SearchHit searchHit : response.getHits()) {
 if (response.getHits().getHits().length <= 0) {
 return null;
 }
 try {
 T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
 for (String fieldName : highlightFields) {
 Field f = clazz.getDeclaredField(fieldName);
 HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
 if (highlightField != null) {
 f.setAccessible(true);
 f.set(t, highlightField.fragments()[0].toString());
 }
 }
 chunk.add(t);
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } catch (NoSuchFieldException e) {
 e.printStackTrace();
 }
 }
 if (chunk.size() > 0) {
 return new AggregatedPageImpl<>((List) chunk);
 }

 return null;
 }

 @Override
 public  T mapSearchHit(SearchHit searchHit, Class type) {
 return null;
 }
 });
 }
 // 总记录数
 long totalElements = page.getTotalElements();
 // 总页数
 int totalPages = page.getTotalPages();
 // 当前页号
 //int currentPage = page.getPageable().getPageNumber();
 // 当前页数据集
 List beanList = page.toList();
 List content = page.getContent();
 System.out.println(beanList);
 //TODO 根据项目中的分页封装类将以上数据设置后返回即可
 return Lists.newArrayList();
 }

 /**
 * 游标分页
 *
 * @param t
 * @param 
 */
 public  List queryScrollPage(T t) throws IllegalAccessException, NoSuchFieldException {
 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
 Class clazz = (Class) t.getClass();
 String scrollId = (String) clazz.getField("scrollId").get(t);
 if (StringUtils.isNotBlank(scrollId)) {
 ScrolledPage page = restTemplate.continueScroll(scrollId, EntityEs.scrollIdExpireTime, clazz);
 // 总记录数
 long totalElements = page.getTotalElements();
 // 总页数
 //int totalPages = page.getTotalPages();
 // 当前页号
 //int currentPage = page.getPageable().getPageNumber();
 // 当前页数据集
 List beanSet = page.toList();
 List content = page.getContent();
 System.out.println("page.getScrollId:" + page.getScrollId());
 System.out.println(beanSet);
 //TODO 根据项目中的分页封装类将以上数据设置后返回即可
 return Lists.newArrayList();
 }
 Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
 Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
 List highlightFields = (List) clazz.getField("highlightFields").get(t);
 String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
 String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
 Integer pageNumber = !Objects.isNull((Integer) clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
 Integer pageSize = !Objects.isNull((Integer) clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 10;
 List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);

 String beanIdName = null;
 Field[] Fields = clazz.getDeclaredFields();
 for (Field f : Fields) {
 f.setAccessible(true);
 if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
 beanIdName = f.getName();
 break;
 }
 }
 //构建组合查询(支持权重)
 getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
 //处理多层bool查询
 getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
 //支持多字段排序查询
 getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
 //支持多字段高亮查询并可自定义高亮标签规则
 getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);
 //分页查询
 nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));

 ScrolledPage page = restTemplate.startScroll(EntityEs.scrollIdExpireTime, nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
 @Override
 public  AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
 List chunk = new ArrayList<>();
 for (SearchHit searchHit : response.getHits()) {
 if (response.getHits().getHits().length <= 0) {
 return null;
 }
 try {
 T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
 for (String fieldName : highlightFields) {
 Field f = clazz.getDeclaredField(fieldName);
 HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
 if (highlightField != null) {
 f.setAccessible(true);
 f.set(t, highlightField.fragments()[0].toString());
 }
 }
 chunk.add(t);
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } catch (NoSuchFieldException e) {
 e.printStackTrace();
 }
 }
 if (chunk.size() > 0) {
 return new AggregatedPageImpl<>((List) chunk);
 }
 return null;
 }

 @Override
 public  T mapSearchHit(SearchHit searchHit, Class type) {
 return null;
 }
 });

 // 总记录数
 long totalElements = page.getTotalElements();
 // 总页数
 //int totalPages = page.getTotalPages();
 // 当前页号
 //int currentPage = page.getPageable().getPageNumber();
 // 当前页数据集
 List beanSet = page.toList();
 List content = page.getContent();
 System.out.println("page.getScrollId:" + page.getScrollId());
 System.out.println(beanSet);
 //TODO 根据项目中的分页封装类将以上数据设置后返回即可
 return Lists.newArrayList();
 }

 /**
 * 聚合查询
 *
 * @param t
 * @param 
 */
 public  Map queryForAggregation(T t) throws IllegalAccessException, NoSuchFieldException {
 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
 Class clazz = (Class) t.getClass();

 Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
 Integer pageNumber = !Objects.isNull(clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
 Integer pageSize = !Objects.isNull(clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 1;
 Map aggregationMap = (LinkedHashMap) clazz.getField("aggregationMap").get(t);
 List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);

 //构建组合查询(支持权重)
 getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
 //处理多层bool查询
 getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
 //分页查询
 nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));

 // 创建聚合查询条件
 String aggKey = null;
 String aggValue = null;
 for (Map.Entry entry : aggregationMap.entrySet()) {
 aggKey = entry.getKey();
 aggValue = entry.getValue();
 if (Objects.equals(aggValue, EntityEs.COUNT)) {
 TermsAggregationBuilder agg = AggregationBuilders.terms(aggKey).field(aggKey);
 nativeSearchQueryBuilder.addAggregation(agg);
 break;
 } else if (Objects.equals(aggValue, EntityEs.SUM)) {
 SumAggregationBuilder agg = AggregationBuilders.sum(aggKey).field(aggKey);
 nativeSearchQueryBuilder.addAggregation(agg);
 break;
 }
 }
 AggregatedPage page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz);
 // 取出聚合结果
 Aggregations entitiesAggregations = page.getAggregations();
 Map retMap = new HashMap<>();
 if (Objects.equals(aggValue, EntityEs.COUNT)) {
 Terms terms = (Terms) entitiesAggregations.asMap().get(aggKey);
 // 遍历取出聚合字段列的值,与对应的数量
 for (Terms.Bucket bucket : terms.getBuckets()) {
 // 聚合字段列的值
 String keyAsString = bucket.getKeyAsString();
 // 聚合字段对应的数量
 long docCount = bucket.getDocCount();
 log.info("keyAsString={},value={}", keyAsString, docCount);
 retMap.put(keyAsString, docCount);
 }
 } else if (Objects.equals(aggValue, EntityEs.SUM)) {
 Aggregation aggregation = entitiesAggregations.get(aggKey);
 retMap.put(aggregation.getName(), ((ParsedSum) aggregation).getValue());
 }
 // 当前页数据集
 List beanList = page.toList();
 System.out.println("当前页数据集:" + beanList);
 return retMap;
 }

 /**
 * 根据自定义查询条件批量查询
 *
 * @param searchQuery
 * @param clazz
 * @param 
 */
 public  List queryListBySearchQuery(SearchQuery searchQuery, Class clazz) {
 return restTemplate.queryForList(searchQuery, clazz);
 }

 /*------------------------------------------- private 私有方法 ----------------------------------------------*/

 private void getNestQueryBuilder(BoolQueryBuilder boolQueryBuilder, Class clazz, List multiLayerQueryList) throws NoSuchFieldException {
 if (!CollectionUtils.isEmpty(multiLayerQueryList)) {
 for (EntityEs.MultiLayerRelation r : multiLayerQueryList) {
 BoolQueryBuilder nestBoolQuery = QueryBuilders.boolQuery();
 EsMapUtil nestMap = r.getMap();
 getFieldQueryBuilder(nestBoolQuery, clazz, nestMap);
 if (Objects.equals(r.getQueryMode(), EntityEs.MUST)) {
 boolQueryBuilder.must(nestBoolQuery);
 } else if (Objects.equals(r.getQueryMode(), EntityEs.SHOULD)) {
 boolQueryBuilder.should(nestBoolQuery);
 } else if (Objects.equals(r.getQueryMode(), EntityEs.FILTER)) {
 boolQueryBuilder.filter(nestBoolQuery);
 } else if (Objects.equals(r.getQueryMode(), EntityEs.MUST\_NOT)) {
 boolQueryBuilder.mustNot(nestBoolQuery);
 }
 //递归嵌套
 if (!CollectionUtils.isEmpty(r.getMultiLayerList())) {
 //处理多层bool查询
 getNestQueryBuilder(nestBoolQuery, clazz, r.getMultiLayerList());
 }
 }
 }
 }

 /**
 * 构建组合查询(支持权重)
 *
 * @param boolQueryBuilder
 * @param clazz
 * @param queryMap
 */
 private void getFieldQueryBuilder(BoolQueryBuilder boolQueryBuilder, Class clazz, Map queryMap) throws NoSuchFieldException {
 if (queryMap != null && queryMap.size() > 0) {
 for (Map.Entry entry : queryMap.entrySet()) {
 String k = entry.getKey();
 List vList = new ArrayList();
 if (entry.getValue() instanceof List) {
 vList = (ArrayList) entry.getValue();
 } else {
 vList.add(entry.getValue());
 }
 FieldType type = null;
 if (k.indexOf(".") == -1) {
 Field f = clazz.getDeclaredField(k);
 if (f.isAnnotationPresent(org.springframework.data.elasticsearch.annotations.Field.class)) {
 type = f.getAnnotation(org.springframework.data.elasticsearch.annotations.Field.class).type();
 } else if (f.isAnnotationPresent(org.springframework.data.elasticsearch.annotations.MultiField.class)) {
 type = f.getAnnotation(org.springframework.data.elasticsearch.annotations.MultiField.class).mainField().type();
 }
 } else {
 //如果字段Field type定义的是Keyword,走matchQuery效果也是term精确查询
 type = FieldType.Text;
 }
 if (Objects.equals(type, FieldType.Text)) {
 for (Object o : vList) {
 if (o instanceof EntityEs.RangeRelation) {
 EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
 //范围查询
 getRangeBuilder(boolQueryBuilder, k, v);
 } else if (o instanceof EntityEs.QueryRelation) {
 EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
 if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.must(QueryBuilders.matchQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.must(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.mustNot(QueryBuilders.matchQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.mustNot(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.should(QueryBuilders.matchQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.should(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.filter(QueryBuilders.matchQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.filter(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 }
 }
 }
 } else if (Objects.equals(type, FieldType.Keyword)) {
 for (Object o : vList) {
 if (o instanceof EntityEs.RangeRelation) {
 EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
 //范围查询
 getRangeBuilder(boolQueryBuilder, k, v);
 } else if (o instanceof EntityEs.QueryRelation) {
 EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
 if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 }

 }
 }
 } else {
 for (Object o : vList) {
 if (o instanceof EntityEs.RangeRelation) {
 EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
 //范围查询
 getRangeBuilder(boolQueryBuilder, k, v);
 } else if (o instanceof EntityEs.QueryRelation) {
 EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
 if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
 if (Objects.isNull(v.getBoostValue())) {
 boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()));
 } else {
 boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
 }
 }
 }
 }
 }
 }
 }
 }

 /**
 * 构建范围查询
 *
 * @param boolQueryBuilder
 * @param k
 * @param v
 */
 private void getRangeBuilder(BoolQueryBuilder boolQueryBuilder, String k, EntityEs.RangeRelation v) {
 if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
 if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
 }
 if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
 boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
 if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
 }
 if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
 boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
 if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
 }
 if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
 boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
 }
 } else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
 if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
 } else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
 }
 if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
 } else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
 boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
 }
 }

 }

 /**
 * 构建排序查询
 *
 * @param beanIdName
 * @param orderMap
 * @param nativeSearchQueryBuilder
 */
 private void getOrderBuilder(String beanIdName, Map orderMap, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
 if (orderMap != null && orderMap.size() > 0) {
 orderMap.forEach((k, v) -> {
 nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((String) k).order((SortOrder) v));
 });
 } else {
 //无指定排序字段默认按ID倒序
 //nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(beanIdName).order(SortOrder.DESC));
 }
 }

 /**
 * 构建高亮查询
 *
 * @param highlightFields
 * @param preTags
 * @param postTags
 * @param nativeSearchQueryBuilder
 */
 private void getHighLightBuilder(List highlightFields, String preTags, String postTags, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
 if (highlightFields != null && highlightFields.size() > 0) {
 List highlightTitles = new ArrayList<>();
 for (String title : highlightFields) {
 highlightTitles.add(new HighlightBuilder.Field(title).preTags(preTags).postTags(postTags));
 }
 nativeSearchQueryBuilder.withHighlightFields(highlightTitles.stream().toArray(HighlightBuilder.Field[]::new));
 }
 }
}

View Code

五、单元测试

1、根据映射实体设置生成索引与mapping

  说明:启动项目会自动加载自动创建,如需要手动创建可调用方法
@Test
public void indexCreateTest() {
 System.out.println(esService.indexCreate(EmployeeEs.class));
}

2、删除指定索引

@Test
public void indexDelete() {
 System.out.println(esService.indexDelete("employee\_index"));
}

3、判断指定索引是否存在

@Test
public void indexExists() {
 System.out.println(esService.indexExists(EmployeeEs.class));
}

4、保存单个bean

@Autowired
private EsService esService;

@Test
public void saveBean() {
 System.out.println("-----es测试start...");
 EmployeeEs employee = EmployeeEs.builder().userId(9L).userName("张三1").userCode("abc").userAge(22).userMobile("12345678987")
 .remarks("今天天气好晴朗~").birthDay(new Date()).build();
 esService.saveBean(employee);
 System.out.println("-----es测试end...");
}

5、批量保存

@Test
public void saveList() throws ParseException {
 System.out.println("-----es测试start...");
 EmployeeEs employee =  EmployeeEs.builder().userId(1L).userName("张三").userCode("abc").userAge(18).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-9-20")).build();
 EmployeeEs employee1 = EmployeeEs.builder().userId(2L).userName("李四").userCode("abc").userAge(10).userSex("女").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-6-20")).build();
 EmployeeEs employee2 = EmployeeEs.builder().userId(3L).userName("王五").userCode("abc").userAge(10).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-5-20")).build();
 EmployeeEs employee3 = EmployeeEs.builder().userId(4L).userName("赵六").userCode("abc").userAge(20).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-8-20")).build();
 EmployeeEs employee4 = EmployeeEs.builder().userId(5L).userName("董七").userCode("abc").userAge(20).userSex("女").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-8-20")).build();

 esService.saveList(Lists.newArrayList(employee,employee1,employee2,employee3,employee4));
 System.out.println("-----es测试end...");
}

d91c157872e9a57ffb7bd8b91713a05f - elasticsearch通用工具类

6、根据ID删除指定Bean

@Test
public void deleteByBean() {
 EmployeeEs employee = EmployeeEs.builder().userId(1L).build();
 esService.deleteByBean(employee);
}

7、批量删除

@Test
public void deleteList() {
 EmployeeEs employee = EmployeeEs.builder().userId(1L).build();
 EmployeeEs employee1 = EmployeeEs.builder().userId(2L).build();
 esService.deleteAllByBeanList(Lists.newArrayList(employee,employee1));
}

8、删除该索引下所有数据

@Test
public void deleteAll() {
 esService.deleteAll(EmployeeEs.class);
}

9、修改数据(ID不能为空)

@Test
public void updateTest() throws IllegalAccessException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = EmployeeEs.builder().userId(5L).userName("张一").userCode("abcD").userAge(19).build();
 esService.updateByBean(employee);
 System.out.println("-----es测试end...");
}

10、根据ID查询指定Bean

@Test
public void queryById() {
 EmployeeEs employeeEs = esService.queryBeanById("2", EmployeeEs.class);
 System.out.println(employeeEs);
}

11、批量查询

/**
 * 涉及到了组合查询bool、权重、范围查找、排序
 */
@Test
public void queryList() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();
 List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation("李四", EntityEs.SHOULD, 20F)).collect(Collectors.toList());
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList).put(EmployeeEs::getUserAge, employee.new RangeRelation(20, EntityEs.GTE, null, null, EntityEs.MUST)));
 //排序查询
 employee.setOrderMap(new EsMapUtil().put(EmployeeEs::getUserId, SortOrder.DESC));
 List employeeEs = esService.queryList(employee);
 System.out.println(employeeEs);
 System.out.println("-----es测试end...");
}

打印出来的语句:

61756efcaaeae66d91d868a6e925af3d - elasticsearch通用工具类

查询结果:

8ea4d97f92fe7f875207962d4766cec9 - elasticsearch通用工具类

12、二级属性查询

@Test
public void querySecondList() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();
 employee.setFieldQueryMap(new EsMapUtil().putStr("userName.trueName", employee.new QueryRelation("张三", EntityEs.MUST)));
 List employeeEsList = esService.queryList(employee);
 System.out.println(employeeEsList);
 System.out.println("-----es测试end...");
}

先准备一条测试数据插入

b466e1c19da833537167feb3c1e6ef16 - elasticsearch通用工具类

581bf5908e2e868d986d2791fe80d477 - elasticsearch通用工具类

看下上面查询语句的结果:

2beae6e0b0560d2eacf48d859f5f2cc9 - elasticsearch通用工具类

由于userName的二级属性trueName的类型是keyword,所以是term精确查找

对比:

@Test
public void querySecondList() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, employee.new QueryRelation("张三", EntityEs.MUST)));
 //employee.setFieldQueryMap(new EsMapUtil().putStr("userName.trueName", employee.new QueryRelation("张三", EntityEs.MUST)));
 List employeeEsList = esService.queryList(employee);
 System.out.println(employeeEsList);
 System.out.println("-----es测试end...");
}

16ab18795aef0e9f3a54f9c26170f3ee - elasticsearch通用工具类

13、分页查询

@Test
public void queryPage() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();
 List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD), employee.new QueryRelation("李四", EntityEs.SHOULD)).collect(Collectors.toList());
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
 //分页
 employee.setPageNumber(0);
 employee.setPageSize(2);
 List employeeEs = esService.queryPage(employee);
 System.out.println(employeeEs);
 System.out.println("-----es测试end...");
}

14、游标分页查询

@Test
public void queryScrollPage() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 String scrollId = "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAADJEWMVFWMVBnb1ZSZDZsV1k2Y2JjLVlldw==";
 EmployeeEs employee = new EmployeeEs();
 if (StringUtils.isNotBlank(scrollId)) {
 //如果前端有传scrollId
 employee.setScrollId(scrollId);
 List employeeEs = esService.queryScrollPage(employee);
 System.out.println(employeeEs);
 } else {
 List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 20F), employee.new QueryRelation("李四", EntityEs.SHOULD)).collect(Collectors.toList());
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
 //每页页数
 employee.setPageSize(4);
 List employeeEs = esService.queryScrollPage(employee);
 System.out.println(employeeEs);
 }
 System.out.println("-----es测试end...");
}

15、多层bool套bool查询

@Test
public void queryMuiltiLayer() throws IllegalAccessException, NoSuchFieldException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();

 //多层bool查询
    employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST)));
 List multiLayerUserAgeList = Stream.of(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD)).collect(Collectors.toList());
 EntityEs.MultiLayerRelation multiLayerRelation = employee.new MultiLayerRelation(EntityEs.MUST, new EsMapUtil().put(EmployeeEs::getUserAge, multiLayerUserAgeList));
 employee.setMultiLayerQueryList(Lists.newArrayList(multiLayerRelation));

 List userEs = esService.queryList(employee);
 System.out.println(userEs);
 System.out.println("-----es测试end...");
}

示例:查找年龄为10或者18岁的男性员工

//错误案例
EmployeeEs employee = new EmployeeEs();
List ageList = Lists.newArrayList(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD));
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST))
 .put(EmployeeEs::getUserAge,ageList)
);
List userEs = esService.queryList(employee);
System.out.println(userEs);

5d17f055c0096f6dd475dbdfc5fdffc6 - elasticsearch通用工具类

结果年龄为20的赵六也被查询了出来。原因是:当should遇到must和filter时就不是或者了,而是应该的意思。可通过must嵌套一层解决。

c5770600066935fc12d060c05016220b - elasticsearch通用工具类

修改为多层bool查询

EmployeeEs employee = new EmployeeEs();
//修改为多层bool查询
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST)));
List multiLayerUserAgeList = Stream.of(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD)).collect(Collectors.toList());
EntityEs.MultiLayerRelation multiLayerRelation = employee.new MultiLayerRelation(EntityEs.MUST, new EsMapUtil().put(EmployeeEs::getUserAge, multiLayerUserAgeList));
employee.setMultiLayerQueryList(Lists.newArrayList(multiLayerRelation));

List userEs = esService.queryList(employee);

bf8c694e07b97d1d343ae6dd3fc31258 - elasticsearch通用工具类

7c890f6152c09072a9ddbac654f33aa8 - elasticsearch通用工具类

16、高亮查询

@Test
public void highlightTest() throws NoSuchFieldException, IllegalAccessException {
 System.out.println("-----es测试start...");
 EmployeeEs employee = new EmployeeEs();
 employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, employee.new QueryRelation("张三", EntityEs.MUST))
 .put(EmployeeEs::getRemarks, employee.new QueryRelation("天气", EntityEs.MUST)));
 employee.setHighlightFields(Lists.newArrayList("remarks"));
 //默认,可自定义高亮标签
 employee.setPreTags("# ");
 employee.setPostTags("

");
 List employeeEs = esService.queryList(employee);
 System.out.println(employeeEs);
 System.out.println("-----es测试end...");
}

f1243acf02e1c01ebe0d134b1a37ed2c - elasticsearch通用工具类

17、聚合查询

@Test
public void queryForAggregation() throws NoSuchFieldException, IllegalAccessException {
 System.out.println("-----queryForAggregation-es测试start...");
 EmployeeEs employee = new EmployeeEs();
 employee.setAggregationMap(new EsMapUtil().put(EmployeeEs::getUserAge, EntityEs.COUNT));
 Map employeeEsAggMap = esService.queryForAggregation(employee);
 System.out.println("返回结果:" + employeeEsAggMap);
 System.out.println("-----queryForAggregation-es测试end...");
}

393955ecacd4219926d8404a902377c6 - elasticsearch通用工具类

将上面的EntityEs.COUNT改为EntityEs.SUM 求和运行结果:

fcfd3c95fa0afe8ca19833110a5b82c4 - elasticsearch通用工具类

转载请注明:xuhss » elasticsearch通用工具类

喜欢 (0)

您必须 登录 才能发表评论!