This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 070f42c463 [Enhancement](Es): Support config like whether push down to es (#16800) 070f42c463 is described below commit 070f42c4639caa0d62053f085009686e50f4a146 Author: Stalary <stal...@163.com> AuthorDate: Fri Feb 17 21:56:11 2023 +0800 [Enhancement](Es): Support config like whether push down to es (#16800) Support config like whether push down to es and refactor some code Like transform to wildcard query and push down to es, this increases the cpu consumption of the es, I add a switch control it. --- docs/en/docs/lakehouse/multi-catalog/es.md | 19 +- docs/zh-CN/docs/lakehouse/multi-catalog/es.md | 19 +- .../main/java/org/apache/doris/catalog/Env.java | 3 +- .../java/org/apache/doris/catalog/EsResource.java | 7 + .../java/org/apache/doris/catalog/EsTable.java | 12 + .../doris/catalog/external/EsExternalTable.java | 1 + .../apache/doris/datasource/EsExternalCatalog.java | 5 + .../doris/external/elasticsearch/EsUtil.java | 203 --------------- .../external/elasticsearch/QueryBuilders.java | 280 ++++++++++++++++++++- .../java/org/apache/doris/planner/EsScanNode.java | 5 +- .../doris/external/elasticsearch/EsUtilTest.java | 89 +++---- 11 files changed, 367 insertions(+), 276 deletions(-) diff --git a/docs/en/docs/lakehouse/multi-catalog/es.md b/docs/en/docs/lakehouse/multi-catalog/es.md index 0ad296899b..f44dc9cb62 100644 --- a/docs/en/docs/lakehouse/multi-catalog/es.md +++ b/docs/en/docs/lakehouse/multi-catalog/es.md @@ -50,16 +50,17 @@ After switching to the ES Catalog, you will be in the `dafault_db` so you don't ### Parameter Description -| Parameter | Required or Not | Default Value | Description | -| ----------------- | --------------- | ------------- | ------------------------------------------------------------ | -| `hosts` | Yes | | ES address, can be one or multiple addresses, or the load balancer address of ES | -| `user` | No | Empty | ES username | -| `password` | No | Empty | Password of the corresponding user | -| `doc_value_scan` | No | true | Whether to obtain value of the target field by ES/Lucene columnar storage | -| `keyword_sniff` | No | true | Whether to sniff the text.fields in ES based on keyword; If this is set to false, the system will perform matching after tokenization. | +| Parameter | Required or Not | Default Value | Description | +| ----------------- | --------------- | ------------- |---------------------------------------------------------------------------------------------------------------------------------------------------| +| `hosts` | Yes | | ES address, can be one or multiple addresses, or the load balancer address of ES | +| `user` | No | Empty | ES username | +| `password` | No | Empty | Password of the corresponding user | +| `doc_value_scan` | No | true | Whether to obtain value of the target field by ES/Lucene columnar storage | +| `keyword_sniff` | No | true | Whether to sniff the text.fields in ES based on keyword; If this is set to false, the system will perform matching after tokenization. | | `nodes_discovery` | No | true | Whether to enable ES node discovery, set to true by default; set to false in network isolation environments and only connected to specified nodes | -| `ssl` | No | false | Whether to enable HTTPS access mode for ES, currently follows a "Trust All" method in FE/BE | -| `mapping_es_id` | No | false | Whether to map the `_id` field in the ES index | +| `ssl` | No | false | Whether to enable HTTPS access mode for ES, currently follows a "Trust All" method in FE/BE | +| `mapping_es_id` | No | false | Whether to map the `_id` field in the ES index | +| `like_push_down` | No | true | Whether to transform like to wildcard push down to es, this increases the cpu consumption of the es. | > 1. In terms of authentication, only HTTP Basic authentication is supported > and it requires the user to have read privilege for the index and paths > including `/_cluster/state/` and `_nodes/http` ; if you have not enabled > security authentication for the cluster, you don't need to set the `user` > and `password`. > diff --git a/docs/zh-CN/docs/lakehouse/multi-catalog/es.md b/docs/zh-CN/docs/lakehouse/multi-catalog/es.md index 68fea116ba..c6225d41b0 100644 --- a/docs/zh-CN/docs/lakehouse/multi-catalog/es.md +++ b/docs/zh-CN/docs/lakehouse/multi-catalog/es.md @@ -50,16 +50,17 @@ CREATE CATALOG es PROPERTIES ( ### 参数说明 -参数 | 是否必须 | 默认值 | 说明 ---- | --- | --- | --- -`hosts` | 是 | | ES 地址,可以是一个或多个,也可以是 ES 的负载均衡地址 | -`user` | 否 | 空 | ES 用户名 | -`password` | 否 | 空 | 对应用户的密码信息 | -`doc_value_scan` | 否 | true | 是否开启通过 ES/Lucene 列式存储获取查询字段的值 | +参数 | 是否必须 | 默认值 | 说明 +--- | --- | --- |------------------------------------------------------------------------ +`hosts` | 是 | | ES 地址,可以是一个或多个,也可以是 ES 的负载均衡地址 | +`user` | 否 | 空 | ES 用户名 | +`password` | 否 | 空 | 对应用户的密码信息 | +`doc_value_scan` | 否 | true | 是否开启通过 ES/Lucene 列式存储获取查询字段的值 | `keyword_sniff` | 否 | true | 是否对 ES 中字符串分词类型 text.fields 进行探测,通过 keyword 进行查询。设置为 false 会按照分词后的内容匹配 | -`nodes_discovery` | 否 | true | 是否开启 ES 节点发现,默认为 true,在网络隔离环境下设置为 false,只连接指定节点 | -`ssl` | 否 | false | ES 是否开启 https 访问模式,目前在 fe/be 实现方式为信任所有 | -`mapping_es_id` | 否 | false | 是否映射 ES 索引中的 `_id` 字段 | +`nodes_discovery` | 否 | true | 是否开启 ES 节点发现,默认为 true,在网络隔离环境下设置为 false,只连接指定节点 | +`ssl` | 否 | false | ES 是否开启 https 访问模式,目前在 fe/be 实现方式为信任所有 | +`mapping_es_id` | 否 | false | 是否映射 ES 索引中的 `_id` 字段 | +`like_push_down` | 否 | true | 是否将 like 转化为 wildchard 下推到 ES,会增加 ES cpu 消耗 | > 1. 认证方式目前仅支持 Http Basic 认证,并且需要确保该用户有访问: `/_cluster/state/、_nodes/http` 等路径和 > index 的读权限; 集群未开启安全认证,用户名和密码不需要设置。 > diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java index 6e27a626f2..4e1f10dd3f 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java @@ -3042,7 +3042,8 @@ public class Env { sb.append("\"max_docvalue_fields\" = \"").append(esTable.getMaxDocValueFields()).append("\",\n"); sb.append("\"enable_keyword_sniff\" = \"").append(esTable.isEnableKeywordSniff()).append("\",\n"); sb.append("\"nodes_discovery\" = \"").append(esTable.isNodesDiscovery()).append("\",\n"); - sb.append("\"http_ssl_enabled\" = \"").append(esTable.isHttpSslEnabled()).append("\"\n"); + sb.append("\"http_ssl_enabled\" = \"").append(esTable.isHttpSslEnabled()).append("\",\n"); + sb.append("\"like_push_down\" = \"").append(esTable.isLikePushDown()).append("\"\n"); sb.append(")"); } else if (table.getType() == TableType.HIVE) { HiveTable hiveTable = (HiveTable) table; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/EsResource.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/EsResource.java index 012ad119e3..91cb4529ad 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/EsResource.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/EsResource.java @@ -60,6 +60,8 @@ public class EsResource extends Resource { public static final String NODES_DISCOVERY = "nodes_discovery"; public static final String HTTP_SSL_ENABLED = "http_ssl_enabled"; public static final String MAPPING_ES_ID = "mapping_es_id"; + + public static final String LIKE_PUSH_DOWN = "like_push_down"; public static final String QUERY_DSL = "query_dsl"; public static final String DOC_VALUE_SCAN_DEFAULT_VALUE = "true"; @@ -67,6 +69,8 @@ public class EsResource extends Resource { public static final String HTTP_SSL_ENABLED_DEFAULT_VALUE = "false"; public static final String NODES_DISCOVERY_DEFAULT_VALUE = "true"; public static final String MAPPING_ES_ID_DEFAULT_VALUE = "false"; + + public static final String LIKE_PUSH_DOWN_DEFAULT_VALUE = "true"; @SerializedName(value = "properties") private Map<String, String> properties; @@ -127,6 +131,9 @@ public class EsResource extends Resource { if (properties.containsKey(EsResource.MAPPING_ES_ID)) { EsUtil.getBoolean(properties, EsResource.MAPPING_ES_ID); } + if (properties.containsKey(EsResource.LIKE_PUSH_DOWN)) { + EsUtil.getBoolean(properties, EsResource.LIKE_PUSH_DOWN); + } } private Map<String, String> processCompatibleProperties(Map<String, String> props) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/EsTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/EsTable.java index a26a7db7f9..81000c69d1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/EsTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/EsTable.java @@ -87,10 +87,15 @@ public class EsTable extends Table { // would downgrade to extract value from `stored_fields` private int maxDocValueFields = DEFAULT_MAX_DOCVALUE_FIELDS; + // Whether to enable the discovery of es nodes, You can disable it if you are in network isolation private boolean nodesDiscovery = Boolean.parseBoolean(EsResource.NODES_DISCOVERY_DEFAULT_VALUE); + // Whether to use ssl call es, be and fe access through trust private boolean httpSslEnabled = Boolean.parseBoolean(EsResource.HTTP_SSL_ENABLED_DEFAULT_VALUE); + // Whether pushdown like expr, like will trans to wildcard query, consumes too many es cpu resources + private boolean likePushDown = Boolean.parseBoolean(EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE); + // tableContext is used for being convenient to persist some configuration parameters uniformly private Map<String, String> tableContext = new HashMap<>(); @@ -171,6 +176,10 @@ public class EsTable extends Table { httpSslEnabled = EsUtil.getBoolean(properties, EsResource.HTTP_SSL_ENABLED); } + if (properties.containsKey(EsResource.LIKE_PUSH_DOWN)) { + likePushDown = EsUtil.getBoolean(properties, EsResource.LIKE_PUSH_DOWN); + } + if (StringUtils.isNotBlank(properties.get(EsResource.TYPE))) { mappingType = properties.get(EsResource.TYPE).trim(); } @@ -197,6 +206,7 @@ public class EsTable extends Table { tableContext.put("maxDocValueFields", String.valueOf(maxDocValueFields)); tableContext.put(EsResource.NODES_DISCOVERY, String.valueOf(nodesDiscovery)); tableContext.put(EsResource.HTTP_SSL_ENABLED, String.valueOf(httpSslEnabled)); + tableContext.put(EsResource.LIKE_PUSH_DOWN, String.valueOf(likePushDown)); } @Override @@ -275,6 +285,8 @@ public class EsTable extends Table { EsResource.NODES_DISCOVERY_DEFAULT_VALUE)); httpSslEnabled = Boolean.parseBoolean(tableContext.getOrDefault(EsResource.HTTP_SSL_ENABLED, EsResource.HTTP_SSL_ENABLED_DEFAULT_VALUE)); + likePushDown = Boolean.parseBoolean(tableContext.getOrDefault(EsResource.LIKE_PUSH_DOWN, + EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE)); PartitionType partType = PartitionType.valueOf(Text.readString(in)); if (partType == PartitionType.UNPARTITIONED) { partitionInfo = SinglePartitionInfo.read(in); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/EsExternalTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/EsExternalTable.java index 4eab32b17a..290917e21c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/external/EsExternalTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/external/EsExternalTable.java @@ -96,6 +96,7 @@ public class EsExternalTable extends ExternalTable { esTable.setEnableKeywordSniff(esCatalog.enableKeywordSniff()); esTable.setNodesDiscovery(esCatalog.enableNodesDiscovery()); esTable.setHttpSslEnabled(esCatalog.enableSsl()); + esTable.setLikePushDown(esCatalog.enableLikePushDown()); esTable.setSeeds(esCatalog.getNodes()); esTable.setHosts(String.join(",", esCatalog.getNodes())); esTable.syncTableMetaData(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/EsExternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/EsExternalCatalog.java index 390963ae58..650e5374e5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/EsExternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/EsExternalCatalog.java @@ -106,6 +106,11 @@ public class EsExternalCatalog extends ExternalCatalog { EsResource.MAPPING_ES_ID_DEFAULT_VALUE)); } + public boolean enableLikePushDown() { + return Boolean.parseBoolean(catalogProperty.getOrDefault(EsResource.LIKE_PUSH_DOWN, + EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE)); + } + @Override protected void initLocalObjectsImpl() { esRestClient = new EsRestClient(getNodes(), getUsername(), getPassword(), enableSsl()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java b/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java index 2276356fa8..4dd1991853 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java @@ -17,32 +17,15 @@ package org.apache.doris.external.elasticsearch; -import org.apache.doris.analysis.BinaryPredicate; -import org.apache.doris.analysis.BoolLiteral; -import org.apache.doris.analysis.CastExpr; -import org.apache.doris.analysis.CompoundPredicate; -import org.apache.doris.analysis.DecimalLiteral; import org.apache.doris.analysis.DistributionDesc; -import org.apache.doris.analysis.Expr; -import org.apache.doris.analysis.FloatLiteral; -import org.apache.doris.analysis.FunctionCallExpr; -import org.apache.doris.analysis.InPredicate; -import org.apache.doris.analysis.IntLiteral; -import org.apache.doris.analysis.IsNullPredicate; -import org.apache.doris.analysis.LargeIntLiteral; -import org.apache.doris.analysis.LikePredicate; -import org.apache.doris.analysis.LikePredicate.Operator; import org.apache.doris.analysis.PartitionDesc; import org.apache.doris.analysis.RangePartitionDesc; -import org.apache.doris.analysis.SlotRef; import org.apache.doris.catalog.ArrayType; import org.apache.doris.catalog.Column; import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DdlException; -import org.apache.doris.external.elasticsearch.QueryBuilders.QueryBuilder; -import org.apache.doris.thrift.TExprOpcode; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -50,12 +33,10 @@ import org.json.simple.JSONObject; import org.json.simple.JSONValue; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * Util for ES, some static method. @@ -213,167 +194,6 @@ public class EsUtil { return properties; } - private static QueryBuilder toCompoundEsDsl(Expr expr, List<Expr> notPushDownList, - Map<String, String> fieldsContext) { - CompoundPredicate compoundPredicate = (CompoundPredicate) expr; - switch (compoundPredicate.getOp()) { - case AND: { - QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext); - QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), notPushDownList, fieldsContext); - if (left != null && right != null) { - return QueryBuilders.boolQuery().must(left).must(right); - } - return null; - } - case OR: { - int beforeSize = notPushDownList.size(); - QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext); - QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), notPushDownList, fieldsContext); - int afterSize = notPushDownList.size(); - if (left != null && right != null) { - return QueryBuilders.boolQuery().should(left).should(right); - } - // One 'or' association cannot be pushed down and the other cannot be pushed down - if (afterSize > beforeSize) { - if (left != null) { - // add right if right don't pushdown - notPushDownList.add(compoundPredicate.getChild(0)); - } else if (right != null) { - // add left if left don't pushdown - notPushDownList.add(compoundPredicate.getChild(1)); - } - } - return null; - } - case NOT: { - QueryBuilder child = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext); - if (child != null) { - return QueryBuilders.boolQuery().mustNot(child); - } - return null; - } - default: - return null; - } - } - - private static Expr exprWithoutCast(Expr expr) { - if (expr instanceof CastExpr) { - return exprWithoutCast(expr.getChild(0)); - } - return expr; - } - - public static QueryBuilder toEsDsl(Expr expr) { - return toEsDsl(expr, new ArrayList<>(), new HashMap<>()); - } - - /** - * Doris expr to es dsl. - **/ - public static QueryBuilder toEsDsl(Expr expr, List<Expr> notPushDownList, Map<String, String> fieldsContext) { - if (expr == null) { - return null; - } - // CompoundPredicate, `between` also converted to CompoundPredicate. - if (expr instanceof CompoundPredicate) { - return toCompoundEsDsl(expr, notPushDownList, fieldsContext); - } - TExprOpcode opCode = expr.getOpcode(); - String column; - Expr leftExpr = expr.getChild(0); - // Type transformed cast can not pushdown - if (leftExpr instanceof CastExpr) { - Expr withoutCastExpr = exprWithoutCast(leftExpr); - // pushdown col(float) >= 3 - if (withoutCastExpr.getType().equals(leftExpr.getType()) || (withoutCastExpr.getType().isFloatingPointType() - && leftExpr.getType().isFloatingPointType())) { - column = ((SlotRef) withoutCastExpr).getColumnName(); - } else { - notPushDownList.add(expr); - return null; - } - } else if (leftExpr instanceof SlotRef) { - column = ((SlotRef) leftExpr).getColumnName(); - } else { - notPushDownList.add(expr); - return null; - } - // Replace col with col.keyword if mapping exist. - column = fieldsContext.getOrDefault(column, column); - if (expr instanceof BinaryPredicate) { - Object value = toDorisLiteral(expr.getChild(1)); - switch (opCode) { - case EQ: - case EQ_FOR_NULL: - return QueryBuilders.termQuery(column, value); - case NE: - return QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(column, value)); - case GE: - return QueryBuilders.rangeQuery(column).gte(value); - case GT: - return QueryBuilders.rangeQuery(column).gt(value); - case LE: - return QueryBuilders.rangeQuery(column).lte(value); - case LT: - return QueryBuilders.rangeQuery(column).lt(value); - default: - return null; - } - } - if (expr instanceof IsNullPredicate) { - IsNullPredicate isNullPredicate = (IsNullPredicate) expr; - if (isNullPredicate.isNotNull()) { - return QueryBuilders.existsQuery(column); - } - return QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(column)); - } - if (expr instanceof LikePredicate) { - LikePredicate likePredicate = (LikePredicate) expr; - if (likePredicate.getOp().equals(Operator.LIKE)) { - char[] chars = likePredicate.getChild(1).getStringValue().toCharArray(); - // example of translation : - // abc_123 ===> abc?123 - // abc%ykz ===> abc*123 - // %abc123 ===> *abc123 - // _abc123 ===> ?abc123 - // \\_abc1 ===> \\_abc1 - // abc\\_123 ===> abc\\_123 - // abc\\%123 ===> abc\\%123 - // NOTE. user must input sql like 'abc\\_123' or 'abc\\%ykz' - for (int i = 0; i < chars.length; i++) { - if (chars[i] == '_' || chars[i] == '%') { - if (i == 0) { - chars[i] = (chars[i] == '_') ? '?' : '*'; - } else if (chars[i - 1] != '\\') { - chars[i] = (chars[i] == '_') ? '?' : '*'; - } - } - } - return QueryBuilders.wildcardQuery(column, new String(chars)); - } else { - return QueryBuilders.wildcardQuery(column, likePredicate.getChild(1).getStringValue()); - } - } - if (expr instanceof InPredicate) { - InPredicate inPredicate = (InPredicate) expr; - List<Object> values = inPredicate.getListChildren().stream().map(EsUtil::toDorisLiteral) - .collect(Collectors.toList()); - if (inPredicate.isNotIn()) { - return QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(column, values)); - } - return QueryBuilders.termsQuery(column, values); - } - if (expr instanceof FunctionCallExpr) { - FunctionCallExpr functionCallExpr = (FunctionCallExpr) expr; - if ("esquery".equals(functionCallExpr.getFnName().getFunction())) { - String stringValue = functionCallExpr.getChild(1).getStringValue(); - return new QueryBuilders.EsQueryBuilder(stringValue); - } - } - return null; - } - /** * Generate columns from ES Cluster. @@ -458,28 +278,5 @@ public class EsUtil { } } - private static Object toDorisLiteral(Expr expr) { - if (!expr.isLiteral()) { - return null; - } - if (expr instanceof BoolLiteral) { - BoolLiteral boolLiteral = (BoolLiteral) expr; - return boolLiteral.getValue(); - } else if (expr instanceof DecimalLiteral) { - DecimalLiteral decimalLiteral = (DecimalLiteral) expr; - return decimalLiteral.getValue(); - } else if (expr instanceof FloatLiteral) { - FloatLiteral floatLiteral = (FloatLiteral) expr; - return floatLiteral.getValue(); - } else if (expr instanceof IntLiteral) { - IntLiteral intLiteral = (IntLiteral) expr; - return intLiteral.getValue(); - } else if (expr instanceof LargeIntLiteral) { - LargeIntLiteral largeIntLiteral = (LargeIntLiteral) expr; - return largeIntLiteral.getLongValue(); - } - return expr.getStringValue(); - } - } diff --git a/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java b/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java index 3dd800cb91..cc269a452a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java +++ b/fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java @@ -17,19 +17,42 @@ package org.apache.doris.external.elasticsearch; +import org.apache.doris.analysis.BinaryPredicate; +import org.apache.doris.analysis.BoolLiteral; +import org.apache.doris.analysis.CastExpr; +import org.apache.doris.analysis.CompoundPredicate; +import org.apache.doris.analysis.DecimalLiteral; +import org.apache.doris.analysis.Expr; +import org.apache.doris.analysis.FloatLiteral; +import org.apache.doris.analysis.FunctionCallExpr; +import org.apache.doris.analysis.InPredicate; +import org.apache.doris.analysis.IntLiteral; +import org.apache.doris.analysis.IsNullPredicate; +import org.apache.doris.analysis.LargeIntLiteral; +import org.apache.doris.analysis.LikePredicate; +import org.apache.doris.analysis.LikePredicate.Operator; +import org.apache.doris.analysis.SlotRef; +import org.apache.doris.catalog.EsResource; +import org.apache.doris.thrift.TExprOpcode; + import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Builder; +import lombok.Data; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.stream.Collectors; /** @@ -38,6 +61,233 @@ import java.util.Objects; */ public final class QueryBuilders { + /** + * Generate dsl from compound expr. + **/ + private static QueryBuilder toCompoundEsDsl(Expr expr, List<Expr> notPushDownList, + Map<String, String> fieldsContext, BuilderOptions builderOptions) { + CompoundPredicate compoundPredicate = (CompoundPredicate) expr; + switch (compoundPredicate.getOp()) { + case AND: { + QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext, + builderOptions); + QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), notPushDownList, fieldsContext, + builderOptions); + if (left != null && right != null) { + return QueryBuilders.boolQuery().must(left).must(right); + } + return null; + } + case OR: { + int beforeSize = notPushDownList.size(); + QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext, + builderOptions); + QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), notPushDownList, fieldsContext, + builderOptions); + int afterSize = notPushDownList.size(); + if (left != null && right != null) { + return QueryBuilders.boolQuery().should(left).should(right); + } + // One 'or' association cannot be pushed down and the other cannot be pushed down + if (afterSize > beforeSize) { + notPushDownList.add(compoundPredicate); + } + return null; + } + case NOT: { + QueryBuilder child = toEsDsl(compoundPredicate.getChild(0), notPushDownList, fieldsContext, + builderOptions); + if (child != null) { + return QueryBuilders.boolQuery().mustNot(child); + } + return null; + } + default: + return null; + } + } + + /** + * Get the expr inside the cast. + **/ + private static Expr exprWithoutCast(Expr expr) { + if (expr instanceof CastExpr) { + return exprWithoutCast(expr.getChild(0)); + } + return expr; + } + + public static QueryBuilder toEsDsl(Expr expr) { + return toEsDsl(expr, new ArrayList<>(), new HashMap<>(), + BuilderOptions.builder().likePushDown(Boolean.parseBoolean(EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE)) + .build()); + } + + private static QueryBuilder parseBinaryPredicate(Expr expr, TExprOpcode opCode, String column) { + Object value = toDorisLiteral(expr.getChild(1)); + switch (opCode) { + case EQ: + case EQ_FOR_NULL: + return QueryBuilders.termQuery(column, value); + case NE: + return QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(column, value)); + case GE: + return QueryBuilders.rangeQuery(column).gte(value); + case GT: + return QueryBuilders.rangeQuery(column).gt(value); + case LE: + return QueryBuilders.rangeQuery(column).lte(value); + case LT: + return QueryBuilders.rangeQuery(column).lt(value); + default: + return null; + } + } + + private static QueryBuilder parseIsNullPredicate(Expr expr, String column) { + IsNullPredicate isNullPredicate = (IsNullPredicate) expr; + if (isNullPredicate.isNotNull()) { + return QueryBuilders.existsQuery(column); + } + return QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(column)); + } + + private static QueryBuilder parseLikePredicate(Expr expr, String column) { + LikePredicate likePredicate = (LikePredicate) expr; + if (likePredicate.getOp().equals(Operator.LIKE)) { + char[] chars = likePredicate.getChild(1).getStringValue().toCharArray(); + // example of translation : + // abc_123 ===> abc?123 + // abc%ykz ===> abc*123 + // %abc123 ===> *abc123 + // _abc123 ===> ?abc123 + // \\_abc1 ===> \\_abc1 + // abc\\_123 ===> abc\\_123 + // abc\\%123 ===> abc\\%123 + // NOTE. user must input sql like 'abc\\_123' or 'abc\\%ykz' + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '_' || chars[i] == '%') { + if (i == 0) { + chars[i] = (chars[i] == '_') ? '?' : '*'; + } else if (chars[i - 1] != '\\') { + chars[i] = (chars[i] == '_') ? '?' : '*'; + } + } + } + return QueryBuilders.wildcardQuery(column, new String(chars)); + } else { + return QueryBuilders.wildcardQuery(column, likePredicate.getChild(1).getStringValue()); + } + } + + private static QueryBuilder parseInPredicate(Expr expr, String column) { + InPredicate inPredicate = (InPredicate) expr; + List<Object> values = inPredicate.getListChildren().stream().map(QueryBuilders::toDorisLiteral) + .collect(Collectors.toList()); + if (inPredicate.isNotIn()) { + return QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(column, values)); + } + return QueryBuilders.termsQuery(column, values); + } + + private static QueryBuilder parseFunctionCallExpr(Expr expr) { + // esquery(k1, '{ + // "match_phrase": { + // "k1": "doris on es" + // } + // }'); + // The first child k1 compatible with expr syntax + FunctionCallExpr functionCallExpr = (FunctionCallExpr) expr; + if ("esquery".equals(functionCallExpr.getFnName().getFunction())) { + String stringValue = functionCallExpr.getChild(1).getStringValue(); + return new QueryBuilders.EsQueryBuilder(stringValue); + } + return null; + } + + /** + * Doris expr to es dsl. + **/ + public static QueryBuilder toEsDsl(Expr expr, List<Expr> notPushDownList, Map<String, String> fieldsContext, + BuilderOptions builderOptions) { + if (expr == null) { + return null; + } + // CompoundPredicate, `between` also converted to CompoundPredicate. + if (expr instanceof CompoundPredicate) { + return toCompoundEsDsl(expr, notPushDownList, fieldsContext, builderOptions); + } + TExprOpcode opCode = expr.getOpcode(); + String column; + Expr leftExpr = expr.getChild(0); + // Type transformed cast can not pushdown + if (leftExpr instanceof CastExpr) { + Expr withoutCastExpr = exprWithoutCast(leftExpr); + // pushdown col(float) >= 3 + if (withoutCastExpr.getType().equals(leftExpr.getType()) || (withoutCastExpr.getType().isFloatingPointType() + && leftExpr.getType().isFloatingPointType())) { + column = ((SlotRef) withoutCastExpr).getColumnName(); + } else { + notPushDownList.add(expr); + return null; + } + } else if (leftExpr instanceof SlotRef) { + column = ((SlotRef) leftExpr).getColumnName(); + } else { + notPushDownList.add(expr); + return null; + } + // Replace col with col.keyword if mapping exist. + column = fieldsContext.getOrDefault(column, column); + if (expr instanceof BinaryPredicate) { + return parseBinaryPredicate(expr, opCode, column); + } + if (expr instanceof IsNullPredicate) { + return parseIsNullPredicate(expr, column); + } + if (expr instanceof LikePredicate) { + if (!builderOptions.isLikePushDown()) { + notPushDownList.add(expr); + return null; + } else { + return parseLikePredicate(expr, column); + } + } + if (expr instanceof InPredicate) { + return parseInPredicate(expr, column); + } + if (expr instanceof FunctionCallExpr) { + return parseFunctionCallExpr(expr); + } + return null; + } + + /** + * Expr trans to doris literal. + **/ + private static Object toDorisLiteral(Expr expr) { + if (!expr.isLiteral()) { + return null; + } + if (expr instanceof BoolLiteral) { + BoolLiteral boolLiteral = (BoolLiteral) expr; + return boolLiteral.getValue(); + } else if (expr instanceof DecimalLiteral) { + DecimalLiteral decimalLiteral = (DecimalLiteral) expr; + return decimalLiteral.getValue(); + } else if (expr instanceof FloatLiteral) { + FloatLiteral floatLiteral = (FloatLiteral) expr; + return floatLiteral.getValue(); + } else if (expr instanceof IntLiteral) { + IntLiteral intLiteral = (IntLiteral) expr; + return intLiteral.getValue(); + } else if (expr instanceof LargeIntLiteral) { + LargeIntLiteral largeIntLiteral = (LargeIntLiteral) expr; + return largeIntLiteral.getLongValue(); + } + return expr.getStringValue(); + } + /** * A query that matches on all documents. */ @@ -48,7 +298,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, String value) { @@ -58,7 +308,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, int value) { @@ -68,7 +318,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, long value) { @@ -78,7 +328,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, float value) { @@ -88,7 +338,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, double value) { @@ -98,7 +348,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, boolean value) { @@ -108,7 +358,7 @@ public final class QueryBuilders { /** * A Query that matches documents containing a term. * - * @param name The name of the field + * @param name The name of the field * @param value The value of the term */ public static TermQueryBuilder termQuery(String name, Object value) { @@ -123,7 +373,7 @@ public final class QueryBuilders { * a Wildcard term should not start with one of the wildcards {@code *} or * {@code ?}. * - * @param name The field name + * @param name The field name * @param query The wildcard query string */ public static WildcardQueryBuilder wildcardQuery(String name, String query) { @@ -141,7 +391,7 @@ public final class QueryBuilders { /** * A filter for a field based on several terms matching on any of them. * - * @param name The field name + * @param name The field name * @param values The terms */ public static TermsQueryBuilder termsQuery(String name, Iterable<?> values) { @@ -166,6 +416,16 @@ public final class QueryBuilders { return new RangeQueryBuilder(name); } + /** + * Used to pass some parameters to generate the dsl + **/ + @Builder + @Data + public static class BuilderOptions { + + private boolean likePushDown; + } + /** * Base class to build various ES queries @@ -505,7 +765,7 @@ public final class QueryBuilders { /** * Write (scalar) value (string, number, boolean or null) to json format * - * @param out source target + * @param out source target * @param value value to write * @throws IOException if error */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/EsScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/EsScanNode.java index 5a6667eb71..7c9aae4a8d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/EsScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/EsScanNode.java @@ -33,9 +33,9 @@ import org.apache.doris.common.UserException; import org.apache.doris.external.elasticsearch.EsShardPartitions; import org.apache.doris.external.elasticsearch.EsShardRouting; import org.apache.doris.external.elasticsearch.EsTablePartitions; -import org.apache.doris.external.elasticsearch.EsUtil; import org.apache.doris.external.elasticsearch.QueryBuilders; import org.apache.doris.external.elasticsearch.QueryBuilders.BoolQueryBuilder; +import org.apache.doris.external.elasticsearch.QueryBuilders.BuilderOptions; import org.apache.doris.external.elasticsearch.QueryBuilders.QueryBuilder; import org.apache.doris.statistics.StatisticalType; import org.apache.doris.system.Backend; @@ -362,7 +362,8 @@ public class EsScanNode extends ScanNode { BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); List<Expr> notPushDownList = new ArrayList<>(); for (Expr expr : conjuncts) { - QueryBuilder queryBuilder = EsUtil.toEsDsl(expr, notPushDownList, fieldsContext); + QueryBuilder queryBuilder = QueryBuilders.toEsDsl(expr, notPushDownList, fieldsContext, + BuilderOptions.builder().likePushDown(table.isLikePushDown()).build()); if (queryBuilder != null) { hasFilter = true; boolQueryBuilder.must(queryBuilder); diff --git a/fe/fe-core/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java b/fe/fe-core/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java index 7783b4d437..a744b0fba0 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java @@ -31,10 +31,12 @@ import org.apache.doris.analysis.LikePredicate; import org.apache.doris.analysis.SlotRef; import org.apache.doris.analysis.StringLiteral; import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.EsResource; import org.apache.doris.catalog.EsTable; import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.catalog.Type; import org.apache.doris.common.ExceptionChecker; +import org.apache.doris.external.elasticsearch.QueryBuilders.BuilderOptions; import mockit.Expectations; import mockit.Injectable; @@ -179,13 +181,14 @@ public class EsUtilTest extends EsTestCase { Expr ltExpr = new BinaryPredicate(Operator.LT, k1, intLiteral); Expr gtExpr = new BinaryPredicate(Operator.GT, k1, intLiteral); Expr efnExpr = new BinaryPredicate(Operator.EQ_FOR_NULL, new SlotRef(null, "k1"), new IntLiteral(3)); - Assertions.assertEquals("{\"term\":{\"k1\":3}}", EsUtil.toEsDsl(eqExpr).toJson()); - Assertions.assertEquals("{\"bool\":{\"must_not\":{\"term\":{\"k1\":3}}}}", EsUtil.toEsDsl(neExpr).toJson()); - Assertions.assertEquals("{\"range\":{\"k1\":{\"lte\":3}}}", EsUtil.toEsDsl(leExpr).toJson()); - Assertions.assertEquals("{\"range\":{\"k1\":{\"gte\":3}}}", EsUtil.toEsDsl(geExpr).toJson()); - Assertions.assertEquals("{\"range\":{\"k1\":{\"lt\":3}}}", EsUtil.toEsDsl(ltExpr).toJson()); - Assertions.assertEquals("{\"range\":{\"k1\":{\"gt\":3}}}", EsUtil.toEsDsl(gtExpr).toJson()); - Assertions.assertEquals("{\"term\":{\"k1\":3}}", EsUtil.toEsDsl(efnExpr).toJson()); + Assertions.assertEquals("{\"term\":{\"k1\":3}}", QueryBuilders.toEsDsl(eqExpr).toJson()); + Assertions.assertEquals("{\"bool\":{\"must_not\":{\"term\":{\"k1\":3}}}}", + QueryBuilders.toEsDsl(neExpr).toJson()); + Assertions.assertEquals("{\"range\":{\"k1\":{\"lte\":3}}}", QueryBuilders.toEsDsl(leExpr).toJson()); + Assertions.assertEquals("{\"range\":{\"k1\":{\"gte\":3}}}", QueryBuilders.toEsDsl(geExpr).toJson()); + Assertions.assertEquals("{\"range\":{\"k1\":{\"lt\":3}}}", QueryBuilders.toEsDsl(ltExpr).toJson()); + Assertions.assertEquals("{\"range\":{\"k1\":{\"gt\":3}}}", QueryBuilders.toEsDsl(gtExpr).toJson()); + Assertions.assertEquals("{\"term\":{\"k1\":3}}", QueryBuilders.toEsDsl(efnExpr).toJson()); } @Test @@ -202,11 +205,11 @@ public class EsUtilTest extends EsTestCase { binaryPredicate2); CompoundPredicate notPredicate = new CompoundPredicate(CompoundPredicate.Operator.NOT, binaryPredicate1, null); Assertions.assertEquals("{\"bool\":{\"must\":[{\"term\":{\"k1\":3}},{\"range\":{\"k2\":{\"gt\":5}}}]}}", - EsUtil.toEsDsl(andPredicate).toJson()); + QueryBuilders.toEsDsl(andPredicate).toJson()); Assertions.assertEquals("{\"bool\":{\"should\":[{\"term\":{\"k1\":3}},{\"range\":{\"k2\":{\"gt\":5}}}]}}", - EsUtil.toEsDsl(orPredicate).toJson()); + QueryBuilders.toEsDsl(orPredicate).toJson()); Assertions.assertEquals("{\"bool\":{\"must_not\":{\"term\":{\"k1\":3}}}}", - EsUtil.toEsDsl(notPredicate).toJson()); + QueryBuilders.toEsDsl(notPredicate).toJson()); } @Test @@ -215,8 +218,8 @@ public class EsUtilTest extends EsTestCase { IsNullPredicate isNullPredicate = new IsNullPredicate(k1, false); IsNullPredicate isNotNullPredicate = new IsNullPredicate(k1, true); Assertions.assertEquals("{\"bool\":{\"must_not\":{\"exists\":{\"field\":\"k1\"}}}}", - EsUtil.toEsDsl(isNullPredicate).toJson()); - Assertions.assertEquals("{\"exists\":{\"field\":\"k1\"}}", EsUtil.toEsDsl(isNotNullPredicate).toJson()); + QueryBuilders.toEsDsl(isNullPredicate).toJson()); + Assertions.assertEquals("{\"exists\":{\"field\":\"k1\"}}", QueryBuilders.toEsDsl(isNotNullPredicate).toJson()); } @Test @@ -228,9 +231,12 @@ public class EsUtilTest extends EsTestCase { LikePredicate likePredicate1 = new LikePredicate(LikePredicate.Operator.LIKE, k1, stringLiteral1); LikePredicate regexPredicate = new LikePredicate(LikePredicate.Operator.REGEXP, k1, stringLiteral2); LikePredicate likePredicate2 = new LikePredicate(LikePredicate.Operator.LIKE, k1, stringLiteral3); - Assertions.assertEquals("{\"wildcard\":{\"k1\":\"*1*\"}}", EsUtil.toEsDsl(likePredicate1).toJson()); - Assertions.assertEquals("{\"wildcard\":{\"k1\":\"*1*\"}}", EsUtil.toEsDsl(regexPredicate).toJson()); - Assertions.assertEquals("{\"wildcard\":{\"k1\":\"1?2\"}}", EsUtil.toEsDsl(likePredicate2).toJson()); + Assertions.assertEquals("{\"wildcard\":{\"k1\":\"*1*\"}}", QueryBuilders.toEsDsl(likePredicate1).toJson()); + Assertions.assertEquals("{\"wildcard\":{\"k1\":\"*1*\"}}", QueryBuilders.toEsDsl(regexPredicate).toJson()); + Assertions.assertEquals("{\"wildcard\":{\"k1\":\"1?2\"}}", QueryBuilders.toEsDsl(likePredicate2).toJson()); + List<Expr> notPushDownList = new ArrayList<>(); + Assertions.assertNull(QueryBuilders.toEsDsl(likePredicate2, notPushDownList, new HashMap<>(), BuilderOptions.builder().likePushDown(false).build())); + Assertions.assertFalse(notPushDownList.isEmpty()); } @Test @@ -243,9 +249,9 @@ public class EsUtilTest extends EsTestCase { intLiterals.add(intLiteral2); InPredicate isInPredicate = new InPredicate(k1, intLiterals, false); InPredicate isNotInPredicate = new InPredicate(k1, intLiterals, true); - Assertions.assertEquals("{\"terms\":{\"k1\":[3,5]}}", EsUtil.toEsDsl(isInPredicate).toJson()); + Assertions.assertEquals("{\"terms\":{\"k1\":[3,5]}}", QueryBuilders.toEsDsl(isInPredicate).toJson()); Assertions.assertEquals("{\"bool\":{\"must_not\":{\"terms\":{\"k1\":[3,5]}}}}", - EsUtil.toEsDsl(isNotInPredicate).toJson()); + QueryBuilders.toEsDsl(isNotInPredicate).toJson()); } @Test @@ -257,7 +263,7 @@ public class EsUtilTest extends EsTestCase { exprs.add(k1); exprs.add(stringLiteral); FunctionCallExpr functionCallExpr = new FunctionCallExpr("esquery", exprs); - Assertions.assertEquals(str, EsUtil.toEsDsl(functionCallExpr).toJson()); + Assertions.assertEquals(str, QueryBuilders.toEsDsl(functionCallExpr).toJson()); SlotRef k2 = new SlotRef(null, "k2"); IntLiteral intLiteral = new IntLiteral(5); @@ -266,7 +272,7 @@ public class EsUtilTest extends EsTestCase { functionCallExpr); Assertions.assertEquals( "{\"bool\":{\"must\":[{\"term\":{\"k2\":5}},{\"bool\":{\"must_not\":{\"terms\":{\"k1\":[3,5]}}}}]}}", - EsUtil.toEsDsl(compoundPredicate).toJson()); + QueryBuilders.toEsDsl(compoundPredicate).toJson()); } @Test @@ -276,7 +282,9 @@ public class EsUtilTest extends EsTestCase { BinaryPredicate castPredicate = new BinaryPredicate(Operator.EQ, castExpr, new IntLiteral(3)); List<Expr> notPushDownList = new ArrayList<>(); Map<String, String> fieldsContext = new HashMap<>(); - Assertions.assertNull(EsUtil.toEsDsl(castPredicate, notPushDownList, fieldsContext)); + BuilderOptions builderOptions = BuilderOptions.builder() + .likePushDown(Boolean.parseBoolean(EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE)).build(); + Assertions.assertNull(QueryBuilders.toEsDsl(castPredicate, notPushDownList, fieldsContext, builderOptions)); Assertions.assertEquals(1, notPushDownList.size()); SlotRef k2 = new SlotRef(null, "k2"); @@ -284,7 +292,8 @@ public class EsUtilTest extends EsTestCase { BinaryPredicate eqPredicate = new BinaryPredicate(Operator.EQ, k2, intLiteral); CompoundPredicate compoundPredicate = new CompoundPredicate(CompoundPredicate.Operator.OR, castPredicate, eqPredicate); - EsUtil.toEsDsl(compoundPredicate, notPushDownList, fieldsContext); + + QueryBuilders.toEsDsl(compoundPredicate, notPushDownList, fieldsContext, builderOptions); Assertions.assertEquals(3, notPushDownList.size()); SlotRef k3 = new SlotRef(null, "k3"); @@ -292,7 +301,7 @@ public class EsUtilTest extends EsTestCase { CastExpr castDoubleExpr = new CastExpr(Type.DOUBLE, k3); BinaryPredicate castDoublePredicate = new BinaryPredicate(Operator.GE, castDoubleExpr, new FloatLiteral(3.0, Type.DOUBLE)); - EsUtil.toEsDsl(castDoublePredicate, notPushDownList, fieldsContext); + QueryBuilders.toEsDsl(castDoublePredicate, notPushDownList, fieldsContext, builderOptions); Assertions.assertEquals(3, notPushDownList.size()); } @@ -317,22 +326,20 @@ public class EsUtilTest extends EsTestCase { + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testIndex.toJSONString()); - JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es6_dynamic_templates_mapping.json"), - "doc"); + JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", + loadJsonFromFile("data/es/es6_dynamic_templates_mapping.json"), "doc"); Assertions.assertEquals("{\"test4\":{\"type\":\"date\"},\"test2\":{\"type\":\"text\"," - + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," - + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", + + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testDynamicTemplates.toJSONString()); expectedEx.expect(DorisEsException.class); expectedEx.expectMessage("Do not support index without explicit mapping."); - EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es6_only_dynamic_templates_mapping.json"), - "doc"); + EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es6_only_dynamic_templates_mapping.json"), "doc"); expectedEx.expect(DorisEsException.class); expectedEx.expectMessage("Do not support index without explicit mapping."); - EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es6_only_dynamic_templates_mapping.json"), - null); + EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es6_only_dynamic_templates_mapping.json"), null); } @Test @@ -356,17 +363,16 @@ public class EsUtilTest extends EsTestCase { + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testIndex.toJSONString()); - JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es7_dynamic_templates_mapping.json"), - null); + JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", + loadJsonFromFile("data/es/es7_dynamic_templates_mapping.json"), null); Assertions.assertEquals("{\"test4\":{\"type\":\"date\"},\"test2\":{\"type\":\"text\"," - + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," - + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", + + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testDynamicTemplates.toJSONString()); expectedEx.expect(DorisEsException.class); expectedEx.expectMessage("Do not support index without explicit mapping."); - EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es7_only_dynamic_templates_mapping.json"), - null); + EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es7_only_dynamic_templates_mapping.json"), null); } @Test @@ -390,17 +396,16 @@ public class EsUtilTest extends EsTestCase { + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testIndex.toJSONString()); - JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es8_dynamic_templates_mapping.json"), - "doc"); + JSONObject testDynamicTemplates = EsUtil.getMappingProps("test", + loadJsonFromFile("data/es/es8_dynamic_templates_mapping.json"), "doc"); Assertions.assertEquals("{\"test4\":{\"type\":\"date\"},\"test2\":{\"type\":\"text\"," - + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," - + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", + + "\"fields\":{\"keyword\":{\"ignore_above\":256,\"type\":\"keyword\"}}}," + + "\"test3\":{\"type\":\"double\"},\"test1\":{\"type\":\"keyword\"}}", testDynamicTemplates.toJSONString()); expectedEx.expect(DorisEsException.class); expectedEx.expectMessage("Do not support index without explicit mapping."); - EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es8_only_dynamic_templates_mapping.json"), - "doc"); + EsUtil.getMappingProps("test", loadJsonFromFile("data/es/es8_only_dynamic_templates_mapping.json"), "doc"); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org