• elasticsearch通用工具类


      这几天写了一个关于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 <T> List<T> 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<String>("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation<String>("李四", 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> employeeEs = esFeignClient.queryList(employee);
      //.....employeeEs与业务方Dto转换
    }
    复制代码

    三、具体实现

    es-api 引入es依赖

    复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>transport</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-high-level-client</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>6.7.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>6.7.0</version>
    </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接口

    /**
     * 员工对象
     * <p>
     * 注解:@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<EmployeeEs,Long> {
    }
    复制代码

    二、功能性实体类:EntityEs

    说明:

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

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

    /**
     * @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<String> 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<T> {
    
            //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> {
    
            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<EntityEs.MultiLayerRelation> multiLayerList;
    
            public MultiLayerRelation(String queryMode, EsMapUtil map) {
                this.queryMode = queryMode;
                this.map = map;
            }
    
            public MultiLayerRelation(String queryMode, EsMapUtil map, List<MultiLayerRelation> 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<T> extends Serializable{
        Object get(T source);
    }
    复制代码
    /**
     * @author: shf
     * description
     * date: 2019/11/13 18:30
     */
    public class EsMapUtil extends LinkedHashMap<String, Object> {
    
        public <T> EsMapUtil put(IGetterFunction<T> fn, Object value) {
            String key = getFieldName(fn);
            super.put(key, value);
            return this;
        }
    
        public <T> EsMapUtil putStr(String key, Object value) {
            super.put(key, value);
            return this;
        }
    
        private static Map<Class, SerializedLambda> CLASS_LAMDBA_CACHE = new ConcurrentHashMap<>();
    
        /***
         * 转换方法引用为属性名
         * @param fn
         * @return
         */
        public <T> String getFieldName(IGetterFunction<T> 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

    /**
     * @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 <T> boolean indexExists(Class<T> clazz) {
            return restTemplate.indexExists(clazz);
        }
     
        /**
         * 判断索引是否存在
         *
         * @param indexName 索引名称
         * @return boolean
         */
        public boolean indexExists(String indexName) {
            return restTemplate.indexExists(indexName);
        }
     
        /**
         * 创建索引(推荐使用:因为Java对象已经通过注解描述了Setting和Mapping)
         *
         * @return boolean
         */
        public <T> boolean indexCreate(Class<T> 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 <T> void saveBean(T bean) {
            EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
            CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
            crudRepository.save(bean);
        }
     
        /**
         * 批量新增数据
         *
         * @param list 数据集合
         */
        public <T> void saveList(List<T> 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 <T> void deleteByBean(T bean) {
            EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
            CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
            crudRepository.delete(bean);
        }
     
        /**
         * 根据对象集合,批量删除
         *
         * @param beanList 对象集合
         */
        public <T> void deleteAllByBeanList(List<T> 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 <T> void deleteAll(T bean) {
            EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
            CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
            crudRepository.deleteAll();
        }
     
        /**
         * 修改数据
         *
         * @param t 修改数据对象,ID不能为空
         */
        public <T> 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 <T>
         */
        public <T> T queryBeanById(String beanId, Class<T> clazz) {
            return restTemplate.queryForObject(GetQuery.getById(beanId), clazz);
        }
     
        /**
         * 数据查询,返回List
         *
         * @return List<T>
         */
        public <T> List<T> queryList(T t) throws IllegalAccessException, NoSuchFieldException {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            Class clazz = (Class) t.getClass();
            Map<String, Object> queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
            Map<String, String> orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
            List<String> highlightFields = (List<String>) clazz.getField("highlightFields").get(t);
            String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "<em>";
            String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "</em>";
            List<EntityEs.MultiLayerRelation> multiLayerQueryList = (List<EntityEs.MultiLayerRelation>) 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 <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                        List<T> 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<T>) chunk);
                        }
                        return null;
                    }
     
                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                        return null;
                    }
                });
                return page.toList();
            }
        }
     
     
        /**
         * 分页查询
         *
         * @param t
         * @param <T>
         */
        public <T> List<T> queryPage(T t) throws IllegalAccessException, NoSuchFieldException {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            Class clazz = (Class) t.getClass();
     
            Map<String, Object> queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
            Map<String, String> orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
            List<String> highlightFields = (List<String>) clazz.getField("highlightFields").get(t);
            String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "<em>";
            String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "</em>";
            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<EntityEs.MultiLayerRelation> multiLayerQueryList = (List<EntityEs.MultiLayerRelation>) 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 <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                        List<T> 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<T>) chunk);
                        }
     
     
                        return null;
                    }
     
                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                        return null;
                    }
                });
            }
            // 总记录数
            long totalElements = page.getTotalElements();
            // 总页数
            int totalPages = page.getTotalPages();
            // 当前页号
            //int currentPage = page.getPageable().getPageNumber();
            // 当前页数据集
            List<T> beanList = page.toList();
            List<T> content = page.getContent();
            System.out.println(beanList);
            //TODO 根据项目中的分页封装类将以上数据设置后返回即可
            return Lists.newArrayList();
        }
     
     
        /**
         * 游标分页
         *
         * @param t
         * @param <T>
         */
        public <T> List<T> 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<T> beanSet = page.toList();
                List<T> content = page.getContent();
                System.out.println("page.getScrollId:" + page.getScrollId());
                System.out.println(beanSet);
                //TODO 根据项目中的分页封装类将以上数据设置后返回即可
                return Lists.newArrayList();
            }
            Map<String, Object> queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
            Map<String, String> orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
            List<String> highlightFields = (List<String>) clazz.getField("highlightFields").get(t);
            String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "<em>";
            String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "</em>";
            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<EntityEs.MultiLayerRelation> multiLayerQueryList = (List<EntityEs.MultiLayerRelation>) 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 <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                    List<T> 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<T>) chunk);
                    }
                    return null;
                }
     
                @Override
                public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                    return null;
                }
            });
     
            // 总记录数
            long totalElements = page.getTotalElements();
            // 总页数
            //int totalPages = page.getTotalPages();
            // 当前页号
            //int currentPage = page.getPageable().getPageNumber();
            // 当前页数据集
            List<T> beanSet = page.toList();
            List<T> content = page.getContent();
            System.out.println("page.getScrollId:" + page.getScrollId());
            System.out.println(beanSet);
            //TODO 根据项目中的分页封装类将以上数据设置后返回即可
            return Lists.newArrayList();
        }
     
     
        /**
         * 聚合查询
         *
         * @param t
         * @param <T>
         */
        public <T> Map queryForAggregation(T t) throws IllegalAccessException, NoSuchFieldException {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            Class clazz = (Class) t.getClass();
     
            Map<String, Object> 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<String, String> aggregationMap = (LinkedHashMap) clazz.getField("aggregationMap").get(t);
            List<EntityEs.MultiLayerRelation> multiLayerQueryList = (List<EntityEs.MultiLayerRelation>) 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<String, String> 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<String, Object> 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<T> beanList = page.toList();
            System.out.println("当前页数据集:" + beanList);
            return retMap;
        }
     
     
        /**
         * 根据自定义查询条件批量查询
         *
         * @param searchQuery
         * @param clazz
         * @param <T>
         */
        public <T> List<T> queryListBySearchQuery(SearchQuery searchQuery, Class<T> clazz) {
            return restTemplate.queryForList(searchQuery, clazz);
        }
     
     
        /*------------------------------------------- private 私有方法 ----------------------------------------------*/
     
        private void getNestQueryBuilder(BoolQueryBuilder boolQueryBuilder, Class clazz, List<EntityEs.MultiLayerRelation> 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<String, Object> queryMap) throws NoSuchFieldException {
            if (queryMap != null && queryMap.size() > 0) {
                for (Map.Entry<String, Object> 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<String> highlightFields, String preTags, String postTags, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
            if (highlightFields != null && highlightFields.size() > 0) {
                List<HighlightBuilder.Field> 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...");
    }
    复制代码

     

     

    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<String>("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation<String>("李四", 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> employeeEs = esService.queryList(employee);
     System.out.println(employeeEs);
     System.out.println("-----es测试end...");
    }
    复制代码

    打印出来的语句:

    查询结果:

    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<String>("张三", EntityEs.MUST)));
     List<EmployeeEs> employeeEsList = esService.queryList(employee);
     System.out.println(employeeEsList);
     System.out.println("-----es测试end...");
    }
    复制代码

    先准备一条测试数据插入

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

    由于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<String>("张三", EntityEs.MUST)));
     //employee.setFieldQueryMap(new EsMapUtil().putStr("userName.trueName", employee.new QueryRelation<String>("张三", EntityEs.MUST)));
     List<EmployeeEs> employeeEsList = esService.queryList(employee);
     System.out.println(employeeEsList);
     System.out.println("-----es测试end...");
    }
    复制代码

    13、分页查询

    复制代码
    @Test
    public void queryPage() throws IllegalAccessException, NoSuchFieldException {
        System.out.println("-----es测试start...");
        EmployeeEs employee = new EmployeeEs();
        List<EntityEs.QueryRelation> queryList = Stream.of(employee.new QueryRelation<String>("张三", EntityEs.SHOULD), employee.new QueryRelation<String>("李四", EntityEs.SHOULD)).collect(Collectors.toList());
        employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
        //分页
        employee.setPageNumber(0);
        employee.setPageSize(2);
        List<EmployeeEs> 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> employeeEs = esService.queryScrollPage(employee);
            System.out.println(employeeEs);
        } else {
            List<EntityEs.QueryRelation> queryList = Stream.of(employee.new QueryRelation<String>("张三", EntityEs.SHOULD, 20F), employee.new QueryRelation<String>("李四", EntityEs.SHOULD)).collect(Collectors.toList());
            employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
            //每页页数
            employee.setPageSize(4);
            List<EmployeeEs> 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<EntityEs.QueryRelation> 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<EmployeeEs> userEs = esService.queryList(employee);
        System.out.println(userEs);
        System.out.println("-----es测试end...");
    }
    复制代码

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

    复制代码
    //错误案例
    EmployeeEs employee = new EmployeeEs();
    List<EntityEs.QueryRelation> 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<EmployeeEs> userEs = esService.queryList(employee);
    System.out.println(userEs);
    复制代码

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

    修改为多层bool查询

    复制代码
    EmployeeEs employee = new EmployeeEs();
    //修改为多层bool查询
    employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST)));
    List<EntityEs.QueryRelation> 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<EmployeeEs> userEs = esService.queryList(employee);
    复制代码

     

     

    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<String>("张三", EntityEs.MUST))
            .put(EmployeeEs::getRemarks, employee.new QueryRelation<String>("天气", EntityEs.MUST)));
        employee.setHighlightFields(Lists.newArrayList("remarks"));
        //默认<em></em>,可自定义高亮标签
        employee.setPreTags("<h1>");
        employee.setPostTags("</h1>");
        List<EmployeeEs> employeeEs = esService.queryList(employee);
        System.out.println(employeeEs);
        System.out.println("-----es测试end...");
    }
    复制代码

    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...");
    }
    复制代码

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

     

  • 相关阅读:
    数据可视化PCA与t-SNE
    【Qt】三种方式实现抽奖小游戏
    Python读取Excel工作表数据写入CSV、XML、文本
    安卓全机型 玩机 搞机 ADB FAST 各种指令解析说明与操作
    FCIS 2023网络安全创新大会:洞察前沿技术,探索安全新境界(附大会核心PPT下载)
    最长上升子序列
    Idea远程debug
    毫米波雷达点云 DBSCAN聚类算法
    透视虎牙斗鱼三季报:游戏直播在各自“求变”中见分晓
    【Spring Cloud】Spring Cloud Oauth2 + Gateway 微服务权限管理方案
  • 原文地址:https://www.cnblogs.com/better-farther-world2099/p/15992842.html