mirror of
https://gitee.com/dromara/easy-es.git
synced 2025-12-06 17:18:57 +08:00
v2.0-beta1
调整重建索引超时时间默认值为72小时,避免小白踩坑超时,并且可配置. 彻底搞定5种嵌套及多层级嵌套
This commit is contained in:
parent
572591aa31
commit
848ba0c7b5
@ -74,4 +74,11 @@ public @interface IndexName {
|
||||
* @return 默认子类
|
||||
*/
|
||||
Class<?> childClass() default DefaultChildClass.class;
|
||||
|
||||
/**
|
||||
* 路由
|
||||
*
|
||||
* @return CRUD作用的路由
|
||||
*/
|
||||
String routing() default "";
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package cn.easyes.annotation.rely;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Es支持的数据类型枚举
|
||||
* <p>
|
||||
@ -67,4 +69,17 @@ public enum FieldType {
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型字符串获取对应枚举
|
||||
*
|
||||
* @param type 类型字符串
|
||||
* @return 对应枚举
|
||||
*/
|
||||
public static FieldType getByType(String type) {
|
||||
return Arrays.stream(FieldType.values())
|
||||
.filter(v -> v.getType().equals(type))
|
||||
.findFirst()
|
||||
.orElse(FieldType.KEYWORD_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,10 +55,6 @@ public interface BaseEsConstants {
|
||||
* 冒号
|
||||
*/
|
||||
String COLON = ":";
|
||||
/**
|
||||
* 逗号分隔符
|
||||
*/
|
||||
String COMMA_SEPARATOR = ",";
|
||||
/**
|
||||
* ee内置es分布式锁索引名称
|
||||
*/
|
||||
@ -135,10 +131,6 @@ public interface BaseEsConstants {
|
||||
* 默认返回数
|
||||
*/
|
||||
Integer DEFAULT_SIZE = 10000;
|
||||
/**
|
||||
* es默认得分字段
|
||||
*/
|
||||
String SCORE_FIELD = "_score";
|
||||
/**
|
||||
* DSL语句前缀
|
||||
*/
|
||||
@ -200,10 +192,6 @@ public interface BaseEsConstants {
|
||||
* 默认最小匹配百分比
|
||||
*/
|
||||
int DEFAULT_MIN_SHOULD_MATCH = 60;
|
||||
/**
|
||||
* 百分比符号
|
||||
*/
|
||||
String PERCENT = "%";
|
||||
/**
|
||||
* 嵌套类型 path和field连接符
|
||||
*/
|
||||
|
||||
@ -36,6 +36,10 @@ public class EntityInfo {
|
||||
* 索引名称(原索引名)
|
||||
*/
|
||||
private String indexName;
|
||||
/**
|
||||
* 配置的路由
|
||||
*/
|
||||
private String routing;
|
||||
/**
|
||||
* 新索引名(由EE在更新索引时自动创建)
|
||||
*/
|
||||
@ -132,6 +136,10 @@ public class EntityInfo {
|
||||
* 实体字段->高亮返回结果 键值对
|
||||
*/
|
||||
private final Map<String, String> highlightFieldMap = new HashMap<>();
|
||||
/**
|
||||
* 实体字段名->es字段类型
|
||||
*/
|
||||
private final Map<String, String> fieldTypeMap = new HashMap<>();
|
||||
/**
|
||||
* 实体字段->es实际字段映射
|
||||
*/
|
||||
@ -152,6 +160,10 @@ public class EntityInfo {
|
||||
* 嵌套类型 path和class对应关系
|
||||
*/
|
||||
private final Map<String, Class<?>> pathClassMap = new HashMap<>();
|
||||
/**
|
||||
* 嵌套类型 实体字段名->字段类型
|
||||
*/
|
||||
private final Map<Class<?>, Map<String, String>> nestedClassFieldTypeMap = new HashMap<>();
|
||||
/**
|
||||
* 嵌套类型 实体字段->es实际字段映射
|
||||
*/
|
||||
|
||||
@ -65,7 +65,7 @@ public interface Nested<Param, Children> extends Serializable {
|
||||
Children should(boolean condition, Consumer<Param> consumer);
|
||||
|
||||
default Children filter(Consumer<Param> consumer) {
|
||||
return should(true, consumer);
|
||||
return filter(true, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +78,7 @@ public interface Nested<Param, Children> extends Serializable {
|
||||
Children filter(boolean condition, Consumer<Param> consumer);
|
||||
|
||||
default Children mustNot(Consumer<Param> consumer) {
|
||||
return should(true, consumer);
|
||||
return mustNot(true, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -25,6 +25,10 @@ public class GlobalConfig {
|
||||
* process index mode Smoothly by default 索引处理模式 默认开启平滑模式
|
||||
*/
|
||||
private ProcessIndexStrategyEnum processIndexMode = ProcessIndexStrategyEnum.SMOOTHLY;
|
||||
/**
|
||||
* Rebuild index timeout unit: hour, default: 72 重建索引超时时间 单位小时,默认72
|
||||
*/
|
||||
private int reindexTimeOutHours = 72;
|
||||
/**
|
||||
* process index blocking main thread true by default 异步处理索引是否阻塞主线程 默认阻塞
|
||||
*/
|
||||
@ -43,7 +47,6 @@ public class GlobalConfig {
|
||||
* 分布式环境下,平滑模式,当前客户端激活最新索引最大重试次数 若数据量过大,重建索引数据迁移时间超过60*(180/60)=180分钟时,可调大此参数值 此参数值决定多久重试一次 单位:秒
|
||||
*/
|
||||
private int activeReleaseIndexFixedDelay = 180;
|
||||
|
||||
/**
|
||||
* es db config 数据库配置
|
||||
*/
|
||||
|
||||
@ -135,10 +135,12 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
|
||||
|
||||
@Override
|
||||
public Children or(boolean condition) {
|
||||
if (!paramQueue.isEmpty()) {
|
||||
Param param = paramQueue.peekLast();
|
||||
// 需要将其前一同level节点prevQueryType修改为or_should
|
||||
for (int i = paramQueue.size() - 1; i >= 0; i--) {
|
||||
Param param = paramQueue.get(i);
|
||||
if (Objects.equals(level, param.getLevel())) {
|
||||
param.setPrevQueryType(OR_SHOULD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addParam(condition, OR, null, null, null);
|
||||
@ -655,6 +657,7 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
|
||||
* @param boost 权重
|
||||
*/
|
||||
private void addBaseParam(Param param, EsQueryTypeEnum queryTypeEnum, String column, Object val, Float boost) {
|
||||
// 基本值设置
|
||||
param.setId(UUID.randomUUID().toString());
|
||||
Optional.ofNullable(parentId).ifPresent(param::setParentId);
|
||||
param.setPrevQueryType(prevQueryType);
|
||||
@ -662,18 +665,62 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
|
||||
param.setVal(val);
|
||||
param.setColumn(column);
|
||||
param.setBoost(boost);
|
||||
param.setLevel(level);
|
||||
|
||||
// 入队之前需要先对MP中的拼接or()特殊处理之所以在此处处理,是因为可以少遍历一遍树 节省OLog(N) 时间复杂度
|
||||
if (!paramQueue.isEmpty()) {
|
||||
Param prev = paramQueue.peekLast();
|
||||
if (OR.equals(prev.getQueryTypeEnum())) {
|
||||
// 上一节点是拼接or() 则修改当前节点的prevQueryType为OR_SHOULD 让其走should查询
|
||||
param.setPrevQueryType(OR_SHOULD);
|
||||
}
|
||||
}
|
||||
// 入队之前需要先对MP中的拼接or()特殊处理
|
||||
processOr(param);
|
||||
paramQueue.add(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加基础嵌套
|
||||
*
|
||||
* @param param 参数
|
||||
* @param queryTypeEnum 查询类型
|
||||
* @param consumer 消费者
|
||||
*/
|
||||
private void addBaseNested(Param param, EsQueryTypeEnum queryTypeEnum, Consumer<Children> consumer) {
|
||||
// 基本值设置
|
||||
param.setId(UUID.randomUUID().toString());
|
||||
Optional.ofNullable(parentId).ifPresent(param::setParentId);
|
||||
param.setQueryTypeEnum(queryTypeEnum);
|
||||
param.setLevel(level);
|
||||
param.setPrevQueryType(queryTypeEnum);
|
||||
|
||||
// 入队之前需要先对MP中的拼接or()特殊处理
|
||||
processOr(param);
|
||||
|
||||
paramQueue.add(param);
|
||||
this.parentId = param.getId();
|
||||
parentIdQueue.push(parentId);
|
||||
level++;
|
||||
consumer.accept(instance());
|
||||
// 深度优先在consumer条件消费完后会来执行这里 此时parentId需要重置 至于为什么,比较烧脑 可断点打在consumer前后观察一波
|
||||
level--;
|
||||
if (!parentIdQueue.isEmpty()) {
|
||||
this.parentId = parentIdQueue.pollLast();
|
||||
}
|
||||
if (level == 0) {
|
||||
// 仙人板板 根节点
|
||||
this.parentId = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 特殊处理拼接or
|
||||
*
|
||||
* @param param 参数
|
||||
*/
|
||||
private void processOr(Param param) {
|
||||
if (!paramQueue.isEmpty()) {
|
||||
Param prev = paramQueue.peekLast();
|
||||
if (OR.equals(prev.getQueryTypeEnum())) {
|
||||
// 上一节点是拼接or() 需要重置其prevQueryType类型,让其走should查询
|
||||
param.setPrevQueryType(OR_SHOULD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加查询参数
|
||||
@ -763,39 +810,6 @@ public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 追加基础嵌套
|
||||
*
|
||||
* @param param 参数
|
||||
* @param queryTypeEnum 查询类型
|
||||
* @param consumer 消费者
|
||||
*/
|
||||
private void addBaseNested(Param param, EsQueryTypeEnum queryTypeEnum, Consumer<Children> consumer) {
|
||||
param.setId(UUID.randomUUID().toString());
|
||||
Optional.ofNullable(parentId).ifPresent(param::setParentId);
|
||||
param.setQueryTypeEnum(queryTypeEnum);
|
||||
level++;
|
||||
param.setLevel(level);
|
||||
paramQueue.add(param);
|
||||
this.parentId = param.getId();
|
||||
parentIdQueue.push(parentId);
|
||||
prevQueryTypeQueue.push(queryTypeEnum);
|
||||
consumer.accept(instance());
|
||||
// 深度优先在consumer条件消费完后会来执行这里 此时parentId需要重置 至于为什么 可断点打在consumer前后观察一波 整个框架最难的地方就在此
|
||||
level--;
|
||||
if (!parentIdQueue.isEmpty()) {
|
||||
this.parentId = parentIdQueue.pollLast();
|
||||
}
|
||||
if (!prevQueryTypeQueue.isEmpty()) {
|
||||
this.prevQueryType = prevQueryTypeQueue.pollLast();
|
||||
}
|
||||
if (level == 0) {
|
||||
// 仙人板板 根节点
|
||||
this.parentId = null;
|
||||
this.prevQueryType = AND_MUST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载,追加嵌套条件
|
||||
*
|
||||
|
||||
@ -213,6 +213,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
public String getSource(Wrapper<T> wrapper) {
|
||||
// 获取由本框架生成的es查询参数 用于验证生成语法的正确性
|
||||
SearchRequest searchRequest = new SearchRequest(getIndexNames(wrapper.indexNames));
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
SearchSourceBuilder searchSourceBuilder = WrapperProcessor.buildSearchSourceBuilder(wrapper, entityClass);
|
||||
searchRequest.source(searchSourceBuilder);
|
||||
return Optional.ofNullable(searchRequest.source())
|
||||
@ -292,6 +293,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
} else {
|
||||
// 不去重,直接count获取,效率更高
|
||||
CountRequest countRequest = new CountRequest(getIndexNames(wrapper.indexNames));
|
||||
Optional.ofNullable(getRouting()).ifPresent(countRequest::routing);
|
||||
QueryBuilder queryBuilder = Optional.ofNullable(wrapper.searchSourceBuilder)
|
||||
.map(SearchSourceBuilder::query)
|
||||
.orElseGet(() -> WrapperProcessor.initBoolQueryBuilder(wrapper.paramQueue, entityClass));
|
||||
@ -369,6 +371,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
@Override
|
||||
public Integer delete(Wrapper<T> wrapper) {
|
||||
DeleteByQueryRequest request = new DeleteByQueryRequest(getIndexNames(wrapper.indexNames));
|
||||
Optional.ofNullable(getRouting()).ifPresent(request::setRouting);
|
||||
BoolQueryBuilder boolQueryBuilder = WrapperProcessor.initBoolQueryBuilder(wrapper.paramQueue, entityClass);
|
||||
request.setQuery(boolQueryBuilder);
|
||||
BulkByScrollResponse bulkResponse;
|
||||
@ -467,6 +470,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
// 构造查询参数
|
||||
List<String> stringIdList = idList.stream().map(Object::toString).collect(Collectors.toList());
|
||||
SearchRequest searchRequest = new SearchRequest(getIndexNames(indexName));
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
|
||||
sourceBuilder.query(QueryBuilders.termsQuery(DEFAULT_ES_ID_NAME, stringIdList));
|
||||
sourceBuilder.size(idList.size());
|
||||
@ -574,6 +578,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
|
||||
// 更新mapping
|
||||
PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
|
||||
|
||||
if (Objects.isNull(wrapper.mapping)) {
|
||||
Assert.notEmpty(wrapper.esIndexParamList, String.format("update index: %s failed, because of empty update args", indexName));
|
||||
Map<String, Object> mapping = IndexUtils.initMapping(EntityInfoHelper.getEntityInfo(entityClass), wrapper.esIndexParamList);
|
||||
@ -601,6 +606,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private Integer doInsert(T entity, String indexName) {
|
||||
// 构建请求入参
|
||||
IndexRequest indexRequest = buildIndexRequest(entity, indexName);
|
||||
Optional.ofNullable(getRouting()).ifPresent(indexRequest::routing);
|
||||
indexRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
|
||||
try {
|
||||
@ -629,6 +635,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private Integer doInsertBatch(Collection<T> entityList, String indexName) {
|
||||
// 构建批量请求参数
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
Optional.ofNullable(getRouting()).ifPresent(bulkRequest::routing);
|
||||
bulkRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
entityList.forEach(entity -> {
|
||||
IndexRequest indexRequest = buildIndexRequest(entity, indexName);
|
||||
@ -649,6 +656,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
*/
|
||||
private Integer doDeleteById(Serializable id, String indexName) {
|
||||
DeleteRequest deleteRequest = generateDelRequest(id, indexName);
|
||||
Optional.ofNullable(getRouting()).ifPresent(deleteRequest::routing);
|
||||
deleteRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
try {
|
||||
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
|
||||
@ -671,6 +679,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
*/
|
||||
private Integer doDeleteBatchIds(Collection<? extends Serializable> idList, String indexName) {
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
Optional.ofNullable(getRouting()).ifPresent(bulkRequest::routing);
|
||||
bulkRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
idList.forEach(id -> {
|
||||
DeleteRequest deleteRequest = generateDelRequest(id, indexName);
|
||||
@ -690,6 +699,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private Integer doUpdateById(T entity, String idValue, String indexName) {
|
||||
// 构建更新请求参数
|
||||
UpdateRequest updateRequest = buildUpdateRequest(entity, idValue, indexName);
|
||||
Optional.ofNullable(getRouting()).ifPresent(updateRequest::routing);
|
||||
updateRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
|
||||
// 执行更新
|
||||
@ -715,6 +725,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private Integer doUpdateBatchByIds(Collection<T> entityList, String indexName) {
|
||||
// 封装批量请求参数
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
Optional.ofNullable(getRouting()).ifPresent(bulkRequest::routing);
|
||||
bulkRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
entityList.forEach(entity -> {
|
||||
String idValue = getIdValue(entity);
|
||||
@ -748,6 +759,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
|
||||
// 批量更新
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
Optional.ofNullable(getRouting()).ifPresent(bulkRequest::routing);
|
||||
bulkRequest.setRefreshPolicy(getRefreshPolicy());
|
||||
Method getId = BaseCache.getterMethod(entityClass, getRealIdFieldName());
|
||||
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
|
||||
@ -782,6 +794,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private T doSelectById(Serializable id, String indexName) {
|
||||
// 构造查询参数
|
||||
SearchRequest searchRequest = new SearchRequest(indexName);
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||
searchSourceBuilder.query(QueryBuilders.termQuery(DEFAULT_ES_ID_NAME, id));
|
||||
searchRequest.source(searchSourceBuilder);
|
||||
@ -807,6 +820,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private SearchResponse getSearchResponse(Wrapper<T> wrapper, Object[] searchAfter) {
|
||||
// 构建es restHighLevelClient 查询参数
|
||||
SearchRequest searchRequest = new SearchRequest(getIndexNames(wrapper.indexNames));
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
|
||||
// 用户在wrapper中指定的混合查询条件优先级最高
|
||||
SearchSourceBuilder searchSourceBuilder = Optional.ofNullable(wrapper.searchSourceBuilder)
|
||||
@ -859,6 +873,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
private List<T> selectListByUpdateWrapper(Wrapper<T> wrapper, String indexName) {
|
||||
// 构建查询条件
|
||||
SearchRequest searchRequest = new SearchRequest(indexName);
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
SearchSourceBuilder searchSourceBuilder;
|
||||
if (Objects.isNull(wrapper.searchSourceBuilder)) {
|
||||
searchSourceBuilder = new SearchSourceBuilder();
|
||||
@ -881,7 +896,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
searchRequest.source(searchSourceBuilder);
|
||||
printDSL(searchRequest);
|
||||
try {
|
||||
// 查询数据明细
|
||||
// 查询数据明细
|
||||
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
|
||||
printResponseErrors(response);
|
||||
SearchHit[] searchHits = parseSearchHitArray(response);
|
||||
@ -1126,6 +1141,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
*/
|
||||
private SearchHit[] getSearchHitArray(Wrapper<T> wrapper) {
|
||||
SearchRequest searchRequest = new SearchRequest(getIndexNames(wrapper.indexNames));
|
||||
Optional.ofNullable(getRouting()).ifPresent(searchRequest::routing);
|
||||
|
||||
// 用户在wrapper中指定的混合查询条件优先级最高
|
||||
SearchSourceBuilder searchSourceBuilder = Objects.isNull(wrapper.searchSourceBuilder) ?
|
||||
@ -1209,7 +1225,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
updateParamList.forEach(esUpdateParam -> {
|
||||
String realField = FieldUtils.getRealFieldNotConvertId(esUpdateParam.getField(),
|
||||
EntityInfoHelper.getEntityInfo(entityClass).getMappingColumnMap(),
|
||||
GlobalConfigCache.getGlobalConfig().getDbConfig());
|
||||
GlobalConfigCache.getGlobalConfig().getDbConfig().isMapUnderscoreToCamelCase());
|
||||
jsonObject.put(realField, esUpdateParam.getValue());
|
||||
});
|
||||
return JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue);
|
||||
@ -1445,11 +1461,20 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 父子
|
||||
* 获取路由
|
||||
*
|
||||
* @return 路由
|
||||
*/
|
||||
private String getRouting() {
|
||||
return EntityInfoHelper.getEntityInfo(entityClass).getRouting();
|
||||
}
|
||||
|
||||
/**
|
||||
* 父子文档获取路由
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @param joinFieldClass join字段类
|
||||
* @return
|
||||
* @return 路由
|
||||
*/
|
||||
private String getRouting(T entity, Class<?> joinFieldClass) {
|
||||
// 父子类型-子文档,设置路由
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
package cn.easyes.core.core;
|
||||
|
||||
import cn.easyes.annotation.rely.FieldType;
|
||||
import cn.easyes.common.enums.AggregationTypeEnum;
|
||||
import cn.easyes.common.enums.EsQueryTypeEnum;
|
||||
import cn.easyes.common.utils.*;
|
||||
import cn.easyes.core.biz.*;
|
||||
import cn.easyes.core.cache.GlobalConfigCache;
|
||||
import cn.easyes.core.config.GlobalConfig;
|
||||
import cn.easyes.core.toolkit.EntityInfoHelper;
|
||||
import cn.easyes.core.toolkit.FieldUtils;
|
||||
import cn.easyes.core.toolkit.TreeBuilder;
|
||||
@ -38,6 +36,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static cn.easyes.common.constants.BaseEsConstants.*;
|
||||
import static cn.easyes.common.enums.EsQueryTypeEnum.*;
|
||||
import static cn.easyes.core.toolkit.FieldUtils.*;
|
||||
|
||||
/**
|
||||
* 核心 wrapper处理类
|
||||
@ -74,60 +73,14 @@ public class WrapperProcessor {
|
||||
* @param entityClass 实体类
|
||||
*/
|
||||
public static BoolQueryBuilder initBoolQueryBuilder(List<Param> paramList, Class<?> entityClass) {
|
||||
// 数据预处理
|
||||
List<Param> rootList = new ArrayList<>();
|
||||
preProcessData(paramList, rootList, entityClass);
|
||||
|
||||
// 建立参数森林(无根树)
|
||||
List<Param> rootList = paramList.stream().filter(i -> Objects.isNull(i.getParentId())).collect(Collectors.toList());
|
||||
TreeBuilder treeBuilder = new TreeBuilder(rootList, paramList);
|
||||
List<Param> tree = (List<Param>) treeBuilder.build();
|
||||
BoolQueryBuilder rootBool = QueryBuilders.boolQuery();
|
||||
|
||||
// 对森林的每个根节点递归封装 这里看似简单实则很绕很烧脑 整个框架的核心 主要依托树的递归 深度优先遍历 森林
|
||||
return getBool(tree, rootBool);
|
||||
}
|
||||
|
||||
/***
|
||||
* 数据预处理 原始数据转换为目标数据
|
||||
* @param paramList 参数列表
|
||||
* @param rootList 子树根
|
||||
* @param entityClass 实体类
|
||||
*/
|
||||
private static void preProcessData(List<Param> paramList, List<Param> rootList, Class<?> entityClass) {
|
||||
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
Map<String, String> fieldTypeMap = entityInfo.getFieldList().stream()
|
||||
.collect(Collectors.toMap(EntityFieldInfo::getColumn, item -> Optional.ofNullable(item.getFieldType())
|
||||
.map(FieldType::getType).orElse(FieldType.KEYWORD_TEXT.getType())));
|
||||
// TODO 嵌套类型中的字段名称及自动智能拼接.keyword后缀待近期补充 以及嵌套类型自定义字段处理
|
||||
Map<Class<?>, List<EntityFieldInfo>> nestedFieldListMap = entityInfo.getNestedFieldListMap();
|
||||
|
||||
paramList.forEach(param -> {
|
||||
// 驼峰及自定义字段转换
|
||||
String realField = FieldUtils.getRealField(param.getColumn(), entityInfo.getMappingColumnMap(), dbConfig);
|
||||
param.setColumn(realField);
|
||||
if (ArrayUtils.isNotEmpty(param.getColumns())) {
|
||||
String[] columns = FieldUtils.getRealFields(param.getColumns(), entityInfo.getMappingColumnMap(), dbConfig);
|
||||
param.setColumns(columns);
|
||||
}
|
||||
if (HAS_CHILD.equals(param.getQueryTypeEnum()) || HAS_PARENT.equals(param.getQueryTypeEnum())) {
|
||||
String realPath = FieldUtils.getRealField(param.getExt1().toString(), entityInfo.getMappingColumnMap(), dbConfig);
|
||||
param.setExt1(realPath);
|
||||
}
|
||||
|
||||
// 是否需要智能拼接.keyword后缀
|
||||
Optional.ofNullable(fieldTypeMap.get(realField))
|
||||
.ifPresent(fieldType -> {
|
||||
if (FieldType.KEYWORD_TEXT.getType().equals(fieldType)) {
|
||||
param.setNeedAddKeywordSuffix(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (param.getParentId() == null) {
|
||||
// 仙人板板
|
||||
rootList.add(param);
|
||||
}
|
||||
});
|
||||
// 对森林的每个根节点递归封装 这里看似简单实则很绕很烧脑 整个框架的核心 主要依托树的递归 深度优先遍历 森林 还原lambda条件构造语句
|
||||
return getBool(tree, rootBool, EntityInfoHelper.getEntityInfo(entityClass), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,34 +90,39 @@ public class WrapperProcessor {
|
||||
* @param param 查询参数
|
||||
*/
|
||||
@SneakyThrows
|
||||
private static void initBool(BoolQueryBuilder bool, Param param) {
|
||||
private static void initBool(BoolQueryBuilder bool, Param param, EntityInfo entityInfo,
|
||||
Map<String, String> mappingColumnMap, Map<String, String> fieldTypeMap) {
|
||||
List<Param> children = (List<Param>) param.getChildren();
|
||||
QueryBuilder queryBuilder;
|
||||
RangeQueryBuilder rangeBuilder;
|
||||
String finalField;
|
||||
String realField;
|
||||
switch (param.getQueryTypeEnum()) {
|
||||
case OR:
|
||||
// 渣男行为,*完就不认人了,因为拼接OR已处理过了 直接跳过
|
||||
break;
|
||||
case TERM:
|
||||
finalField = getFinalField(param.getColumn(), param.isNeedAddKeywordSuffix());
|
||||
queryBuilder = QueryBuilders.termQuery(finalField, param.getVal()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.termQuery(realField, param.getVal()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case MATCH:
|
||||
queryBuilder = QueryBuilders.matchQuery(param.getColumn(), param.getVal()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.matchQuery(realField, param.getVal()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case MATCH_PHRASE:
|
||||
queryBuilder = QueryBuilders.matchPhraseQuery(param.getColumn(), param.getVal()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.matchPhraseQuery(realField, param.getVal()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case MATCH_PHRASE_PREFIX:
|
||||
queryBuilder = QueryBuilders.matchPhrasePrefixQuery(param.getColumn(), param.getVal()).boost(param.getBoost()).maxExpansions((int) param.getExt1());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.matchPhrasePrefixQuery(realField, param.getVal()).boost(param.getBoost()).maxExpansions((int) param.getExt1());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case MULTI_MATCH:
|
||||
queryBuilder = QueryBuilders.multiMatchQuery(param.getVal(), param.getColumns()).operator((Operator) param.getExt1()).minimumShouldMatch(String.valueOf(param.getExt2()));
|
||||
String[] realFields = getRealFields(param.getColumns(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.multiMatchQuery(param.getVal(), realFields).operator((Operator) param.getExt1()).minimumShouldMatch(String.valueOf(param.getExt2()));
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case MATCH_ALL:
|
||||
@ -172,111 +130,120 @@ public class WrapperProcessor {
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case QUERY_STRING:
|
||||
queryBuilder = QueryBuilders.queryStringQuery(param.getColumn()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.queryStringQuery(realField).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case PREFIX:
|
||||
queryBuilder = QueryBuilders.prefixQuery(param.getColumn(), (String) param.getVal()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.prefixQuery(realField, (String) param.getVal()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GT:
|
||||
rangeBuilder = QueryBuilders.rangeQuery(param.getColumn()).gt(param.getVal()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
rangeBuilder = QueryBuilders.rangeQuery(realField).gt(param.getVal()).boost(param.getBoost());
|
||||
Optional.ofNullable(param.getExt1()).ifPresent(ext1 -> rangeBuilder.timeZone(((ZoneId) ext1).getId()));
|
||||
Optional.ofNullable(param.getExt2()).ifPresent(ext2 -> rangeBuilder.format(ext2.toString()));
|
||||
setBool(bool, rangeBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GE:
|
||||
rangeBuilder = QueryBuilders.rangeQuery(param.getColumn()).gte(param.getVal()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
rangeBuilder = QueryBuilders.rangeQuery(realField).gte(param.getVal()).boost(param.getBoost());
|
||||
Optional.ofNullable(param.getExt1()).ifPresent(ext1 -> rangeBuilder.timeZone(((ZoneId) ext1).getId()));
|
||||
Optional.ofNullable(param.getExt2()).ifPresent(ext2 -> rangeBuilder.format(ext2.toString()));
|
||||
setBool(bool, rangeBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case LT:
|
||||
rangeBuilder = QueryBuilders.rangeQuery(param.getColumn()).lt(param.getVal()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
rangeBuilder = QueryBuilders.rangeQuery(realField).lt(param.getVal()).boost(param.getBoost());
|
||||
Optional.ofNullable(param.getExt1()).ifPresent(ext1 -> rangeBuilder.timeZone(((ZoneId) ext1).getId()));
|
||||
Optional.ofNullable(param.getExt2()).ifPresent(ext2 -> rangeBuilder.format(ext2.toString()));
|
||||
setBool(bool, rangeBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case LE:
|
||||
rangeBuilder = QueryBuilders.rangeQuery(param.getColumn()).lte(param.getVal()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
rangeBuilder = QueryBuilders.rangeQuery(realField).lte(param.getVal()).boost(param.getBoost());
|
||||
Optional.ofNullable(param.getExt1()).ifPresent(ext1 -> rangeBuilder.timeZone(((ZoneId) ext1).getId()));
|
||||
Optional.ofNullable(param.getExt2()).ifPresent(ext2 -> rangeBuilder.format(ext2.toString()));
|
||||
setBool(bool, rangeBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case BETWEEN:
|
||||
rangeBuilder = QueryBuilders.rangeQuery(param.getColumn()).gte(param.getExt1()).lte(param.getExt2()).boost(param.getBoost());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
rangeBuilder = QueryBuilders.rangeQuery(realField).gte(param.getExt1()).lte(param.getExt2()).boost(param.getBoost());
|
||||
Optional.ofNullable(param.getExt3()).ifPresent(ext3 -> rangeBuilder.timeZone(((ZoneId) ext3).getId()));
|
||||
Optional.ofNullable(param.getExt4()).ifPresent(ext4 -> rangeBuilder.format(ext4.toString()));
|
||||
setBool(bool, rangeBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case WILDCARD:
|
||||
finalField = getFinalField(param.getColumn(), param.isNeedAddKeywordSuffix());
|
||||
queryBuilder = QueryBuilders.wildcardQuery(finalField, param.getVal().toString());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.wildcardQuery(realField, param.getVal().toString());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case TERMS:
|
||||
finalField = getFinalField(param.getColumn(), param.isNeedAddKeywordSuffix());
|
||||
queryBuilder = QueryBuilders.termsQuery(finalField, (Collection<?>) param.getVal());
|
||||
realField = getRealFieldAndSuffix(param.getColumn(), fieldTypeMap, mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.termsQuery(realField, (Collection<?>) param.getVal());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case EXISTS:
|
||||
queryBuilder = QueryBuilders.existsQuery(param.getColumn()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.existsQuery(realField).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GEO_BOUNDING_BOX:
|
||||
queryBuilder = QueryBuilders.geoBoundingBoxQuery(param.getColumn()).setCorners((GeoPoint) param.getExt1(), (GeoPoint) param.getExt2()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.geoBoundingBoxQuery(realField).setCorners((GeoPoint) param.getExt1(), (GeoPoint) param.getExt2()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GEO_DISTANCE:
|
||||
GeoDistanceQueryBuilder geoDistanceBuilder = QueryBuilders.geoDistanceQuery(param.getColumn()).point((GeoPoint) param.getExt2()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
GeoDistanceQueryBuilder geoDistanceBuilder = QueryBuilders.geoDistanceQuery(realField).point((GeoPoint) param.getExt2()).boost(param.getBoost());
|
||||
MyOptional.ofNullable(param.getExt1()).ifPresent(ext1 -> geoDistanceBuilder.distance((double) param.getVal(), (DistanceUnit) ext1), () -> geoDistanceBuilder.distance((String) param.getVal()));
|
||||
queryBuilder = geoDistanceBuilder;
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GEO_POLYGON:
|
||||
queryBuilder = QueryBuilders.geoPolygonQuery(param.getColumn(), (List<GeoPoint>) param.getVal());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.geoPolygonQuery(realField, (List<GeoPoint>) param.getVal());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GEO_SHAPE_ID:
|
||||
queryBuilder = QueryBuilders.geoShapeQuery(param.getColumn(), param.getVal().toString()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.geoShapeQuery(realField, param.getVal().toString()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case GEO_SHAPE:
|
||||
queryBuilder = QueryBuilders.geoShapeQuery(param.getColumn(), (Geometry) param.getVal()).relation((ShapeRelation) param.getExt1()).boost(param.getBoost());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = QueryBuilders.geoShapeQuery(realField, (Geometry) param.getVal()).relation((ShapeRelation) param.getExt1()).boost(param.getBoost());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case HAS_CHILD:
|
||||
queryBuilder = new HasChildQueryBuilder(param.getExt1().toString(), QueryBuilders.matchQuery(param.getExt1().toString() + PATH_FIELD_JOIN + param.getColumn(), param.getVal()).boost(param.getBoost()), (ScoreMode) param.getExt2());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = new HasChildQueryBuilder(param.getExt1().toString(), QueryBuilders.matchQuery(param.getExt1().toString() + PATH_FIELD_JOIN + realField, param.getVal()).boost(param.getBoost()), (ScoreMode) param.getExt2());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case HAS_PARENT:
|
||||
queryBuilder = new HasParentQueryBuilder(param.getExt1().toString(), QueryBuilders.matchQuery(param.getExt1().toString() + PATH_FIELD_JOIN + param.getColumn(), param.getVal()).boost(param.getBoost()), (boolean) param.getExt2());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = new HasParentQueryBuilder(param.getExt1().toString(), QueryBuilders.matchQuery(param.getExt1().toString() + PATH_FIELD_JOIN + realField, param.getVal()).boost(param.getBoost()), (boolean) param.getExt2());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case PARENT_ID:
|
||||
queryBuilder = new ParentIdQueryBuilder(param.getColumn(), param.getVal().toString());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
queryBuilder = new ParentIdQueryBuilder(realField, param.getVal().toString());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
// 下面五种嵌套类型 需要对孩子节点递归处理
|
||||
case AND_MUST:
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery());
|
||||
setBool(bool, queryBuilder, AND_MUST);
|
||||
break;
|
||||
case FILTER:
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery());
|
||||
setBool(bool, queryBuilder, FILTER);
|
||||
break;
|
||||
case MUST_NOT:
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery());
|
||||
setBool(bool, queryBuilder, MUST_NOT);
|
||||
break;
|
||||
case OR_SHOULD:
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery());
|
||||
setBool(bool, queryBuilder, OR_SHOULD);
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery(), entityInfo, null);
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
case NESTED:
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery());
|
||||
queryBuilder = QueryBuilders.nestedQuery(param.getColumn(), queryBuilder, (ScoreMode) param.getVal());
|
||||
realField = getRealField(param.getColumn(), mappingColumnMap);
|
||||
String[] split = param.getColumn().split("\\.");
|
||||
queryBuilder = getBool(children, QueryBuilders.boolQuery(), entityInfo, split[split.length - 1]);
|
||||
queryBuilder = QueryBuilders.nestedQuery(realField, queryBuilder, (ScoreMode) param.getVal());
|
||||
setBool(bool, queryBuilder, param.getPrevQueryType());
|
||||
break;
|
||||
default:
|
||||
@ -285,7 +252,6 @@ public class WrapperProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置节点的bool
|
||||
*
|
||||
@ -303,6 +269,7 @@ public class WrapperProcessor {
|
||||
} else if (MUST_NOT.equals(parentType)) {
|
||||
bool.mustNot(queryBuilder);
|
||||
} else {
|
||||
// just ignore,almost never happen
|
||||
bool.must(queryBuilder);
|
||||
}
|
||||
}
|
||||
@ -314,28 +281,29 @@ public class WrapperProcessor {
|
||||
* @param builder 新的根bool
|
||||
* @return 子节点bool合集, 统一封装至入参builder中
|
||||
*/
|
||||
private static BoolQueryBuilder getBool(List<Param> paramList, BoolQueryBuilder builder) {
|
||||
private static BoolQueryBuilder getBool(List<Param> paramList, BoolQueryBuilder builder, EntityInfo entityInfo, String path) {
|
||||
if (CollectionUtils.isEmpty(paramList)) {
|
||||
return builder;
|
||||
}
|
||||
paramList.forEach(param -> initBool(builder, param));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段最终名称
|
||||
*
|
||||
* @param origin 初始值
|
||||
* @param condition 是否拼接
|
||||
* @return 最终字段名
|
||||
*/
|
||||
private static String getFinalField(String origin, boolean condition) {
|
||||
if (condition && origin != null) {
|
||||
if (!origin.endsWith(KEYWORD_SUFFIX)) {
|
||||
return origin + KEYWORD_SUFFIX;
|
||||
}
|
||||
// 获取字段名称映射关系以及字段类型映射关系
|
||||
Map<String, String> mappingColumnMap;
|
||||
Map<String, String> fieldTypeMap;
|
||||
if (StringUtils.isNotBlank(path)) {
|
||||
// 嵌套类型
|
||||
Class<?> clazz = entityInfo.getPathClassMap().get(path);
|
||||
mappingColumnMap = Optional.ofNullable(entityInfo.getNestedClassMappingColumnMap().get(clazz))
|
||||
.orElse(new HashMap<>(0));
|
||||
fieldTypeMap = Optional.ofNullable(entityInfo.getNestedClassFieldTypeMap().get(clazz))
|
||||
.orElse(new HashMap<>(0));
|
||||
} else {
|
||||
mappingColumnMap = entityInfo.getMappingColumnMap();
|
||||
fieldTypeMap = entityInfo.getFieldTypeMap();
|
||||
}
|
||||
return origin;
|
||||
|
||||
// 批量初始化每一个参数至BoolQueryBuilder
|
||||
paramList.forEach(param -> initBool(builder, param, entityInfo, mappingColumnMap, fieldTypeMap));
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@ -405,10 +373,10 @@ public class WrapperProcessor {
|
||||
if (ArrayUtils.isEmpty(wrapper.include) && ArrayUtils.isEmpty(wrapper.exclude)) {
|
||||
return;
|
||||
}
|
||||
// 获取配置
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
String[] includes = FieldUtils.getRealFields(wrapper.include, mappingColumnMap, dbConfig);
|
||||
String[] excludes = FieldUtils.getRealFields(wrapper.exclude, mappingColumnMap, dbConfig);
|
||||
|
||||
// 获取实际字段
|
||||
String[] includes = FieldUtils.getRealFields(wrapper.include, mappingColumnMap);
|
||||
String[] excludes = FieldUtils.getRealFields(wrapper.exclude, mappingColumnMap);
|
||||
searchSourceBuilder.fetchSource(includes, excludes);
|
||||
}
|
||||
|
||||
@ -450,15 +418,12 @@ public class WrapperProcessor {
|
||||
* @param searchSourceBuilder 查询参数建造者
|
||||
*/
|
||||
private static void setSort(Wrapper<?> wrapper, Map<String, String> mappingColumnMap, SearchSourceBuilder searchSourceBuilder) {
|
||||
// 获取配置
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
|
||||
// 批量设置排序字段
|
||||
if (CollectionUtils.isNotEmpty(wrapper.baseSortParams)) {
|
||||
wrapper.baseSortParams.forEach(baseSortParam -> {
|
||||
// 获取es中的实际字段 有可能已经被用户自定义或者驼峰转成下划线
|
||||
String realField = Objects.isNull(baseSortParam.getSortField()) ?
|
||||
null : FieldUtils.getRealField(baseSortParam.getSortField(), mappingColumnMap, dbConfig);
|
||||
null : getRealField(baseSortParam.getSortField(), mappingColumnMap);
|
||||
SortBuilder<?> sortBuilder = getSortBuilder(realField, baseSortParam);
|
||||
Optional.ofNullable(sortBuilder).ifPresent(searchSourceBuilder::sort);
|
||||
});
|
||||
@ -518,13 +483,10 @@ public class WrapperProcessor {
|
||||
*/
|
||||
private static void setAggregations(Wrapper<?> wrapper, Map<String, String> mappingColumnMap,
|
||||
SearchSourceBuilder searchSourceBuilder) {
|
||||
// 获取配置
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
|
||||
// 设置折叠(去重)字段
|
||||
Optional.ofNullable(wrapper.distinctField)
|
||||
.ifPresent(distinctField -> {
|
||||
String realField = FieldUtils.getRealField(distinctField, mappingColumnMap, dbConfig);
|
||||
String realField = getRealField(distinctField, mappingColumnMap);
|
||||
searchSourceBuilder.collapse(new CollapseBuilder(realField));
|
||||
searchSourceBuilder.aggregation(AggregationBuilders.cardinality(REPEAT_NUM_KEY).field(realField));
|
||||
});
|
||||
@ -539,7 +501,7 @@ public class WrapperProcessor {
|
||||
AggregationBuilder root = null;
|
||||
AggregationBuilder cursor = null;
|
||||
for (AggregationParam aggParam : aggregationParamList) {
|
||||
String realField = FieldUtils.getRealField(aggParam.getField(), mappingColumnMap, dbConfig);
|
||||
String realField = getRealField(aggParam.getField(), mappingColumnMap);
|
||||
AggregationBuilder builder = getRealAggregationBuilder(aggParam.getAggregationType(), aggParam.getName(), realField);
|
||||
if (aggParam.isEnablePipeline()) {
|
||||
// 管道聚合, 构造聚合树
|
||||
|
||||
@ -315,12 +315,14 @@ public class EntityInfoHelper {
|
||||
}
|
||||
|
||||
// 其它
|
||||
FieldType fieldType = FieldType.getByType(IndexUtils.getEsFieldType(tableField.fieldType(), field.getType().getSimpleName()));
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
entityFieldInfo.setAnalyzer(tableField.analyzer());
|
||||
entityFieldInfo.setSearchAnalyzer(tableField.searchAnalyzer());
|
||||
entityFieldInfo.setFieldType(tableField.fieldType());
|
||||
entityFieldInfo.setFieldType(fieldType);
|
||||
entityFieldInfo.setFieldData(tableField.fieldData());
|
||||
entityFieldInfo.setColumnType(field.getType().getSimpleName());
|
||||
entityInfo.getFieldTypeMap().putIfAbsent(field.getName(), fieldType.getType());
|
||||
|
||||
// 父子类型
|
||||
if (FieldType.JOIN.equals(tableField.fieldType())) {
|
||||
@ -389,18 +391,22 @@ public class EntityInfoHelper {
|
||||
List<Field> allFields = getAllFields(nestedClass);
|
||||
Map<String, String> mappingColumnMap = new HashMap<>(allFields.size());
|
||||
Map<String, String> columnMappingMap = new HashMap<>(allFields.size());
|
||||
Map<String, String> fieldTypeMap = new HashMap<>();
|
||||
|
||||
List<EntityFieldInfo> entityFieldInfoList = new ArrayList<>();
|
||||
Set<String> notSerializedFields = new HashSet<>();
|
||||
allFields.forEach(field -> {
|
||||
String mappingColumn;
|
||||
FieldType fieldType;
|
||||
// 处理TableField注解
|
||||
IndexField tableField = field.getAnnotation(IndexField.class);
|
||||
if (Objects.isNull(tableField)) {
|
||||
mappingColumn = getMappingColumn(dbConfig, field);
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field);
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
entityFieldInfo.setFieldType(FieldType.TEXT);
|
||||
entityFieldInfo.setColumnType(FieldType.TEXT.getType());
|
||||
fieldType = FieldType.getByType(IndexUtils.getEsFieldType(FieldType.NONE, field.getType().getSimpleName()));
|
||||
entityFieldInfo.setFieldType(fieldType);
|
||||
entityFieldInfo.setColumnType(field.getType().getSimpleName());
|
||||
entityFieldInfoList.add(entityFieldInfo);
|
||||
} else {
|
||||
if (tableField.exist()) {
|
||||
@ -419,7 +425,7 @@ public class EntityInfoHelper {
|
||||
|
||||
// 设置实体字段信息
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, tableField);
|
||||
FieldType fieldType = FieldType.NONE.equals(tableField.fieldType()) ? FieldType.KEYWORD : tableField.fieldType();
|
||||
fieldType = FieldType.NONE.equals(tableField.fieldType()) ? FieldType.KEYWORD_TEXT : tableField.fieldType();
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
entityFieldInfo.setFieldType(fieldType);
|
||||
entityFieldInfo.setFieldData(tableField.fieldData());
|
||||
@ -432,18 +438,20 @@ public class EntityInfoHelper {
|
||||
entityFieldInfoList.add(entityFieldInfo);
|
||||
} else {
|
||||
mappingColumn = getMappingColumn(dbConfig, field);
|
||||
fieldType = FieldType.KEYWORD_TEXT;
|
||||
notSerializedFields.add(field.getName());
|
||||
}
|
||||
}
|
||||
columnMappingMap.putIfAbsent(mappingColumn, field.getName());
|
||||
mappingColumnMap.putIfAbsent(field.getName(), mappingColumn);
|
||||
fieldTypeMap.putIfAbsent(field.getName(), fieldType.getType());
|
||||
|
||||
});
|
||||
entityInfo.getNestedNotSerializeField().putIfAbsent(nestedClass, notSerializedFields);
|
||||
entityInfo.getNestedClassColumnMappingMap().putIfAbsent(nestedClass, columnMappingMap);
|
||||
entityInfo.getNestedClassMappingColumnMap().putIfAbsent(nestedClass, mappingColumnMap);
|
||||
entityInfo.getNestedClassFieldTypeMap().putIfAbsent(nestedClass, fieldTypeMap);
|
||||
entityInfo.getNestedFieldListMap().put(nestedClass, entityFieldInfoList);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -466,6 +474,8 @@ public class EntityInfoHelper {
|
||||
// 初始化
|
||||
String mappingColumn = initMappingColumnMapAndGet(dbConfig, entityInfo, field);
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
FieldType fieldType = FieldType.getByType(IndexUtils.getEsFieldType(FieldType.NONE, field.getType().getSimpleName()));
|
||||
entityInfo.getFieldTypeMap().putIfAbsent(field.getName(), fieldType.getType());
|
||||
entityFieldInfo.setColumnType(field.getType().getSimpleName());
|
||||
fieldList.add(entityFieldInfo);
|
||||
}
|
||||
@ -588,6 +598,9 @@ public class EntityInfoHelper {
|
||||
} else {
|
||||
indexName = tableName;
|
||||
}
|
||||
if (StringUtils.isNotBlank(table.routing())) {
|
||||
entityInfo.setRouting(table.routing());
|
||||
}
|
||||
entityInfo.setMaxResultWindow(table.maxResultWindow());
|
||||
entityInfo.setAliasName(table.aliasName());
|
||||
entityInfo.setShardsNum(table.shardsNum());
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.easyes.core.toolkit;
|
||||
|
||||
import cn.easyes.annotation.rely.FieldType;
|
||||
import cn.easyes.common.constants.BaseEsConstants;
|
||||
import cn.easyes.common.params.SFunction;
|
||||
import cn.easyes.common.utils.StringUtils;
|
||||
@ -18,8 +19,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.easyes.common.constants.BaseEsConstants.DEFAULT_ES_ID_NAME;
|
||||
import static cn.easyes.common.constants.BaseEsConstants.DEFAULT_ID_NAME;
|
||||
import static cn.easyes.common.constants.BaseEsConstants.*;
|
||||
|
||||
/**
|
||||
* 核心 处理字段名称工具类
|
||||
@ -165,16 +165,17 @@ public class FieldUtils {
|
||||
/**
|
||||
* 获取实际字段名
|
||||
*
|
||||
* @param field 原字段名
|
||||
* @param mappingColumnMap 字段映射关系map
|
||||
* @param dbConfig 配置
|
||||
* @param field 原字段名
|
||||
* @param mappingColumnMap 字段映射关系map
|
||||
* @param isMapUnderscoreToCamelCase 是否开启下划线自动转驼峰
|
||||
* @return 实际字段名
|
||||
*/
|
||||
public static String getRealField(String field, Map<String, String> mappingColumnMap, GlobalConfig.DbConfig dbConfig) {
|
||||
public static String getRealField(String field, Map<String, String> mappingColumnMap) {
|
||||
String customField = mappingColumnMap.get(field);
|
||||
if (Objects.nonNull(customField)) {
|
||||
return DEFAULT_ID_NAME.equals(customField) ? DEFAULT_ES_ID_NAME : customField;
|
||||
} else {
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
if (dbConfig.isMapUnderscoreToCamelCase()) {
|
||||
return StringUtils.camelToUnderline(field);
|
||||
} else {
|
||||
@ -183,21 +184,40 @@ public class FieldUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实际字段名 并且根据配置智能追加.keyword后缀
|
||||
*
|
||||
* @param field 字段
|
||||
* @param fieldTypeMap 字段与es字段类型映射
|
||||
* @param mappingColumnMap 实体字段与es实际字段映射
|
||||
* @return 最终的字段
|
||||
*/
|
||||
public static String getRealFieldAndSuffix(String field, Map<String, String> fieldTypeMap, Map<String, String> mappingColumnMap) {
|
||||
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
|
||||
String realField = getRealField(field, mappingColumnMap);
|
||||
String fieldType = fieldTypeMap.get(field);
|
||||
boolean addSuffix = dbConfig.isSmartAddKeywordSuffix() && FieldType.KEYWORD_TEXT.getType().equals(fieldType);
|
||||
if (addSuffix) {
|
||||
return realField + KEYWORD_SUFFIX;
|
||||
}
|
||||
return realField;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取实际字段名 不转换id
|
||||
*
|
||||
* @param field 原字段名
|
||||
* @param mappingColumnMap 字段映射关系map
|
||||
* @param dbConfig 配置
|
||||
* @param field 原字段名
|
||||
* @param mappingColumnMap 字段映射关系map
|
||||
* @param isMapUnderscoreToCamelCase 是否开启下划线自动转驼峰
|
||||
* @return 实际字段名
|
||||
*/
|
||||
public static String getRealFieldNotConvertId(String field, Map<String, String> mappingColumnMap, GlobalConfig.DbConfig dbConfig) {
|
||||
public static String getRealFieldNotConvertId(String field, Map<String, String> mappingColumnMap, boolean isMapUnderscoreToCamelCase) {
|
||||
String customField = mappingColumnMap.get(field);
|
||||
if (Objects.nonNull(customField)) {
|
||||
return customField;
|
||||
} else {
|
||||
if (dbConfig.isMapUnderscoreToCamelCase()) {
|
||||
if (isMapUnderscoreToCamelCase) {
|
||||
return StringUtils.camelToUnderline(field);
|
||||
} else {
|
||||
return field;
|
||||
@ -210,12 +230,11 @@ public class FieldUtils {
|
||||
*
|
||||
* @param fields 原字段名数组
|
||||
* @param mappingColumnMap 字段映射关系map
|
||||
* @param dbConfig 配置
|
||||
* @return 实际字段数组
|
||||
*/
|
||||
public static String[] getRealFields(String[] fields, Map<String, String> mappingColumnMap, GlobalConfig.DbConfig dbConfig) {
|
||||
public static String[] getRealFields(String[] fields, Map<String, String> mappingColumnMap) {
|
||||
return Arrays.stream(fields)
|
||||
.map(field -> getRealField(field, mappingColumnMap, dbConfig))
|
||||
.map(field -> getRealField(field, mappingColumnMap))
|
||||
.collect(Collectors.toList())
|
||||
.toArray(new String[]{});
|
||||
}
|
||||
@ -228,7 +247,7 @@ public class FieldUtils {
|
||||
* @return 实际字段数组
|
||||
*/
|
||||
public static List<String> getRealFields(List<String> fields, Map<String, String> mappingColumnMap) {
|
||||
return Arrays.stream(getRealFields(fields.toArray(new String[0]), mappingColumnMap, GlobalConfigCache.getGlobalConfig().getDbConfig()))
|
||||
return Arrays.stream(getRealFields(fields.toArray(new String[0]), mappingColumnMap))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@ -101,7 +101,6 @@ public class IndexUtils {
|
||||
*/
|
||||
public static boolean createIndex(RestHighLevelClient client, EntityInfo entityInfo, CreateIndexParam indexParam) {
|
||||
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexParam.getIndexName());
|
||||
|
||||
// 设置settings信息
|
||||
if (Objects.isNull(indexParam.getSettings())) {
|
||||
// 分片个副本信息
|
||||
@ -238,7 +237,8 @@ public class IndexUtils {
|
||||
reindexRequest.setDestOpType(BaseEsConstants.DEFAULT_DEST_OP_TYPE);
|
||||
reindexRequest.setConflicts(BaseEsConstants.DEFAULT_CONFLICTS);
|
||||
reindexRequest.setRefresh(Boolean.TRUE);
|
||||
reindexRequest.setTimeout(TimeValue.MAX_VALUE);
|
||||
int reindexTimeOutHours = GlobalConfigCache.getGlobalConfig().getReindexTimeOutHours();
|
||||
reindexRequest.setTimeout(TimeValue.timeValueHours(reindexTimeOutHours));
|
||||
try {
|
||||
BulkByScrollResponse response = client.reindex(reindexRequest, RequestOptions.DEFAULT);
|
||||
List<BulkItemResponse.Failure> bulkFailures = response.getBulkFailures();
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.List;
|
||||
**/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class)
|
||||
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class,routing = "666")
|
||||
public class Document {
|
||||
/**
|
||||
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
|
||||
|
||||
@ -4,7 +4,6 @@ import cn.easyes.common.constants.BaseEsConstants;
|
||||
import cn.easyes.core.biz.EsPageInfo;
|
||||
import cn.easyes.core.biz.OrderByParam;
|
||||
import cn.easyes.core.biz.SAPageInfo;
|
||||
import cn.easyes.core.cache.GlobalConfigCache;
|
||||
import cn.easyes.core.conditions.select.LambdaEsQueryWrapper;
|
||||
import cn.easyes.core.conditions.update.LambdaEsUpdateWrapper;
|
||||
import cn.easyes.core.core.EsWrappers;
|
||||
@ -177,9 +176,7 @@ public class AllTest {
|
||||
@Order(6)
|
||||
public void testOne() {
|
||||
// 链式调用
|
||||
Document document = EsWrappers.lambdaChainQuery(documentMapper)
|
||||
.eq(Document::getTitle, "测试文档3")
|
||||
.one();
|
||||
Document document = EsWrappers.lambdaChainQuery(documentMapper).eq(Document::getTitle, "测试文档3").one();
|
||||
Assertions.assertEquals(document.getContent(), "测试文档内容3的内容被修改了");
|
||||
}
|
||||
|
||||
@ -196,8 +193,6 @@ public class AllTest {
|
||||
public void testSelectBatchIds() {
|
||||
List<Document> documents = documentMapper.selectBatchIds(Arrays.asList("1", "2"));
|
||||
Assertions.assertEquals(2, documents.size());
|
||||
Assertions.assertEquals("1", documents.get(1).getEsId());
|
||||
Assertions.assertEquals("老汉2", documents.get(0).getCreator());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -568,7 +563,7 @@ public class AllTest {
|
||||
wrapper.orderByDesc(Document::getStarNum);
|
||||
List<Document> documents = documentMapper.selectList(wrapper);
|
||||
Assertions.assertEquals("22", documents.get(0).getEsId());
|
||||
Assertions.assertEquals("1", documents.get(21).getEsId());
|
||||
Assertions.assertEquals("21", documents.get(1).getEsId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -595,7 +590,7 @@ public class AllTest {
|
||||
wrapper.orderBy(orderByParams);
|
||||
List<Document> documents = documentMapper.selectList(wrapper);
|
||||
Assertions.assertEquals("22", documents.get(0).getEsId());
|
||||
Assertions.assertEquals("1", documents.get(21).getEsId());
|
||||
Assertions.assertEquals("21", documents.get(1).getEsId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -657,13 +652,12 @@ public class AllTest {
|
||||
FieldSortBuilder fieldSortBuilder = SortBuilders.
|
||||
fieldSort(FieldUtils.getRealField(
|
||||
FieldUtils.val(Document::getStarNum),
|
||||
EntityInfoHelper.getEntityInfo(Document.class).getMappingColumnMap(),
|
||||
GlobalConfigCache.getGlobalConfig().getDbConfig()));
|
||||
EntityInfoHelper.getEntityInfo(Document.class).getMappingColumnMap()));
|
||||
fieldSortBuilder.order(SortOrder.DESC);
|
||||
wrapper.sort(fieldSortBuilder);
|
||||
List<Document> documents = documentMapper.selectList(wrapper);
|
||||
Assertions.assertEquals("22", documents.get(0).getEsId());
|
||||
Assertions.assertEquals("1", documents.get(21).getEsId());
|
||||
Assertions.assertEquals("21", documents.get(1).getEsId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -852,11 +846,11 @@ public class AllTest {
|
||||
|
||||
System.out.println(boolQueryBuilder);
|
||||
System.out.println("--------------------");
|
||||
|
||||
// MP及EE写法
|
||||
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
|
||||
wrapper.eq("business_type", 1)
|
||||
.and(a -> a.eq("state", 9).or(b -> b.eq("state", 8).eq("bidding_sign", 1))
|
||||
)
|
||||
.and(a -> a.eq("state", 9).or(b -> b.eq("state", 8).eq("bidding_sign", 1)))
|
||||
.or(i -> i.eq("business_type", 2).in("state", 2, 3));
|
||||
documentMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@ -101,12 +101,8 @@ public class NestedTest {
|
||||
.or()
|
||||
.nested("users.faqs", w -> w.match("faq_name", "q3"));
|
||||
List<Document> documents2 = documentMapper.selectList(wrapper2);
|
||||
|
||||
System.out.println(documents2);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
String val = FieldUtils.val(User::getAge);
|
||||
System.out.println(val);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user