Python微信订餐小程序课程视频
https://edu.csdn.net/course/detail/36074
Python实战量化交易理财系统
https://edu.csdn.net/course/detail/35475
这几天写了一个关于es的工具类,主要封装了业务中常用es的常用方法。
本文中使用到的elasticsearch版本6.7,但实际上也支持es7.x以上版本,因为主要是对springboot提供的:ElasticsearchRestTemplate 提供的API做的二次封装。目的是:让不懂es的开发人员新手也能轻松上手。
一、概述
整个工程分为es-api与es-server。
es-api为对外公共jar,包含了es映射实体;
es-server包含了具体的es工具类与Repository接口(下文会提到)。并通过necos配置中心统一管理es配置参数。
外部业务模块可引入es-api jar maven依赖,由Jar提供的入口,通过httpClient或feign调用(springcloud分布式项目)到es-server服务上的es工具类,得到需要的数据。
二、使用
这里仅以springcloud分布式项目简单为例
业务方用户服务user 引入es-api maven
/**
* @author: shf
* description: es-server feign接口
*/
public interface EsServerClient {
@PostMapping(value = "/queryList", produces = {"application/json"})
public List queryList(@RequestBody T t);
}
在user服务中创建feignClient继承自es-api中的EsServerClient
@FeignClient(contextId = "esFeignClient", name = "es-server")
public interface EsFeignClient extends EsServerClient {
}
在user服务的代码中即可调用
@AutoWired
public EsFeignClient esFeignClient;
public void test() {
//.......如业务方Dto与es映射实体转换 等省略
//....
EmployeeEs employee = new EmployeeEs();
List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation("李四", EntityEs.SHOULD, 20F)).collect(Collectors.toList());
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList).put(EmployeeEs::getUserAge, employee.new RangeRelation(20, EntityEs.GTE, null, null, EntityEs.MUST)));
//排序查询
employee.setOrderMap(new EsMapUtil().put(EmployeeEs::getUserId, SortOrder.DESC));
List employeeEs = esFeignClient.queryList(employee);
//.....employeeEs与业务方Dto转换
}
三、具体实现
es-api 引入es依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>transportartifactId>
exclusion>
<exclusion>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>transportartifactId>
<version>6.7.0version>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
<version>6.7.0version>
dependency>
排除后重新引入对应的Es版本6.7,避免因版本不一致导致的一些坑。
es-server 服务 application.yml配置es
spring:
elasticsearch:
rest:
#ES的连接地址,多个地址用逗号分隔
uris: localhost:9200
username: kibana
password: pass
#连接超时时间
connection-timeout: 1000
#读取超时时间
read-timeout: 1000
一、映射实体
1、与ES mapping结构对应的映射实体:EmployeeEs
说明:
①设置的字段与该es对应的该索引完全对应,不存在多余字段。
②项目中引入了spring-boot-starter-data-elasticsearch,所以可直接使用注解形式设置索引信息与mapping结构信息,详见示例
③@JsonIgnoreProperties({"orderMap","pageNumber","pageSize","highlightFields","preTags","postTags","fieldQueryMap","scrollId","aggregationMap","multiLayerQueryList"})
作用:在保存文档到es时忽略父类EntityEs中的功能性字段,下文会提到
④@EsRepository(EmployeeEsRepository.class)
作用:通过注解过去该映射对应的Repository接口
/**
* 员工对象
*
* 注解:@Document用来声明Java对象与ElasticSearch索引的关系 indexName 索引名称 type 索引类型 shards 主分区数量,默认5
* replicas 副本分区数量,默认1 createIndex 索引不存在时,是否自动创建索引,默认true
*/
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EsRepository(EmployeeEsRepository.class)
@JsonIgnoreProperties({"orderMap","pageNumber","pageSize","highlightFields","preTags","postTags","fieldQueryMap","scrollId","aggregationMap","multiLayerQueryList"})
@Document(indexName = "employee\_index", type = "employee\_type", shards = 1, replicas = 0, createIndex = true)
public class EmployeeEs extends EntityEs {
@Id
@Field(type = FieldType.Keyword)
private Long userId;
//@Field(type = FieldType.Text, analyzer = "ik\_max\_word")
@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik\_max\_word"), otherFields = @InnerField(suffix = "trueName", type = FieldType.Keyword))
private String userName;
@Field(type = FieldType.Keyword)
private String userCode;
@Field(type = FieldType.Integer)
private Integer userAge;
@Field(type = FieldType.Keyword)
private String userMobile;
@Field(type = FieldType.Date)
private Date birthDay;
@Field(type = FieldType.Keyword)
private String userSex;
@Field(type = FieldType.Text, analyzer = "ik\_max\_word")
private String remarks;
}
View Code
2、Repository接口:EmployeeEsRepository
/**
* @author: shf
* description: 可根据映射实体设置自动生成mapping结构;支持bean的增删改查操作
* date: 2022/2/23 10:47
*/
@Component
public interface EmployeeEsRepository extends CrudRepository {
}
二、功能性实体类:EntityEs
说明:
①所有字段非es索引中的mapping属性字段,均为功能性字段,如排序、高亮、分页设置和一些常量设置等,详见贴码
②所有es映射实体类均需继承该实体
/**
* @author: shf description: 功能性字段(非mapping结构字段)
* date: 2022/3/1 15:07
*/
@Data
public class EntityEs {
/**
* 组合多查询常量
*/
/**
* 文档 必须 匹配这些条件才能被查询到。相当于sql中的and
*/
public static String MUST = "must";
/**
* 文档 必须不 匹配这些条件才能被查询到。相当于sql中的 not
*/
public static String MUST\_NOT = "must\_not";
/**
* 如果满足这些语句中的任意语句,将增加 \_score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。相当于sql中的or
*/
public static String SHOULD = "should";
/**
* 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档
*/
public static String FILTER = "filter";
/**
* 至少匹配一项should子句
*/
public static String MINIMUM\_SHOULD\_MATCH = "minimum\_should\_match";
/**
* 多字段排序查询
*/
public EsMapUtil orderMap;
/**
* 分页查询
*/
public Integer pageNumber;
public Integer pageSize;
/**
* 游标分页ID
*/
public String scrollId;
/**
* 游标分页ID有效期 单位:毫秒
*/
public static Long scrollIdExpireTime = 1000 * 60 * 2L;
/**
* 游标分页ID最小有效期 单位:毫秒
*/
public static Long scrollIdMinExpireTime = 1000L;
/**
* 高亮查询
*/
public List highlightFields;
public String preTags;
public String postTags;
/**
* 字段查询
*/
public EsMapUtil fieldQueryMap;
/**
* 聚合查询,当前只支持单个字段分组聚合count与sum,只针对keyword类型字段有效
*/
public EsMapUtil aggregationMap;
public static String COUNT = "count";
public static String SUM = "sum";
/**
* 多层(bool)查询
*/
public List multiLayerQueryList;
/**
* 范围查询常量
*/
public static String GT = "gt";
public static String GTE = "gte";
public static String LT = "lt";
public static String LTE = "lte";
@Data
public class RangeRelation {
//String fieldKey;
T fieldMinValue;
String fieldMinMode;
T fieldMaxValue;
String fieldMaxMode;
String queryMode;
public RangeRelation(T fieldMinValue, String fieldMinMode, T fieldMaxValue, String fieldMaxMode, String queryMode) {
this.fieldMinValue = fieldMinValue;
this.fieldMinMode = fieldMinMode;
this.fieldMaxValue = fieldMaxValue;
this.fieldMaxMode = fieldMaxMode;
this.queryMode = queryMode;
}
}
@Data
public class QueryRelation {
T fieldValue;
String queryMode;
Float boostValue;
public QueryRelation(T fieldValue, String queryMode) {
this.fieldValue = fieldValue;
this.queryMode = queryMode;
}
public QueryRelation(T fieldValue, String queryMode, Float boostValue) {
this.fieldValue = fieldValue;
this.queryMode = queryMode;
this.boostValue = boostValue;
}
}
@Data
public class MultiLayerRelation {
String queryMode;
EsMapUtil map;
List multiLayerList;
public MultiLayerRelation(String queryMode, EsMapUtil map) {
this.queryMode = queryMode;
this.map = map;
}
public MultiLayerRelation(String queryMode, EsMapUtil map, List multiLayerList) {
this.queryMode = queryMode;
this.map = map;
this.multiLayerList = multiLayerList;
}
}
}
View Code
三、小工具:EsMapUtil
说明:封装了一个map工具,编码简洁链式调用,应用了方法引用特性避免了字符串硬编码造成单词拼错的情况。
/**
* @author: shf description: 函数式接口 便于方法引用获取实体字段名称
* date: 2022/3/4 13:41
*/
@FunctionalInterface
public interface IGetterFunction extends Serializable{
Object get(T source);
}
/**
* @author: shf
* description
* date: 2019/11/13 18:30
*/
public class EsMapUtil extends LinkedHashMap {
public EsMapUtil put(IGetterFunction fn, Object value) {
String key = getFieldName(fn);
super.put(key, value);
return this;
}
public EsMapUtil putStr(String key, Object value) {
super.put(key, value);
return this;
}
private static Map CLASS\_LAMDBA\_CACHE = new ConcurrentHashMap<>();
/***
* 转换方法引用为属性名
* @param fn
* @return
*/
public String getFieldName(IGetterFunction fn) {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
String prefix = null;
if (methodName.startsWith("get")) {
prefix = "get";
}
// 截取get之后的字符串并转换首字母为小写
return toLowerCaseFirstOne(methodName.replace(prefix, ""));
}
/**
* 首字母转小写
*
* @param s
*/
public String toLowerCaseFirstOne(String s) {
if (Character.isLowerCase(s.charAt(0))) {
return s;
} else {
return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
}
}
public static SerializedLambda getSerializedLambda(Serializable fn) {
SerializedLambda lambda = CLASS\_LAMDBA\_CACHE.get(fn.getClass());
if (lambda == null) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
lambda = (SerializedLambda) method.invoke(fn);
CLASS\_LAMDBA\_CACHE.put(fn.getClass(), lambda);
} catch (Exception e) {
e.printStackTrace();
}
}
return lambda;
}
}
View Code
四、Es通用工具类EsService
/**
* @author: shf description: es工具类,支持:分页(支持游标分页)、高亮(支持自定义标签)、范围查找、bool组合查询、多层bool套bool、多字段排序、加权重、聚合、二级字段查询
* date: 2022/2/23 10:54
*/
@Component
@Slf4j
public class EsService {
@Autowired
private ElasticsearchRestTemplate restTemplate;
@Autowired
private ApplicationContext context;
/**
* 判断索引是否存在
*
* @return boolean
*/
public boolean indexExists(Class clazz) {
return restTemplate.indexExists(clazz);
}
/**
* 判断索引是否存在
*
* @param indexName 索引名称
* @return boolean
*/
public boolean indexExists(String indexName) {
return restTemplate.indexExists(indexName);
}
/**
* 创建索引(推荐使用:因为Java对象已经通过注解描述了Setting和Mapping)
*
* @return boolean
*/
public boolean indexCreate(Class clazz) {
boolean createFlag = restTemplate.createIndex(clazz);
boolean mappingFlag = restTemplate.putMapping(clazz);
return createFlag && mappingFlag;
}
/**
* 索引删除
*
* @param indexName 索引名称
* @return boolean
*/
public boolean indexDelete(String indexName) {
return restTemplate.deleteIndex(indexName);
}
/**
* 新增数据
*
* @param bean 数据对象
*/
public void saveBean(T bean) {
EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
crudRepository.save(bean);
}
/**
* 批量新增数据
*
* @param list 数据集合
*/
public void saveList(List list) {
if (CollectionUtils.isEmpty(list)) {
return;
}
EsRepository esRepositoryAnno = list.get(0).getClass().getAnnotation(EsRepository.class);
CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
crudRepository.saveAll(list);
}
/**
* 根据对象删除数据,主键ID不能为空
*
* @param bean 对象
*/
public void deleteByBean(T bean) {
EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
crudRepository.delete(bean);
}
/**
* 根据对象集合,批量删除
*
* @param beanList 对象集合
*/
public void deleteAllByBeanList(List beanList) {
if (CollectionUtils.isEmpty(beanList)) {
return;
}
EsRepository esRepositoryAnno = beanList.get(0).getClass().getAnnotation(EsRepository.class);
CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
crudRepository.deleteAll(beanList);
}
/**
* 删除所有
*/
public void deleteAll(T bean) {
EsRepository esRepositoryAnno = bean.getClass().getAnnotation(EsRepository.class);
CrudRepository crudRepository = (CrudRepository) context.getBean(esRepositoryAnno.value());
crudRepository.deleteAll();
}
/**
* 修改数据
*
* @param t 修改数据对象,ID不能为空
*/
public boolean updateByBean(T t) throws IllegalAccessException {
Class clazz = t.getClass();
Field[] Fields = clazz.getDeclaredFields();
String beanId = null;
String beanIdName = null;
for (Field f : Fields) {
f.setAccessible(true);
if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
beanId = String.valueOf(f.get(t));
beanIdName = f.getName();
}
}
if (StringUtils.isBlank(beanId)) {
log.warn("id不能为空");
return false;
}
if (Objects.isNull(restTemplate.queryForObject(GetQuery.getById(beanId), clazz))) {
log.warn("该文档不存在");
return false;
}
Document annotation = (Document) clazz.getAnnotation(Document.class);
UpdateRequest updateRequest = new UpdateRequest();
//冲突重试
updateRequest.retryOnConflict(1);
updateRequest.doc(JSON.toJSONString(t), XContentType.JSON);
//默认是\_id来路由的,用来路由到不同的shard,会对这个值做hash,然后映射到shard。所以分片
updateRequest.routing(beanId);
UpdateQuery query = new UpdateQueryBuilder().withIndexName(annotation.indexName()).withType(annotation.type()).withId(beanId)
.withDoUpsert(false)//不加默认false。true表示更新时不存在就插入
.withClass(clazz).withUpdateRequest(updateRequest).build();
UpdateResponse updateResponse = restTemplate.update(query);
if (!Objects.equals(updateResponse.getShardInfo().getSuccessful(), 1)) {
return false;
}
return true;
}
/**
* 根据bean ID 查询
*
* @param beanId
* @param clazz
* @param
*/
public T queryBeanById(String beanId, Class clazz) {
return restTemplate.queryForObject(GetQuery.getById(beanId), clazz);
}
/**
* 数据查询,返回List
*
* @return List
*/
public List queryList(T t) throws IllegalAccessException, NoSuchFieldException {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Class clazz = (Class) t.getClass();
Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
List highlightFields = (List) clazz.getField("highlightFields").get(t);
String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);
String beanIdName = null;
Field[] Fields = clazz.getDeclaredFields();
for (Field f : Fields) {
f.setAccessible(true);
if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
beanIdName = f.getName();
break;
}
}
//构建组合查询(支持权重)
getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
//处理多层bool查询
getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
log.info("打印语句:{}", boolQueryBuilder.toString());
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
//支持多字段排序查询
getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
//支持多字段高亮查询并可自定义高亮标签规则
getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);
if (CollectionUtils.isEmpty(highlightFields)) {
return restTemplate.queryForList(nativeSearchQueryBuilder.build(), clazz);
} else {
nativeSearchQueryBuilder.withPageable(PageRequest.of(0, 10000));
ScrolledPage page = restTemplate.startScroll(EntityEs.scrollIdMinExpireTime, nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
List chunk = new ArrayList<>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
try {
T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
for (String fieldName : highlightFields) {
Field f = clazz.getDeclaredField(fieldName);
HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
if (highlightField != null) {
f.setAccessible(true);
f.set(t, highlightField.fragments()[0].toString());
}
}
chunk.add(t);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if (chunk.size() > 0) {
return new AggregatedPageImpl<>((List) chunk);
}
return null;
}
@Override
public T mapSearchHit(SearchHit searchHit, Class type) {
return null;
}
});
return page.toList();
}
}
/**
* 分页查询
*
* @param t
* @param
*/
public List queryPage(T t) throws IllegalAccessException, NoSuchFieldException {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Class clazz = (Class) t.getClass();
Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
List highlightFields = (List) clazz.getField("highlightFields").get(t);
String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
Integer pageNumber = !Objects.isNull((Integer) clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
Integer pageSize = !Objects.isNull((Integer) clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 10;
List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);
String beanIdName = null;
Field[] Fields = clazz.getDeclaredFields();
for (Field f : Fields) {
f.setAccessible(true);
if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
beanIdName = f.getName();
break;
}
}
//构建组合查询(支持权重)
getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
//处理多层bool查询
getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
//支持多字段排序查询
getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
//支持多字段高亮查询并可自定义高亮标签规则
getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);
//分页查询
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));
AggregatedPage page = null;
if (CollectionUtils.isEmpty(highlightFields)) {
page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz);
} else {
page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
List chunk = new ArrayList<>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
try {
T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
for (String fieldName : highlightFields) {
Field f = clazz.getDeclaredField(fieldName);
HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
if (highlightField != null) {
f.setAccessible(true);
f.set(t, highlightField.fragments()[0].toString());
}
}
chunk.add(t);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if (chunk.size() > 0) {
return new AggregatedPageImpl<>((List) chunk);
}
return null;
}
@Override
public T mapSearchHit(SearchHit searchHit, Class type) {
return null;
}
});
}
// 总记录数
long totalElements = page.getTotalElements();
// 总页数
int totalPages = page.getTotalPages();
// 当前页号
//int currentPage = page.getPageable().getPageNumber();
// 当前页数据集
List beanList = page.toList();
List content = page.getContent();
System.out.println(beanList);
//TODO 根据项目中的分页封装类将以上数据设置后返回即可
return Lists.newArrayList();
}
/**
* 游标分页
*
* @param t
* @param
*/
public List queryScrollPage(T t) throws IllegalAccessException, NoSuchFieldException {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Class clazz = (Class) t.getClass();
String scrollId = (String) clazz.getField("scrollId").get(t);
if (StringUtils.isNotBlank(scrollId)) {
ScrolledPage page = restTemplate.continueScroll(scrollId, EntityEs.scrollIdExpireTime, clazz);
// 总记录数
long totalElements = page.getTotalElements();
// 总页数
//int totalPages = page.getTotalPages();
// 当前页号
//int currentPage = page.getPageable().getPageNumber();
// 当前页数据集
List beanSet = page.toList();
List content = page.getContent();
System.out.println("page.getScrollId:" + page.getScrollId());
System.out.println(beanSet);
//TODO 根据项目中的分页封装类将以上数据设置后返回即可
return Lists.newArrayList();
}
Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
Map orderMap = (LinkedHashMap) clazz.getField("orderMap").get(t);
List highlightFields = (List) clazz.getField("highlightFields").get(t);
String preTags = StringUtils.isNotBlank((String) clazz.getField("preTags").get(t)) ? (String) clazz.getField("preTags").get(t) : "*";
String postTags = StringUtils.isNotBlank((String) clazz.getField("postTags").get(t)) ? (String) clazz.getField("postTags").get(t) : "*";
Integer pageNumber = !Objects.isNull((Integer) clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
Integer pageSize = !Objects.isNull((Integer) clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 10;
List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);
String beanIdName = null;
Field[] Fields = clazz.getDeclaredFields();
for (Field f : Fields) {
f.setAccessible(true);
if (f.isAnnotationPresent(org.springframework.data.annotation.Id.class)) {
beanIdName = f.getName();
break;
}
}
//构建组合查询(支持权重)
getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
//处理多层bool查询
getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
//支持多字段排序查询
getOrderBuilder(beanIdName, orderMap, nativeSearchQueryBuilder);
//支持多字段高亮查询并可自定义高亮标签规则
getHighLightBuilder(highlightFields, preTags, postTags, nativeSearchQueryBuilder);
//分页查询
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));
ScrolledPage page = restTemplate.startScroll(EntityEs.scrollIdExpireTime, nativeSearchQueryBuilder.build(), clazz, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
List chunk = new ArrayList<>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
try {
T t = (T) JSON.parseObject(searchHit.getSourceAsString(), clazz);
for (String fieldName : highlightFields) {
Field f = clazz.getDeclaredField(fieldName);
HighlightField highlightField = searchHit.getHighlightFields().get(fieldName);
if (highlightField != null) {
f.setAccessible(true);
f.set(t, highlightField.fragments()[0].toString());
}
}
chunk.add(t);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if (chunk.size() > 0) {
return new AggregatedPageImpl<>((List) chunk);
}
return null;
}
@Override
public T mapSearchHit(SearchHit searchHit, Class type) {
return null;
}
});
// 总记录数
long totalElements = page.getTotalElements();
// 总页数
//int totalPages = page.getTotalPages();
// 当前页号
//int currentPage = page.getPageable().getPageNumber();
// 当前页数据集
List beanSet = page.toList();
List content = page.getContent();
System.out.println("page.getScrollId:" + page.getScrollId());
System.out.println(beanSet);
//TODO 根据项目中的分页封装类将以上数据设置后返回即可
return Lists.newArrayList();
}
/**
* 聚合查询
*
* @param t
* @param
*/
public Map queryForAggregation(T t) throws IllegalAccessException, NoSuchFieldException {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Class clazz = (Class) t.getClass();
Map queryMap = (LinkedHashMap) clazz.getField("fieldQueryMap").get(t);
Integer pageNumber = !Objects.isNull(clazz.getField("pageNumber").get(t)) ? (Integer) clazz.getField("pageNumber").get(t) : 0;
Integer pageSize = !Objects.isNull(clazz.getField("pageSize").get(t)) ? (Integer) clazz.getField("pageSize").get(t) : 1;
Map aggregationMap = (LinkedHashMap) clazz.getField("aggregationMap").get(t);
List multiLayerQueryList = (List) clazz.getField("multiLayerQueryList").get(t);
//构建组合查询(支持权重)
getFieldQueryBuilder(boolQueryBuilder, clazz, queryMap);
//处理多层bool查询
getNestQueryBuilder(boolQueryBuilder, clazz, multiLayerQueryList);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
//分页查询
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));
// 创建聚合查询条件
String aggKey = null;
String aggValue = null;
for (Map.Entry entry : aggregationMap.entrySet()) {
aggKey = entry.getKey();
aggValue = entry.getValue();
if (Objects.equals(aggValue, EntityEs.COUNT)) {
TermsAggregationBuilder agg = AggregationBuilders.terms(aggKey).field(aggKey);
nativeSearchQueryBuilder.addAggregation(agg);
break;
} else if (Objects.equals(aggValue, EntityEs.SUM)) {
SumAggregationBuilder agg = AggregationBuilders.sum(aggKey).field(aggKey);
nativeSearchQueryBuilder.addAggregation(agg);
break;
}
}
AggregatedPage page = restTemplate.queryForPage(nativeSearchQueryBuilder.build(), clazz);
// 取出聚合结果
Aggregations entitiesAggregations = page.getAggregations();
Map retMap = new HashMap<>();
if (Objects.equals(aggValue, EntityEs.COUNT)) {
Terms terms = (Terms) entitiesAggregations.asMap().get(aggKey);
// 遍历取出聚合字段列的值,与对应的数量
for (Terms.Bucket bucket : terms.getBuckets()) {
// 聚合字段列的值
String keyAsString = bucket.getKeyAsString();
// 聚合字段对应的数量
long docCount = bucket.getDocCount();
log.info("keyAsString={},value={}", keyAsString, docCount);
retMap.put(keyAsString, docCount);
}
} else if (Objects.equals(aggValue, EntityEs.SUM)) {
Aggregation aggregation = entitiesAggregations.get(aggKey);
retMap.put(aggregation.getName(), ((ParsedSum) aggregation).getValue());
}
// 当前页数据集
List beanList = page.toList();
System.out.println("当前页数据集:" + beanList);
return retMap;
}
/**
* 根据自定义查询条件批量查询
*
* @param searchQuery
* @param clazz
* @param
*/
public List queryListBySearchQuery(SearchQuery searchQuery, Class clazz) {
return restTemplate.queryForList(searchQuery, clazz);
}
/*------------------------------------------- private 私有方法 ----------------------------------------------*/
private void getNestQueryBuilder(BoolQueryBuilder boolQueryBuilder, Class clazz, List multiLayerQueryList) throws NoSuchFieldException {
if (!CollectionUtils.isEmpty(multiLayerQueryList)) {
for (EntityEs.MultiLayerRelation r : multiLayerQueryList) {
BoolQueryBuilder nestBoolQuery = QueryBuilders.boolQuery();
EsMapUtil nestMap = r.getMap();
getFieldQueryBuilder(nestBoolQuery, clazz, nestMap);
if (Objects.equals(r.getQueryMode(), EntityEs.MUST)) {
boolQueryBuilder.must(nestBoolQuery);
} else if (Objects.equals(r.getQueryMode(), EntityEs.SHOULD)) {
boolQueryBuilder.should(nestBoolQuery);
} else if (Objects.equals(r.getQueryMode(), EntityEs.FILTER)) {
boolQueryBuilder.filter(nestBoolQuery);
} else if (Objects.equals(r.getQueryMode(), EntityEs.MUST\_NOT)) {
boolQueryBuilder.mustNot(nestBoolQuery);
}
//递归嵌套
if (!CollectionUtils.isEmpty(r.getMultiLayerList())) {
//处理多层bool查询
getNestQueryBuilder(nestBoolQuery, clazz, r.getMultiLayerList());
}
}
}
}
/**
* 构建组合查询(支持权重)
*
* @param boolQueryBuilder
* @param clazz
* @param queryMap
*/
private void getFieldQueryBuilder(BoolQueryBuilder boolQueryBuilder, Class clazz, Map queryMap) throws NoSuchFieldException {
if (queryMap != null && queryMap.size() > 0) {
for (Map.Entry entry : queryMap.entrySet()) {
String k = entry.getKey();
List vList = new ArrayList();
if (entry.getValue() instanceof List) {
vList = (ArrayList) entry.getValue();
} else {
vList.add(entry.getValue());
}
FieldType type = null;
if (k.indexOf(".") == -1) {
Field f = clazz.getDeclaredField(k);
if (f.isAnnotationPresent(org.springframework.data.elasticsearch.annotations.Field.class)) {
type = f.getAnnotation(org.springframework.data.elasticsearch.annotations.Field.class).type();
} else if (f.isAnnotationPresent(org.springframework.data.elasticsearch.annotations.MultiField.class)) {
type = f.getAnnotation(org.springframework.data.elasticsearch.annotations.MultiField.class).mainField().type();
}
} else {
//如果字段Field type定义的是Keyword,走matchQuery效果也是term精确查询
type = FieldType.Text;
}
if (Objects.equals(type, FieldType.Text)) {
for (Object o : vList) {
if (o instanceof EntityEs.RangeRelation) {
EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
//范围查询
getRangeBuilder(boolQueryBuilder, k, v);
} else if (o instanceof EntityEs.QueryRelation) {
EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.must(QueryBuilders.matchQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.must(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.mustNot(QueryBuilders.matchQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.mustNot(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.should(QueryBuilders.matchQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.should(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.filter(QueryBuilders.matchQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.filter(QueryBuilders.matchQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
}
}
}
} else if (Objects.equals(type, FieldType.Keyword)) {
for (Object o : vList) {
if (o instanceof EntityEs.RangeRelation) {
EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
//范围查询
getRangeBuilder(boolQueryBuilder, k, v);
} else if (o instanceof EntityEs.QueryRelation) {
EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
}
}
}
} else {
for (Object o : vList) {
if (o instanceof EntityEs.RangeRelation) {
EntityEs.RangeRelation v = (EntityEs.RangeRelation) o;
//范围查询
getRangeBuilder(boolQueryBuilder, k, v);
} else if (o instanceof EntityEs.QueryRelation) {
EntityEs.QueryRelation v = (EntityEs.QueryRelation) o;
if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.must(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.mustNot(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.should(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
if (Objects.isNull(v.getBoostValue())) {
boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()));
} else {
boolQueryBuilder.filter(QueryBuilders.termQuery(k, v.getFieldValue()).boost(v.getBoostValue()));
}
}
}
}
}
}
}
}
/**
* 构建范围查询
*
* @param boolQueryBuilder
* @param k
* @param v
*/
private void getRangeBuilder(BoolQueryBuilder boolQueryBuilder, String k, EntityEs.RangeRelation v) {
if (Objects.equals(v.getQueryMode(), EntityEs.MUST)) {
if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
}
if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
boolQueryBuilder.must(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.MUST\_NOT)) {
if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
}
if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
boolQueryBuilder.mustNot(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.SHOULD)) {
if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
}
if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
boolQueryBuilder.should(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
}
} else if (Objects.equals(v.getQueryMode(), EntityEs.FILTER)) {
if (Objects.equals(v.getFieldMinMode(), EntityEs.GT)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.GTE)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gte(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LT)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lt(v.getFieldMinValue()));
} else if (Objects.equals(v.getFieldMinMode(), EntityEs.LTE)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lte(v.getFieldMinValue()));
}
if (Objects.equals(v.getFieldMaxMode(), EntityEs.GT)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.GTE)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).gte(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LT)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lt(v.getFieldMaxValue()));
} else if (Objects.equals(v.getFieldMaxMode(), EntityEs.LTE)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery(k).lte(v.getFieldMaxValue()));
}
}
}
/**
* 构建排序查询
*
* @param beanIdName
* @param orderMap
* @param nativeSearchQueryBuilder
*/
private void getOrderBuilder(String beanIdName, Map orderMap, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
if (orderMap != null && orderMap.size() > 0) {
orderMap.forEach((k, v) -> {
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((String) k).order((SortOrder) v));
});
} else {
//无指定排序字段默认按ID倒序
//nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(beanIdName).order(SortOrder.DESC));
}
}
/**
* 构建高亮查询
*
* @param highlightFields
* @param preTags
* @param postTags
* @param nativeSearchQueryBuilder
*/
private void getHighLightBuilder(List highlightFields, String preTags, String postTags, NativeSearchQueryBuilder nativeSearchQueryBuilder) {
if (highlightFields != null && highlightFields.size() > 0) {
List highlightTitles = new ArrayList<>();
for (String title : highlightFields) {
highlightTitles.add(new HighlightBuilder.Field(title).preTags(preTags).postTags(postTags));
}
nativeSearchQueryBuilder.withHighlightFields(highlightTitles.stream().toArray(HighlightBuilder.Field[]::new));
}
}
}
View Code
五、单元测试
1、根据映射实体设置生成索引与mapping
说明:启动项目会自动加载自动创建,如需要手动创建可调用方法
@Test
public void indexCreateTest() {
System.out.println(esService.indexCreate(EmployeeEs.class));
}
2、删除指定索引
@Test
public void indexDelete() {
System.out.println(esService.indexDelete("employee\_index"));
}
3、判断指定索引是否存在
@Test
public void indexExists() {
System.out.println(esService.indexExists(EmployeeEs.class));
}
4、保存单个bean
@Autowired
private EsService esService;
@Test
public void saveBean() {
System.out.println("-----es测试start...");
EmployeeEs employee = EmployeeEs.builder().userId(9L).userName("张三1").userCode("abc").userAge(22).userMobile("12345678987")
.remarks("今天天气好晴朗~").birthDay(new Date()).build();
esService.saveBean(employee);
System.out.println("-----es测试end...");
}
5、批量保存
@Test
public void saveList() throws ParseException {
System.out.println("-----es测试start...");
EmployeeEs employee = EmployeeEs.builder().userId(1L).userName("张三").userCode("abc").userAge(18).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-9-20")).build();
EmployeeEs employee1 = EmployeeEs.builder().userId(2L).userName("李四").userCode("abc").userAge(10).userSex("女").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-6-20")).build();
EmployeeEs employee2 = EmployeeEs.builder().userId(3L).userName("王五").userCode("abc").userAge(10).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-5-20")).build();
EmployeeEs employee3 = EmployeeEs.builder().userId(4L).userName("赵六").userCode("abc").userAge(20).userSex("男").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-8-20")).build();
EmployeeEs employee4 = EmployeeEs.builder().userId(5L).userName("董七").userCode("abc").userAge(20).userSex("女").userMobile("12345678987").birthDay(new SimpleDateFormat("yyyy-MM-dd").parse("1995-8-20")).build();
esService.saveList(Lists.newArrayList(employee,employee1,employee2,employee3,employee4));
System.out.println("-----es测试end...");
}
6、根据ID删除指定Bean
@Test
public void deleteByBean() {
EmployeeEs employee = EmployeeEs.builder().userId(1L).build();
esService.deleteByBean(employee);
}
7、批量删除
@Test
public void deleteList() {
EmployeeEs employee = EmployeeEs.builder().userId(1L).build();
EmployeeEs employee1 = EmployeeEs.builder().userId(2L).build();
esService.deleteAllByBeanList(Lists.newArrayList(employee,employee1));
}
8、删除该索引下所有数据
@Test
public void deleteAll() {
esService.deleteAll(EmployeeEs.class);
}
9、修改数据(ID不能为空)
@Test
public void updateTest() throws IllegalAccessException {
System.out.println("-----es测试start...");
EmployeeEs employee = EmployeeEs.builder().userId(5L).userName("张一").userCode("abcD").userAge(19).build();
esService.updateByBean(employee);
System.out.println("-----es测试end...");
}
10、根据ID查询指定Bean
@Test
public void queryById() {
EmployeeEs employeeEs = esService.queryBeanById("2", EmployeeEs.class);
System.out.println(employeeEs);
}
11、批量查询
/**
* 涉及到了组合查询bool、权重、范围查找、排序
*/
@Test
public void queryList() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 5F), employee.new QueryRelation("李四", EntityEs.SHOULD, 20F)).collect(Collectors.toList());
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList).put(EmployeeEs::getUserAge, employee.new RangeRelation(20, EntityEs.GTE, null, null, EntityEs.MUST)));
//排序查询
employee.setOrderMap(new EsMapUtil().put(EmployeeEs::getUserId, SortOrder.DESC));
List employeeEs = esService.queryList(employee);
System.out.println(employeeEs);
System.out.println("-----es测试end...");
}
打印出来的语句:
查询结果:
12、二级属性查询
@Test
public void querySecondList() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
employee.setFieldQueryMap(new EsMapUtil().putStr("userName.trueName", employee.new QueryRelation("张三", EntityEs.MUST)));
List employeeEsList = esService.queryList(employee);
System.out.println(employeeEsList);
System.out.println("-----es测试end...");
}
先准备一条测试数据插入
看下上面查询语句的结果:
由于userName的二级属性trueName的类型是keyword,所以是term精确查找
对比:
@Test
public void querySecondList() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, employee.new QueryRelation("张三", EntityEs.MUST)));
//employee.setFieldQueryMap(new EsMapUtil().putStr("userName.trueName", employee.new QueryRelation("张三", EntityEs.MUST)));
List employeeEsList = esService.queryList(employee);
System.out.println(employeeEsList);
System.out.println("-----es测试end...");
}
13、分页查询
@Test
public void queryPage() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD), employee.new QueryRelation("李四", EntityEs.SHOULD)).collect(Collectors.toList());
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
//分页
employee.setPageNumber(0);
employee.setPageSize(2);
List employeeEs = esService.queryPage(employee);
System.out.println(employeeEs);
System.out.println("-----es测试end...");
}
14、游标分页查询
@Test
public void queryScrollPage() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
String scrollId = "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAADJEWMVFWMVBnb1ZSZDZsV1k2Y2JjLVlldw==";
EmployeeEs employee = new EmployeeEs();
if (StringUtils.isNotBlank(scrollId)) {
//如果前端有传scrollId
employee.setScrollId(scrollId);
List employeeEs = esService.queryScrollPage(employee);
System.out.println(employeeEs);
} else {
List queryList = Stream.of(employee.new QueryRelation("张三", EntityEs.SHOULD, 20F), employee.new QueryRelation("李四", EntityEs.SHOULD)).collect(Collectors.toList());
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, queryList));
//每页页数
employee.setPageSize(4);
List employeeEs = esService.queryScrollPage(employee);
System.out.println(employeeEs);
}
System.out.println("-----es测试end...");
}
15、多层bool套bool查询
@Test
public void queryMuiltiLayer() throws IllegalAccessException, NoSuchFieldException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
//多层bool查询
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST)));
List multiLayerUserAgeList = Stream.of(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD)).collect(Collectors.toList());
EntityEs.MultiLayerRelation multiLayerRelation = employee.new MultiLayerRelation(EntityEs.MUST, new EsMapUtil().put(EmployeeEs::getUserAge, multiLayerUserAgeList));
employee.setMultiLayerQueryList(Lists.newArrayList(multiLayerRelation));
List userEs = esService.queryList(employee);
System.out.println(userEs);
System.out.println("-----es测试end...");
}
示例:查找年龄为10或者18岁的男性员工
//错误案例
EmployeeEs employee = new EmployeeEs();
List ageList = Lists.newArrayList(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD));
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST))
.put(EmployeeEs::getUserAge,ageList)
);
List userEs = esService.queryList(employee);
System.out.println(userEs);
结果年龄为20的赵六也被查询了出来。原因是:当should遇到must和filter时就不是或者了,而是应该的意思。可通过must嵌套一层解决。
修改为多层bool查询
EmployeeEs employee = new EmployeeEs();
//修改为多层bool查询
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserSex, employee.new QueryRelation("男", EntityEs.MUST)));
List multiLayerUserAgeList = Stream.of(employee.new QueryRelation(10, EntityEs.SHOULD), employee.new QueryRelation(18, EntityEs.SHOULD)).collect(Collectors.toList());
EntityEs.MultiLayerRelation multiLayerRelation = employee.new MultiLayerRelation(EntityEs.MUST, new EsMapUtil().put(EmployeeEs::getUserAge, multiLayerUserAgeList));
employee.setMultiLayerQueryList(Lists.newArrayList(multiLayerRelation));
List userEs = esService.queryList(employee);
16、高亮查询
@Test
public void highlightTest() throws NoSuchFieldException, IllegalAccessException {
System.out.println("-----es测试start...");
EmployeeEs employee = new EmployeeEs();
employee.setFieldQueryMap(new EsMapUtil().put(EmployeeEs::getUserName, employee.new QueryRelation("张三", EntityEs.MUST))
.put(EmployeeEs::getRemarks, employee.new QueryRelation("天气", EntityEs.MUST)));
employee.setHighlightFields(Lists.newArrayList("remarks"));
//默认,可自定义高亮标签
employee.setPreTags("# ");
employee.setPostTags("
");
List employeeEs = esService.queryList(employee);
System.out.println(employeeEs);
System.out.println("-----es测试end...");
}
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 求和运行结果:
转载请注明:xuhss » elasticsearch通用工具类