这几天写了一个关于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:9200username: kibanapassword: 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;
}

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";@Datapublic 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;}}@Datapublic 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;}}@Datapublic 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;}}
}

三、小工具: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;}
}

四、Es通用工具类EsService

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

五、单元测试

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)) {//如果前端有传scrollIdemployee.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 求和运行结果:

elasticsearch通用工具类相关推荐

  1. java通用解析excel_java读取简单excel通用工具类

    本文实例为大家分享了java读取简单excel通用工具类的具体代码,供大家参考,具体内容如下 读取excel通用工具类 import java.io.File; import java.io.File ...

  2. Unity3d通用工具类之定时触发器

    时隔多日,好不容易挤出点时间来写写博文.不容易,请送我几朵红花,点个赞也行. 今天呢,我们主要来扩展下通用工具类==>定时触发器. 顾名思义,所谓的定时触发器,就是告诉程序在过多长时间后,我要执 ...

  3. c mysql 工具类_Jave工具——servlet+jsp编程中mysql数据库连接及操作通用工具类

    该工具类是在JavaWeb中连接mysql所用到的通用工具类 该类用于Java+Servlet的编程中,方便数据库的操作,连接,获取其列表值.下面是这个数据库操作类的通用方法,基本上能够用于类里面只含 ...

  4. Java通用工具类之按对象属性排序工具类

    本工具类为按对象属性排序工具类,实现的功能: 1.按对象的一个属性和多个属性进行排序. 2.按对象属性正序和倒序排列. 3.完美支持int等基础类和Integer等包装类. 4.完美支持属性为实现了C ...

  5. 【干货分享】通用工具类

    项目实战中不论是业务编码还是通用编码,总会归纳出一些通用的工具类. 放入项目中一劳永逸,让兄弟姐妹们避免编写重复代码. 公司研发团队经过几个项目的洗礼,沉淀和积累了许多通用工具类. 自己抽空将这些散落 ...

  6. 利用poi 读取excel通用工具类

    poi excel导出通用工具 | 这一行是废话 根据上一篇利用poi 导出excel通用工具类去年写的一个工具类,同样根据业务需求重新封装了一个读excel 工具类,感觉还算通用,分享到博客,欢迎各 ...

  7. Excel导出+解析通用工具类

    参照原文:http://blog.csdn.net/houxuehan/article/details/50960259 maven配置: <dependencies> <depen ...

  8. JAVA导出Excel通用工具类——第一篇:详细介绍POI 导出excel的多种复杂情况,包括动态设置筛选、动态合并横向(纵向)单元格等多种复杂情况——保姆级别,真的不能再详细了,代码拿来即用)

    JAVA导出Excel通用工具--第一篇:详细介绍POI 导出excel的多种复杂情况,包括动态设置筛选.动态合并横向(纵向)单元格等多种复杂情况--保姆级别,真的不能再详细了,封装通用工具类,代码拿 ...

  9. ElasticSearch工具类封装

    最近在项目中有看到一种比较实用的ElasticSearch工具类封装方式,特此记录便于日后查阅.         1.controller层 @RequestMapping(value = " ...

最新文章

  1. 【组队学习】【32期】推荐系统-新闻推荐系统实践
  2. 气死我的存储过程和用户定义函数
  3. 不容易系列之(4)——考新郎
  4. 虚拟化概念和KVM简述
  5. mysql 预留一个自定义字段_mysql-预留字段
  6. 爬虫批量下载全站小说并自动保存
  7. 367. 有效的完全平方数
  8. 7-4 最短工期 (25 分)
  9. 基于jmx监控kafka_0542-6.1.0-非安全环境下Kafka管理工具Kafka Eagle安装使用
  10. TinaFace:人脸检测新纪录!
  11. yii2解决资源插件路径不对应问题
  12. MS CRM 4中,添加营销列表成员查找列
  13. 程序性能之显示大表格
  14. CCNA3.0中文版教材
  15. PDF文件编辑并去除水印
  16. 笔记| 计算机数据表示实验(HUST)| 汉字机内码获取实验
  17. 判断字符串是否为空方法
  18. FPGA初学者__个人学习笔记(二)_ generate 用法
  19. Ctrl+Shift+End
  20. python基础程序_Python基础初识

热门文章

  1. Java常见面试50题(java jsp)
  2. java中flush()的作用的是什么?与close有什么联系
  3. 将默认的maven仓库改为阿里的maven仓库
  4. 自动部署项目,全靠它了!
  5. linux 文件添加标签,SELinux——有趣的标签
  6. JPS网页中文乱码解决方案
  7. 网络技术基础(六)网络互连技术
  8. html p标签行间距怎么调,css怎么设置行距?
  9. PIVOT和UNPIVOT使用详解
  10. canvas签名插件 jSignature 移动,PC都适用