diff --git a/easy-es-core/src/main/java/cn/easyes/core/Param.java b/easy-es-core/src/main/java/cn/easyes/core/Param.java index ec8cfb15..81677c55 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/Param.java +++ b/easy-es-core/src/main/java/cn/easyes/core/Param.java @@ -11,6 +11,10 @@ import lombok.Data; **/ @Data public class Param extends Tree { + /** + * 上一节点类型 + */ + private EsQueryTypeEnum prevQueryType; /** * 节点类型 */ diff --git a/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractChainWrapper.java b/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractChainWrapper.java index c85951bf..86eb4eee 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractChainWrapper.java +++ b/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractChainWrapper.java @@ -44,14 +44,14 @@ public abstract class AbstractChainWrapper Children allEq(boolean condition, Map params, boolean null2IsNull) { - getWrapper().allEq(condition, params, null2IsNull); + public Children allEq(boolean condition, Map params) { + getWrapper().allEq(condition, params); return typedThis; } @Override - public Children allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull) { - getWrapper().allEq(condition, filter, params, null2IsNull); + public Children allEq(boolean condition, BiPredicate filter, Map params) { + getWrapper().allEq(condition, filter, params); return typedThis; } diff --git a/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractWrapper.java b/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractWrapper.java index b98db5d8..5ac3ca3a 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractWrapper.java +++ b/easy-es-core/src/main/java/cn/easyes/core/conditions/AbstractWrapper.java @@ -45,6 +45,10 @@ public abstract class AbstractWrapper queue; + protected LinkedList parentIdQueue; + /** + * 队列 存放上一节点类型 + */ + protected LinkedList prevQueryTypeQueue; /** * 基础排序参数列表 */ @@ -111,11 +119,13 @@ public abstract class AbstractWrapper(); paramList = new ArrayList<>(); level = 0; - queue = new LinkedList<>(); + prevQueryType = AND_MUST; + parentIdQueue = new LinkedList<>(); + prevQueryTypeQueue = new LinkedList<>(); } @Override - public Children allEq(boolean condition, Map params, boolean null2IsNull) { + public Children allEq(boolean condition, Map params) { if (condition && CollectionUtils.isNotEmpty(params)) { params.forEach(this::eq); } @@ -123,7 +133,7 @@ public abstract class AbstractWrapper Children allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull) { + public Children allEq(boolean condition, BiPredicate filter, Map params) { if (condition && CollectionUtils.isNotEmpty(params)) { params.forEach((k, v) -> { if (filter.test(k, v)) { @@ -520,10 +530,20 @@ public abstract class AbstractWrapper extends AbstractLambdaQueryWrapper paramList, LinkedList queue, Integer level, String parentId, List baseSortParams, - List aggregationParamList) { + LambdaEsQueryWrapper(T entity, List paramList, LinkedList parentIdQueue, + LinkedList prevQueryTypeQueue, Integer level, String parentId, + EsQueryTypeEnum pervQueryType, List baseSortParams, List aggregationParamList) { super.setEntity(entity); - this.queue = queue; + this.parentIdQueue = parentIdQueue; + this.prevQueryTypeQueue = prevQueryTypeQueue; this.level = level; this.parentId = parentId; + this.prevQueryType = pervQueryType; this.paramList = paramList; this.baseSortParams = baseSortParams; this.aggregationParamList = aggregationParamList; @@ -71,7 +75,7 @@ public class LambdaEsQueryWrapper extends AbstractLambdaQueryWrapper instance() { - return new LambdaEsQueryWrapper<>(entity, paramList, queue, level, parentId, baseSortParams, aggregationParamList); + return new LambdaEsQueryWrapper<>(entity, paramList, parentIdQueue, prevQueryTypeQueue, level, parentId, prevQueryType, baseSortParams, aggregationParamList); } @Override diff --git a/easy-es-core/src/main/java/cn/easyes/core/conditions/WrapperProcessor.java b/easy-es-core/src/main/java/cn/easyes/core/conditions/WrapperProcessor.java index 5d5ec588..30580539 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/conditions/WrapperProcessor.java +++ b/easy-es-core/src/main/java/cn/easyes/core/conditions/WrapperProcessor.java @@ -41,7 +41,7 @@ import static cn.easyes.common.constants.BaseEsConstants.*; import static cn.easyes.common.enums.EsQueryTypeEnum.*; /** - * 核心 wrpeer处理类 + * 核心 wrapper处理类 *

* Copyright © 2021 xpc1024 All Rights Reserved **/ @@ -76,9 +76,27 @@ public class WrapperProcessor { */ public static BoolQueryBuilder initBoolQueryBuilder(List paramList, Class entityClass) { // 数据预处理 + List rootList = new ArrayList<>(); + preProcessData(paramList, rootList, entityClass); + + // 建立参数森林(无根树) + TreeBuilder treeBuilder = new TreeBuilder(rootList, paramList); + List tree = (List) treeBuilder.build(); + BoolQueryBuilder rootBool = QueryBuilders.boolQuery(); + + // 对森林的每个根节点递归封装 这里看似简单实则很绕很烧脑 整个框架的核心 主要依托树的递归 深度优先遍历 森林 + return getBool(tree, rootBool); + } + + /*** + * 数据预处理 原始数据转换为目标数据 + * @param paramList 参数列表 + * @param rootList 子树根 + * @param entityClass 实体类 + */ + private static void preProcessData(List paramList, List rootList, Class entityClass) { EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass); GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig(); - List rootList = new ArrayList<>(); paramList.forEach(param -> { // 驼峰及自定义字段转换 String realField = FieldUtils.getRealField(param.getColumn(), entityInfo.getMappingColumnMap(), dbConfig); @@ -98,41 +116,16 @@ public class WrapperProcessor { rootList.add(param); } }); - - // 建树 - TreeBuilder treeBuilder = new TreeBuilder(rootList, paramList); - List tree = (List) treeBuilder.build(); - BoolQueryBuilder rootBool = QueryBuilders.boolQuery(); - - // 遍历,对森林的每个根节点递归封装 - EsQueryTypeEnum parentQueryType = getParentQueryType(dbConfig.isEnableMust2Filter()); - tree.forEach(root -> setBool(rootBool, root, parentQueryType)); - return rootBool; - } - - /** - * 根据配置获取根节点查询类型 - * - * @param enableMust2Filter 是否开启must转filter配置 true开启 false 否 - * @return 根节点查询类型 - */ - private static EsQueryTypeEnum getParentQueryType(boolean enableMust2Filter) { - if (enableMust2Filter) { - return EsQueryTypeEnum.FILTER; - } else { - return EsQueryTypeEnum.AND_MUST; - } } /** * 递归封装bool查询条件 * - * @param bool BoolQueryBuilder - * @param param 查询参数 - * @param parentType 父查询类型 + * @param bool BoolQueryBuilder + * @param param 查询参数 */ @SneakyThrows - private static void setBool(BoolQueryBuilder bool, Param param, EsQueryTypeEnum parentType) { + private static void initBool(BoolQueryBuilder bool, Param param) { List children = (List) param.getChildren(); QueryBuilder queryBuilder; switch (param.getQueryTypeEnum()) { @@ -141,121 +134,122 @@ public class WrapperProcessor { break; case TERM: queryBuilder = QueryBuilders.termQuery(param.getColumn(), param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case MATCH: queryBuilder = QueryBuilders.matchQuery(param.getColumn(), param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case MATCH_PHRASE: queryBuilder = QueryBuilders.matchPhraseQuery(param.getColumn(), param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case MATCH_PHRASE_PREFIX: queryBuilder = QueryBuilders.matchPhrasePrefixQuery(param.getColumn(), param.getVal()).boost(param.getBoost()).maxExpansions((int) param.getExt1()); - setChildrenBool(bool, queryBuilder, parentType); + 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())); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case MATCH_ALL: queryBuilder = QueryBuilders.matchAllQuery().boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case QUERY_STRING: queryBuilder = QueryBuilders.queryStringQuery(param.getColumn()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case PREFIX: queryBuilder = QueryBuilders.prefixQuery(param.getColumn(), (String) param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GT: queryBuilder = QueryBuilders.rangeQuery(param.getColumn()).gt(param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GE: queryBuilder = QueryBuilders.rangeQuery(param.getColumn()).gte(param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case LT: queryBuilder = QueryBuilders.rangeQuery(param.getColumn()).lt(param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case LE: queryBuilder = QueryBuilders.rangeQuery(param.getColumn()).lte(param.getVal()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case BETWEEN: queryBuilder = QueryBuilders.rangeQuery(param.getColumn()).gte(param.getExt1()).lte(param.getExt2()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case WILDCARD: queryBuilder = QueryBuilders.wildcardQuery(param.getColumn(), param.getVal().toString()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case TERMS: queryBuilder = QueryBuilders.termsQuery(param.getColumn(), (Collection) param.getVal()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case EXISTS: queryBuilder = QueryBuilders.existsQuery(param.getColumn()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + 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()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GEO_DISTANCE: GeoDistanceQueryBuilder geoDistanceBuilder = QueryBuilders.geoDistanceQuery(param.getColumn()).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; - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GEO_POLYGON: queryBuilder = QueryBuilders.geoPolygonQuery(param.getColumn(), (List) param.getVal()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GEO_SHAPE_ID: queryBuilder = QueryBuilders.geoShapeQuery(param.getColumn(), param.getVal().toString()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case GEO_SHAPE: queryBuilder = QueryBuilders.geoShapeQuery(param.getColumn(), (Geometry) param.getVal()).relation((ShapeRelation) param.getExt1()).boost(param.getBoost()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case NESTED_MATCH: queryBuilder = QueryBuilders.nestedQuery(param.getExt1().toString(), QueryBuilders.matchQuery(param.getExt1().toString() + PATH_FIELD_JOIN + param.getColumn(), param.getVal()).boost(param.getBoost()), (ScoreMode) param.getExt2()); - setChildrenBool(bool, queryBuilder, parentType); + 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()); - setChildrenBool(bool, queryBuilder, parentType); + 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()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; case PARENT_ID: queryBuilder = new ParentIdQueryBuilder(param.getColumn(), param.getVal().toString()); - setChildrenBool(bool, queryBuilder, parentType); + setBool(bool, queryBuilder, param.getPrevQueryType()); break; + // 下面四种嵌套类型 需要对孩子节点递归处理 case AND_MUST: - queryBuilder = getChildrenBool(children, QueryBuilders.boolQuery(), parentType); - setChildrenBool(bool, queryBuilder, AND_MUST); + queryBuilder = getBool(children, QueryBuilders.boolQuery()); + setBool(bool, queryBuilder, AND_MUST); break; case FILTER: - queryBuilder = getChildrenBool(children, QueryBuilders.boolQuery(), parentType); - setChildrenBool(bool, queryBuilder, FILTER); + queryBuilder = getBool(children, QueryBuilders.boolQuery()); + setBool(bool, queryBuilder, FILTER); break; case MUST_NOT: - queryBuilder = getChildrenBool(children, QueryBuilders.boolQuery(), parentType); - setChildrenBool(bool, queryBuilder, MUST_NOT); + queryBuilder = getBool(children, QueryBuilders.boolQuery()); + setBool(bool, queryBuilder, MUST_NOT); break; case OR_SHOULD: - queryBuilder = getChildrenBool(children, QueryBuilders.boolQuery(), parentType); - setChildrenBool(bool, queryBuilder, OR_SHOULD); + queryBuilder = getBool(children, QueryBuilders.boolQuery()); + setBool(bool, queryBuilder, OR_SHOULD); break; default: throw ExceptionUtils.eee("非法参数类型"); @@ -263,13 +257,13 @@ public class WrapperProcessor { } /** - * 设置孩子节点的bool + * 设置节点的bool * - * @param bool 父节点BoolQueryBuilder - * @param queryBuilder 孩子节点BoolQueryBuilder + * @param bool 根节点BoolQueryBuilder + * @param queryBuilder 非根节点BoolQueryBuilder * @param parentType 查询类型 */ - private static void setChildrenBool(BoolQueryBuilder bool, QueryBuilder queryBuilder, EsQueryTypeEnum parentType) { + private static void setBool(BoolQueryBuilder bool, QueryBuilder queryBuilder, EsQueryTypeEnum parentType) { if (EsQueryTypeEnum.AND_MUST.equals(parentType)) { bool.must(queryBuilder); } else if (EsQueryTypeEnum.OR_SHOULD.equals(parentType)) { @@ -288,11 +282,11 @@ public class WrapperProcessor { * @param builder 新的根bool * @return 子节点bool合集, 统一封装至入参builder中 */ - private static BoolQueryBuilder getChildrenBool(List paramList, BoolQueryBuilder builder, EsQueryTypeEnum parentType) { + private static BoolQueryBuilder getBool(List paramList, BoolQueryBuilder builder) { if (CollectionUtils.isEmpty(paramList)) { return builder; } - paramList.forEach(param -> setBool(builder, param, parentType)); + paramList.forEach(param -> initBool(builder, param)); return builder; } diff --git a/easy-es-core/src/main/java/cn/easyes/core/conditions/interfaces/Compare.java b/easy-es-core/src/main/java/cn/easyes/core/conditions/interfaces/Compare.java index 4a2301d6..ef86167a 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/conditions/interfaces/Compare.java +++ b/easy-es-core/src/main/java/cn/easyes/core/conditions/interfaces/Compare.java @@ -19,44 +19,34 @@ import static cn.easyes.common.constants.BaseEsConstants.*; public interface Compare extends Serializable { default Children allEq(Map params) { - return allEq(params, true); - } - - - default Children allEq(Map params, boolean null2IsNull) { - return allEq(true, params, null2IsNull); + return allEq(true, params); } /** * map 所有非空属性等于 = * - * @param condition 执行条件 - * @param params map 类型的参数, key 是字段名, value 是字段值 - * @param null2IsNull 是否参数为 null 自动执行 isNull 方法, false 则忽略这个字段 - * @param ignore + * @param condition 执行条件 + * @param params map 类型的参数, key 是字段名, value 是字段值 + * @param ignore * @return children */ - Children allEq(boolean condition, Map params, boolean null2IsNull); + Children allEq(boolean condition, Map params); + default Children allEq(BiPredicate filter, Map params) { - return allEq(filter, params, true); - } - - default Children allEq(BiPredicate filter, Map params, boolean null2IsNull) { - return allEq(true, filter, params, null2IsNull); + return allEq(true, filter, params); } /** * 字段过滤接口,传入多参数时允许对参数进行过滤 * - * @param condition 执行条件 - * @param filter 返回 true 来允许字段传入比对条件中 - * @param params map 类型的参数, key 是字段名, value 是字段值 - * @param null2IsNull 是否参数为 null 自动执行 isNull 方法, false 则忽略这个字段 - * @param ignore + * @param condition 执行条件 + * @param filter 返回 true 来允许字段传入比对条件中 + * @param params map 类型的参数, key 是字段名, value 是字段值 + * @param ignore * @return 泛型 */ - Children allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull); + Children allEq(boolean condition, BiPredicate filter, Map params); default Children eq(R column, Object val) { return eq(true, column, val); diff --git a/easy-es-core/src/main/java/cn/easyes/core/config/GlobalConfig.java b/easy-es-core/src/main/java/cn/easyes/core/config/GlobalConfig.java index ca04a41c..06466f41 100644 --- a/easy-es-core/src/main/java/cn/easyes/core/config/GlobalConfig.java +++ b/easy-es-core/src/main/java/cn/easyes/core/config/GlobalConfig.java @@ -79,10 +79,6 @@ public class GlobalConfig { * data refresh policy 数据刷新策略,默认为NONE */ private RefreshPolicy refreshPolicy = RefreshPolicy.NONE; - /** - * must convert to filter must by default, must 条件转filter 默认不转换 - */ - private boolean enableMust2Filter = false; /** * Batch update threshold 10000 by default 批量更新阈值 默认值为1万 */ diff --git a/easy-es-sample/src/main/resources/application.yml b/easy-es-sample/src/main/resources/application.yml index d06c2354..11120b89 100644 --- a/easy-es-sample/src/main/resources/application.yml +++ b/easy-es-sample/src/main/resources/application.yml @@ -15,5 +15,4 @@ easy-es: id-type: customize field-strategy: not_empty refresh-policy: immediate - enable-track-total-hits: true - enable-must2-filter: false + enable-track-total-hits: true \ No newline at end of file diff --git a/easy-es-test/src/test/java/cn/easyes/test/all/AllTest.java b/easy-es-test/src/test/java/cn/easyes/test/all/AllTest.java index 5c28bd21..e1da3133 100644 --- a/easy-es-test/src/test/java/cn/easyes/test/all/AllTest.java +++ b/easy-es-test/src/test/java/cn/easyes/test/all/AllTest.java @@ -800,24 +800,23 @@ public class AllTest { @Test @Order(21) public void testDSL(){ - // 设置检索条件 + // SQL写法 + // where business_type = 1 and (state = 9 or (state = 8 and bidding_sign = 1)) or business_type = 2 and state in (2,3) + + // RestHighLevelClient写法 List values = Arrays.asList(2,3); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.must(QueryBuilders.termQuery("business_type",1)); boolQueryBuilder.must(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("state",9)) .should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("state",8)).must(QueryBuilders.termQuery("bidding_sign",1)))); boolQueryBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("business_type",2)).must(QueryBuilders.termsQuery("state",values))); - System.out.println(boolQueryBuilder); - System.out.println(); - + // MP及EE写法 LambdaEsQueryWrapper wrapper = new LambdaEsQueryWrapper<>(); wrapper.eq("business_type",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); } diff --git a/easy-es-test/src/test/resources/application.yml b/easy-es-test/src/test/resources/application.yml index c674bbf3..45f8fcac 100644 --- a/easy-es-test/src/test/resources/application.yml +++ b/easy-es-test/src/test/resources/application.yml @@ -16,7 +16,6 @@ easy-es: field-strategy: not_empty refresh-policy: immediate enable-track-total-hits: true - enable-must2-filter: false #logging: # level: # tracer: trace \ No newline at end of file