You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by ka...@apache.org on 2020/06/09 08:45:28 UTC

[incubator-doris] branch master updated: [Doris On ES] [1/3] Add ES QueryBuilders for debug mode (#3774)

This is an automated email from the ASF dual-hosted git repository.

kangkaisen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new acd7a58  [Doris On ES] [1/3] Add ES QueryBuilders for debug mode (#3774)
acd7a58 is described below

commit acd7a5887588a7b438dbb478ececad99a08682b0
Author: Yunfeng,Wu <wu...@baidu.com>
AuthorDate: Tue Jun 9 16:45:16 2020 +0800

    [Doris On ES] [1/3] Add ES QueryBuilders for debug mode (#3774)
---
 .../org/apache/doris/analysis/CreateTableStmt.java |   2 +-
 .../java/org/apache/doris/catalog/Catalog.java     |   2 +-
 .../java/org/apache/doris/catalog/EsTable.java     |   7 +-
 .../doris/common/proc/EsPartitionsProcDir.java     |   2 +-
 .../apache/doris/common/proc/EsShardProcDir.java   |   4 +-
 .../external/{ => elasticsearch}/EsIndexState.java |   2 +-
 .../{ => elasticsearch}/EsMajorVersion.java        |   2 +-
 .../external/{ => elasticsearch}/EsNodeInfo.java   |   2 +-
 .../external/{ => elasticsearch}/EsRestClient.java |  18 +-
 .../{ => elasticsearch}/EsShardRouting.java        |   2 +-
 .../external/{ => elasticsearch}/EsStateStore.java |  10 +-
 .../external/{ => elasticsearch}/EsTableState.java |   2 +-
 .../doris/external/{ => elasticsearch}/EsUtil.java |   2 +-
 .../ExternalDataSourceException.java               |   2 +-
 .../external/elasticsearch/QueryBuilders.java      | 459 +++++++++++++++++++++
 .../java/org/apache/doris/planner/EsScanNode.java  |   6 +-
 .../java/org/apache/doris/es/EsStateStoreTest.java | 254 ------------
 .../{es => external/elasticsearch}/EsUtilTest.java |   4 +-
 .../external/elasticsearch/QueryBuildersTest.java  | 173 ++++++++
 19 files changed, 670 insertions(+), 285 deletions(-)

diff --git a/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java b/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
index 7a87055..27d10e1 100644
--- a/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
@@ -33,7 +33,7 @@ import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.FeNameFormat;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.PrintableMap;
-import org.apache.doris.external.EsUtil;
+import org.apache.doris.external.elasticsearch.EsUtil;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
 
diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
index 43fc47f..37b70c5 100755
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -127,7 +127,7 @@ import org.apache.doris.deploy.DeployManager;
 import org.apache.doris.deploy.impl.AmbariDeployManager;
 import org.apache.doris.deploy.impl.K8sDeployManager;
 import org.apache.doris.deploy.impl.LocalFileDeployManager;
-import org.apache.doris.external.EsStateStore;
+import org.apache.doris.external.elasticsearch.EsStateStore;
 import org.apache.doris.ha.BDBHA;
 import org.apache.doris.ha.FrontendNodeType;
 import org.apache.doris.ha.HAProtocol;
diff --git a/fe/src/main/java/org/apache/doris/catalog/EsTable.java b/fe/src/main/java/org/apache/doris/catalog/EsTable.java
index a8baaa0..c7d5e57 100644
--- a/fe/src/main/java/org/apache/doris/catalog/EsTable.java
+++ b/fe/src/main/java/org/apache/doris/catalog/EsTable.java
@@ -20,14 +20,17 @@ package org.apache.doris.catalog;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.FeMetaVersion;
 import org.apache.doris.common.io.Text;
-import org.apache.doris.external.EsMajorVersion;
-import org.apache.doris.external.EsTableState;
+import org.apache.doris.external.elasticsearch.EsMajorVersion;
+import org.apache.doris.external.elasticsearch.EsTableState;
 import org.apache.doris.thrift.TEsTable;
 import org.apache.doris.thrift.TTableDescriptor;
 import org.apache.doris.thrift.TTableType;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+
 import com.google.common.base.Strings;
+
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
diff --git a/fe/src/main/java/org/apache/doris/common/proc/EsPartitionsProcDir.java b/fe/src/main/java/org/apache/doris/common/proc/EsPartitionsProcDir.java
index 7d9359f..896201e 100644
--- a/fe/src/main/java/org/apache/doris/common/proc/EsPartitionsProcDir.java
+++ b/fe/src/main/java/org/apache/doris/common/proc/EsPartitionsProcDir.java
@@ -24,7 +24,7 @@ import org.apache.doris.catalog.PartitionType;
 import org.apache.doris.catalog.RangePartitionInfo;
 import org.apache.doris.catalog.Table.TableType;
 import org.apache.doris.common.AnalysisException;
-import org.apache.doris.external.EsIndexState;
+import org.apache.doris.external.elasticsearch.EsIndexState;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
diff --git a/fe/src/main/java/org/apache/doris/common/proc/EsShardProcDir.java b/fe/src/main/java/org/apache/doris/common/proc/EsShardProcDir.java
index 51574a2..4cba64e 100644
--- a/fe/src/main/java/org/apache/doris/common/proc/EsShardProcDir.java
+++ b/fe/src/main/java/org/apache/doris/common/proc/EsShardProcDir.java
@@ -25,8 +25,8 @@ import org.apache.doris.catalog.Database;
 import org.apache.doris.catalog.EsTable;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.util.ListComparator;
-import org.apache.doris.external.EsIndexState;
-import org.apache.doris.external.EsShardRouting;
+import org.apache.doris.external.elasticsearch.EsIndexState;
+import org.apache.doris.external.elasticsearch.EsShardRouting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
diff --git a/fe/src/main/java/org/apache/doris/external/EsIndexState.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsIndexState.java
similarity index 99%
rename from fe/src/main/java/org/apache/doris/external/EsIndexState.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsIndexState.java
index 5dca5db..d2d0e90 100644
--- a/fe/src/main/java/org/apache/doris/external/EsIndexState.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsIndexState.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import org.apache.doris.analysis.PartitionKeyDesc;
 import org.apache.doris.analysis.PartitionValue;
diff --git a/fe/src/main/java/org/apache/doris/external/EsMajorVersion.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsMajorVersion.java
similarity index 98%
rename from fe/src/main/java/org/apache/doris/external/EsMajorVersion.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsMajorVersion.java
index b71db8a..2319f58 100644
--- a/fe/src/main/java/org/apache/doris/external/EsMajorVersion.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsMajorVersion.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 
 /**
diff --git a/fe/src/main/java/org/apache/doris/external/EsNodeInfo.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsNodeInfo.java
similarity index 99%
rename from fe/src/main/java/org/apache/doris/external/EsNodeInfo.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsNodeInfo.java
index 61b513b..4e11f9d 100644
--- a/fe/src/main/java/org/apache/doris/external/EsNodeInfo.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsNodeInfo.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import org.apache.doris.thrift.TNetworkAddress;
 
diff --git a/fe/src/main/java/org/apache/doris/external/EsRestClient.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsRestClient.java
similarity index 95%
rename from fe/src/main/java/org/apache/doris/external/EsRestClient.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsRestClient.java
index 2b93ea9..83cbc0c 100644
--- a/fe/src/main/java/org/apache/doris/external/EsRestClient.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsRestClient.java
@@ -15,12 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
-import okhttp3.Credentials;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.util.Strings;
@@ -35,6 +31,11 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import okhttp3.Credentials;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
 public class EsRestClient {
     private static final Logger LOG = LogManager.getLogger(EsRestClient.class);
     private ObjectMapper mapper;
@@ -142,14 +143,19 @@ public class EsRestClient {
             Request request = builder.get()
                     .url(currentNode + "/" + path)
                     .build();
+            Response response = null;
             try {
-                Response response = networkClient.newCall(request).execute();
+                response = networkClient.newCall(request).execute();
                 if (response.isSuccessful()) {
                     return response.body().string();
                 }
             } catch (IOException e) {
                 LOG.warn("request node [{}] [{}] failures {}, try next nodes", currentNode, path, e);
                 scratchExceptionForThrow = e;
+            } finally {
+                if (response != null) {
+                    response.close();
+                }
             }
             nextNode = selectNextNode();
             if (!nextNode) {
diff --git a/fe/src/main/java/org/apache/doris/external/EsShardRouting.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsShardRouting.java
similarity index 98%
rename from fe/src/main/java/org/apache/doris/external/EsShardRouting.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsShardRouting.java
index 12afa5f..c4474ae 100644
--- a/fe/src/main/java/org/apache/doris/external/EsShardRouting.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsShardRouting.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 
 import org.apache.commons.lang.StringUtils;
diff --git a/fe/src/main/java/org/apache/doris/external/EsStateStore.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsStateStore.java
similarity index 99%
rename from fe/src/main/java/org/apache/doris/external/EsStateStore.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsStateStore.java
index 460cc70..d22bb70 100644
--- a/fe/src/main/java/org/apache/doris/external/EsStateStore.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsStateStore.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.catalog.Column;
@@ -32,14 +32,14 @@ import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.util.MasterDaemon;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Range;
-
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.json.JSONObject;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Range;
+
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
diff --git a/fe/src/main/java/org/apache/doris/external/EsTableState.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsTableState.java
similarity index 98%
rename from fe/src/main/java/org/apache/doris/external/EsTableState.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsTableState.java
index 59b69aa..2b546a6 100644
--- a/fe/src/main/java/org/apache/doris/external/EsTableState.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsTableState.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import java.util.Map;
 import java.util.Random;
diff --git a/fe/src/main/java/org/apache/doris/external/EsUtil.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java
similarity index 98%
rename from fe/src/main/java/org/apache/doris/external/EsUtil.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java
index 4e05d0e..754f1ee 100644
--- a/fe/src/main/java/org/apache/doris/external/EsUtil.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/EsUtil.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import org.json.JSONObject;
 
diff --git a/fe/src/main/java/org/apache/doris/external/ExternalDataSourceException.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/ExternalDataSourceException.java
similarity index 95%
rename from fe/src/main/java/org/apache/doris/external/ExternalDataSourceException.java
rename to fe/src/main/java/org/apache/doris/external/elasticsearch/ExternalDataSourceException.java
index aee34a6..abb6744 100644
--- a/fe/src/main/java/org/apache/doris/external/ExternalDataSourceException.java
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/ExternalDataSourceException.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.external;
+package org.apache.doris.external.elasticsearch;
 
 import org.apache.doris.common.UserException;
 
diff --git a/fe/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java b/fe/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java
new file mode 100644
index 0000000..cf51470
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java
@@ -0,0 +1,459 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.external.elasticsearch;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * Utility class to generate elastic search queries.
+ * Some query builders and static helper method have been copied from Elasticsearch
+ */
+public final class QueryBuilders {
+
+    /**
+     * A query that matches on all documents.
+     */
+    public static MatchAllQueryBuilder matchAllQuery() {
+        return new MatchAllQueryBuilder();
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, String value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, int value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, long value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, float value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, double value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, boolean value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * A Query that matches documents containing a term.
+     *
+     * @param name  The name of the field
+     * @param value The value of the term
+     */
+    public static TermQueryBuilder termQuery(String name, Object value) {
+        return new TermQueryBuilder(name, value);
+    }
+
+    /**
+     * Implements the wildcard search query. Supported wildcards are {@code *}, which
+     * matches any character sequence (including the empty one), and {@code ?},
+     * which matches any single character. Note this query can be slow, as it
+     * needs to iterate over many terms. In order to prevent extremely slow WildcardQueries,
+     * a Wildcard term should not start with one of the wildcards {@code *} or
+     * {@code ?}.
+     *
+     * @param name  The field name
+     * @param query The wildcard query string
+     */
+    public static WildcardQueryBuilder wildcardQuery(String name, String query) {
+        return new WildcardQueryBuilder(name, query);
+    }
+
+    /**
+     * A Query that matches documents matching boolean combinations of other queries.
+     */
+    public static BoolQueryBuilder boolQuery() {
+        return new BoolQueryBuilder();
+    }
+
+
+    /**
+     * A filter for a field based on several terms matching on any of them.
+     *
+     * @param name   The field name
+     * @param values The terms
+     */
+    public static TermsQueryBuilder termsQuery(String name, Iterable<?> values) {
+        return new TermsQueryBuilder(name, values);
+    }
+
+    /**
+     * A filter to filter only documents where a field exists in them.
+     *
+     * @param name The name of the field
+     */
+    public static ExistsQueryBuilder existsQuery(String name) {
+        return new ExistsQueryBuilder(name);
+    }
+
+    /**
+     * A Query that matches documents within an range of terms.
+     *
+     * @param name The field name
+     */
+    public static RangeQueryBuilder rangeQuery(String name) {
+        return new RangeQueryBuilder(name);
+    }
+
+
+    /**
+     * Base class to build various ES queries
+     */
+    abstract static class QueryBuilder {
+
+        /**
+         * Convert query to JSON format
+         *
+         * @param out used to generate JSON elements
+         * @throws IOException if IO error occurred
+         */
+        abstract void toJson(JsonGenerator out) throws IOException;
+    }
+
+    /**
+     * A Query that matches documents matching boolean combinations of other queries.
+     */
+    static class BoolQueryBuilder extends QueryBuilder {
+
+        private final List<QueryBuilder> mustClauses = new ArrayList<>();
+        private final List<QueryBuilder> mustNotClauses = new ArrayList<>();
+        private final List<QueryBuilder> filterClauses = new ArrayList<>();
+        private final List<QueryBuilder> shouldClauses = new ArrayList<>();
+
+        BoolQueryBuilder must(QueryBuilder queryBuilder) {
+            Objects.requireNonNull(queryBuilder);
+            mustClauses.add(queryBuilder);
+            return this;
+        }
+
+        BoolQueryBuilder filter(QueryBuilder queryBuilder) {
+            Objects.requireNonNull(queryBuilder);
+            filterClauses.add(queryBuilder);
+            return this;
+        }
+
+        BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
+            Objects.requireNonNull(queryBuilder);
+            mustNotClauses.add(queryBuilder);
+            return this;
+        }
+
+        BoolQueryBuilder should(QueryBuilder queryBuilder) {
+            Objects.requireNonNull(queryBuilder);
+            shouldClauses.add(queryBuilder);
+            return this;
+        }
+
+        @Override
+        protected void toJson(JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("bool");
+            out.writeStartObject();
+            writeJsonArray("must", mustClauses, out);
+            writeJsonArray("filter", filterClauses, out);
+            writeJsonArray("must_not", mustNotClauses, out);
+            writeJsonArray("should", shouldClauses, out);
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+
+        private void writeJsonArray(String field, List<QueryBuilder> clauses, JsonGenerator out)
+                throws IOException {
+            if (clauses.isEmpty()) {
+                return;
+            }
+
+            if (clauses.size() == 1) {
+                out.writeFieldName(field);
+                clauses.get(0).toJson(out);
+            } else {
+                out.writeArrayFieldStart(field);
+                for (QueryBuilder clause : clauses) {
+                    clause.toJson(out);
+                }
+                out.writeEndArray();
+            }
+        }
+    }
+
+    /**
+     * A Query that matches documents containing a term
+     */
+    static class TermQueryBuilder extends QueryBuilder {
+        private final String fieldName;
+        private final Object value;
+
+        private TermQueryBuilder(final String fieldName, final Object value) {
+            this.fieldName = Objects.requireNonNull(fieldName, "fieldName");
+            this.value = Objects.requireNonNull(value, "value");
+        }
+
+        @Override
+        void toJson(final JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("term");
+            out.writeStartObject();
+            out.writeFieldName(fieldName);
+            writeObject(out, value);
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+    }
+
+    /**
+     * A filter for a field based on several terms matching on any of them.
+     */
+    static class TermsQueryBuilder extends QueryBuilder {
+        private final String fieldName;
+        private final Iterable<?> values;
+
+        private TermsQueryBuilder(final String fieldName, final Iterable<?> values) {
+            this.fieldName = Objects.requireNonNull(fieldName, "fieldName");
+            this.values = Objects.requireNonNull(values, "values");
+        }
+
+        @Override
+        void toJson(final JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("terms");
+            out.writeStartObject();
+            out.writeFieldName(fieldName);
+            out.writeStartArray();
+            for (Object value : values) {
+                writeObject(out, value);
+            }
+            out.writeEndArray();
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+    }
+
+    /**
+     * A Query that matches documents within an range of terms
+     */
+    static class RangeQueryBuilder extends QueryBuilder {
+
+        private final String field;
+
+        private Object lt;
+        private boolean lte;
+        private Object gt;
+        private boolean gte;
+
+        private String format;
+
+        private RangeQueryBuilder(final String field) {
+            this.field = Objects.requireNonNull(field, "fieldName");
+        }
+
+        private RangeQueryBuilder to(Object value, boolean lte) {
+            this.lt = Objects.requireNonNull(value, "value");
+            this.lte = lte;
+            return this;
+        }
+
+        private RangeQueryBuilder from(Object value, boolean gte) {
+            this.gt = Objects.requireNonNull(value, "value");
+            this.gte = gte;
+            return this;
+        }
+
+        RangeQueryBuilder lt(Object value) {
+            return to(value, false);
+        }
+
+        RangeQueryBuilder lte(Object value) {
+            return to(value, true);
+        }
+
+        RangeQueryBuilder gt(Object value) {
+            return from(value, false);
+        }
+
+        RangeQueryBuilder gte(Object value) {
+            return from(value, true);
+        }
+
+        RangeQueryBuilder format(String format) {
+            this.format = format;
+            return this;
+        }
+
+        @Override
+        void toJson(final JsonGenerator out) throws IOException {
+            if (lt == null && gt == null) {
+                throw new IllegalStateException("Either lower or upper bound should be provided");
+            }
+
+            out.writeStartObject();
+            out.writeFieldName("range");
+            out.writeStartObject();
+            out.writeFieldName(field);
+            out.writeStartObject();
+
+            if (gt != null) {
+                final String op = gte ? "gte" : "gt";
+                out.writeFieldName(op);
+                writeObject(out, gt);
+            }
+
+            if (lt != null) {
+                final String op = lte ? "lte" : "lt";
+                out.writeFieldName(op);
+                writeObject(out, lt);
+            }
+
+            if (format != null) {
+                out.writeStringField("format", format);
+            }
+
+            out.writeEndObject();
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+    }
+
+
+    /**
+     * Supported wildcards are {@code *}, which
+     * matches any character sequence (including the empty one), and {@code ?},
+     * which matches any single character
+     */
+    static class WildcardQueryBuilder extends QueryBuilder {
+
+        private final String fieldName;
+        private final String value;
+
+
+        public WildcardQueryBuilder(String fieldName, String value) {
+            this.fieldName = Objects.requireNonNull(fieldName, "fieldName");
+            this.value = Objects.requireNonNull(value, "value");
+        }
+
+        @Override
+        void toJson(JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("wildcard");
+            out.writeStartObject();
+            out.writeFieldName(fieldName);
+            out.writeString(value);
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+    }
+
+    /**
+     * Query that only match on documents that the fieldName has a value in them
+     */
+    static class ExistsQueryBuilder extends QueryBuilder {
+
+        private final String fieldName;
+
+        ExistsQueryBuilder(final String fieldName) {
+            this.fieldName = Objects.requireNonNull(fieldName, "fieldName");
+        }
+
+        @Override
+        void toJson(JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("exists");
+            out.writeStartObject();
+            out.writeStringField("field", fieldName);
+            out.writeEndObject();
+            out.writeEndObject();
+
+        }
+    }
+
+    /**
+     * A query that matches on all documents
+     */
+    static class MatchAllQueryBuilder extends QueryBuilder {
+
+        private MatchAllQueryBuilder() {
+        }
+
+        @Override
+        void toJson(final JsonGenerator out) throws IOException {
+            out.writeStartObject();
+            out.writeFieldName("match_all");
+            out.writeStartObject();
+            out.writeEndObject();
+            out.writeEndObject();
+        }
+    }
+
+    /**
+     * Write (scalar) value (string, number, boolean or null) to json format
+     *
+     * @param out   source target
+     * @param value value to write
+     * @throws IOException if error
+     */
+    private static void writeObject(JsonGenerator out, Object value) throws IOException {
+        out.writeObject(value);
+    }
+}
diff --git a/fe/src/main/java/org/apache/doris/planner/EsScanNode.java b/fe/src/main/java/org/apache/doris/planner/EsScanNode.java
index 65fd3f1..497fa63 100644
--- a/fe/src/main/java/org/apache/doris/planner/EsScanNode.java
+++ b/fe/src/main/java/org/apache/doris/planner/EsScanNode.java
@@ -26,9 +26,9 @@ import org.apache.doris.catalog.PartitionKey;
 import org.apache.doris.catalog.RangePartitionInfo;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.UserException;
-import org.apache.doris.external.EsIndexState;
-import org.apache.doris.external.EsShardRouting;
-import org.apache.doris.external.EsTableState;
+import org.apache.doris.external.elasticsearch.EsIndexState;
+import org.apache.doris.external.elasticsearch.EsShardRouting;
+import org.apache.doris.external.elasticsearch.EsTableState;
 import org.apache.doris.system.Backend;
 import org.apache.doris.thrift.TEsScanNode;
 import org.apache.doris.thrift.TEsScanRange;
diff --git a/fe/src/test/java/org/apache/doris/es/EsStateStoreTest.java b/fe/src/test/java/org/apache/doris/es/EsStateStoreTest.java
deleted file mode 100644
index c41c2c4..0000000
--- a/fe/src/test/java/org/apache/doris/es/EsStateStoreTest.java
+++ /dev/null
@@ -1,254 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.es;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.doris.analysis.PartitionValue;
-import org.apache.doris.catalog.Catalog;
-import org.apache.doris.catalog.CatalogTestUtil;
-import org.apache.doris.catalog.EsTable;
-import org.apache.doris.catalog.FakeCatalog;
-import org.apache.doris.catalog.FakeEditLog;
-import org.apache.doris.catalog.PartitionKey;
-import org.apache.doris.catalog.RangePartitionInfo;
-import org.apache.doris.common.AnalysisException;
-import org.apache.doris.common.FeMetaVersion;
-import org.apache.doris.external.EsIndexState;
-import org.apache.doris.external.EsStateStore;
-import org.apache.doris.external.EsTableState;
-import org.apache.doris.meta.MetaContext;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Range;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URISyntaxException;
-import java.util.Map;
-
-public class EsStateStoreTest {
-
-    private static FakeEditLog fakeEditLog;
-    private static FakeCatalog fakeCatalog;
-    private static Catalog masterCatalog;
-    private static String clusterStateStr1 = "";
-    private static String clusterStateStr2 = "";
-    private static String clusterStateStr3 = "";
-    private static String clusterStateStr4 = "";
-    private static String clusterStateStr5 = "";
-    private EsStateStore esStateStore;
-    
-    @BeforeClass
-    public static void init() throws IOException, InstantiationException, IllegalAccessException, 
-        IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException,
-        URISyntaxException {
-        fakeEditLog = new FakeEditLog();
-        fakeCatalog = new FakeCatalog();
-        masterCatalog = CatalogTestUtil.createTestCatalog();
-        MetaContext metaContext = new MetaContext();
-        metaContext.setMetaVersion(FeMetaVersion.VERSION_40);
-        metaContext.setThreadLocalInfo();
-        // masterCatalog.setJournalVersion(FeMetaVersion.VERSION_40);
-        FakeCatalog.setCatalog(masterCatalog);
-        clusterStateStr1 = loadJsonFromFile("data/es/clusterstate1.json");
-        clusterStateStr2 = loadJsonFromFile("data/es/clusterstate2.json");
-        clusterStateStr3 = loadJsonFromFile("data/es/clusterstate3.json");
-        clusterStateStr4 = loadJsonFromFile("data/es/clusterstate4.json");
-        clusterStateStr5 = loadJsonFromFile("data/es/clusterstate5.json");
-    }
-    
-    @Before
-    public void setUp() {
-        esStateStore = new EsStateStore();
-    }
-    
-    /**
-     * partitioned es table schema: k1(date), k2(int), v(double)
-     * @throws AnalysisException 
-     */
-    @Test
-    public void testParsePartitionedClusterState() throws AnalysisException {
-        EsTable esTable = (EsTable) Catalog.getCurrentCatalog()
-                                            .getDb(CatalogTestUtil.testDb1)
-                                            .getTable(CatalogTestUtil.testPartitionedEsTable1);
-        boolean hasException = false;
-        EsTableState esTableState = null;
-        try {
-            esTableState = esStateStore.getTableState(clusterStateStr1, esTable);
-        } catch (Exception e) {
-            e.printStackTrace();
-            hasException = true;
-        }
-        assertFalse(hasException);
-        assertNotNull(esTableState);
-        assertEquals(2, esTableState.getPartitionedIndexStates().size());
-        RangePartitionInfo definedPartInfo = (RangePartitionInfo) esTable.getPartitionInfo();
-        RangePartitionInfo rangePartitionInfo = (RangePartitionInfo) esTableState.getPartitionInfo();
-        Map<Long, Range<PartitionKey>> rangeMap = rangePartitionInfo.getIdToRange(false);
-        assertEquals(2, rangeMap.size());
-        Range<PartitionKey> part0 = rangeMap.get(new Long(0));
-        EsIndexState esIndexState1 = esTableState.getIndexState(0);
-        assertEquals(5, esIndexState1.getShardRoutings().size());
-        assertEquals("index1", esIndexState1.getIndexName());
-        PartitionKey lowKey = PartitionKey.createInfinityPartitionKey(definedPartInfo.getPartitionColumns(), false);
-        PartitionKey upperKey = PartitionKey.createPartitionKey(Lists.newArrayList(new PartitionValue("2018-10-01")),
-                definedPartInfo.getPartitionColumns());
-        Range<PartitionKey> newRange = Range.closedOpen(lowKey, upperKey);
-        assertEquals(newRange, part0);
-        Range<PartitionKey> part1 = rangeMap.get(new Long(1));
-        EsIndexState esIndexState2 = esTableState.getIndexState(1);
-        assertEquals("index2", esIndexState2.getIndexName());
-        lowKey = PartitionKey.createPartitionKey(Lists.newArrayList(new PartitionValue("2018-10-01")),
-                definedPartInfo.getPartitionColumns());
-        upperKey = PartitionKey.createPartitionKey(Lists.newArrayList(new PartitionValue("2018-10-02")),
-                definedPartInfo.getPartitionColumns());
-        newRange = Range.closedOpen(lowKey, upperKey);
-        assertEquals(newRange, part1);
-        assertEquals(6, esIndexState2.getShardRoutings().size());
-    }
-    
-    /**
-     * partitioned es table schema: k1(date), k2(int), v(double)
-     * scenario desc:
-     * 2 indices, one with partition desc, the other does not contains partition desc
-     * @throws AnalysisException 
-     */
-    @Test
-    public void testParsePartitionedClusterStateTwoIndices() throws AnalysisException {
-        EsTable esTable = (EsTable) Catalog.getCurrentCatalog()
-                                            .getDb(CatalogTestUtil.testDb1)
-                                            .getTable(CatalogTestUtil.testPartitionedEsTable1);
-        boolean hasException = false;
-        EsTableState esTableState = null;
-        try {
-            esTableState = esStateStore.getTableState(clusterStateStr3, esTable);
-        } catch (Exception e) {
-            e.printStackTrace();
-            hasException = true;
-        }
-        assertFalse(hasException);
-        assertNotNull(esTableState);
-        
-        // check 
-        assertEquals(1, esTableState.getPartitionedIndexStates().size());
-        assertEquals(1, esTableState.getUnPartitionedIndexStates().size());
-        
-        // check partition info
-        RangePartitionInfo definedPartInfo = (RangePartitionInfo) esTable.getPartitionInfo();
-        RangePartitionInfo rangePartitionInfo = (RangePartitionInfo) esTableState.getPartitionInfo();
-        Map<Long, Range<PartitionKey>> rangeMap = rangePartitionInfo.getIdToRange(false);
-        assertEquals(1, rangeMap.size());
-        Range<PartitionKey> part0 = rangeMap.get(new Long(0));
-        EsIndexState esIndexState1 = esTableState.getIndexState(0);
-        assertEquals(5, esIndexState1.getShardRoutings().size());
-        assertEquals("index1", esIndexState1.getIndexName());
-        PartitionKey lowKey = PartitionKey.createInfinityPartitionKey(definedPartInfo.getPartitionColumns(), false);
-        PartitionKey upperKey = PartitionKey.createPartitionKey(Lists.newArrayList(new PartitionValue("2018-10-01")),
-                definedPartInfo.getPartitionColumns());
-        Range<PartitionKey> newRange = Range.closedOpen(lowKey, upperKey);
-        assertEquals(newRange, part0);
-        
-        // check index with no partition desc
-        EsIndexState esIndexState2 = esTableState.getUnPartitionedIndexStates().get("index2");
-        assertEquals("index2", esIndexState2.getIndexName());
-        assertEquals(6, esIndexState2.getShardRoutings().size());
-    }
-    
-    /**
-     * partitioned es table schema: k1(date), k2(int), v(double)
-     * scenario desc:
-     * 2 indices, both of them does not contains partition desc and es table does not have partition info
-     * but cluster state have partition info
-     * @throws AnalysisException 
-     */
-    @Test
-    public void testParseUnPartitionedClusterStateTwoIndices() throws AnalysisException {
-        EsTable esTable = (EsTable) Catalog.getCurrentCatalog()
-                                            .getDb(CatalogTestUtil.testDb1)
-                                            .getTable(CatalogTestUtil.testUnPartitionedEsTableId1);
-        boolean hasException = false;
-        EsTableState esTableState = null;
-        try {
-            esTableState = esStateStore.getTableState(clusterStateStr4, esTable);
-        } catch (Exception e) {
-            e.printStackTrace();
-            hasException = true;
-        }
-        assertFalse(hasException);
-        assertNotNull(esTableState);
-        
-        // check 
-        assertEquals(0, esTableState.getPartitionedIndexStates().size());
-        assertEquals(2, esTableState.getUnPartitionedIndexStates().size());
-        
-        // check index with no partition desc
-        EsIndexState esIndexState1 = esTableState.getUnPartitionedIndexStates().get("index1");
-        assertEquals("index1", esIndexState1.getIndexName());
-        EsIndexState esIndexState2 = esTableState.getUnPartitionedIndexStates().get("index2");
-        assertEquals("index2", esIndexState2.getIndexName());
-        assertEquals(6, esIndexState2.getShardRoutings().size());
-    }
-
-    
-    /**
-     * partitioned es table schema: k1(date), k2(int), v(double)
-     * "upperbound": "2018" is not a valid date value, so parsing procedure will fail
-     */
-    @Test
-    public void testParseInvalidUpperbound() {
-        EsTable esTable = (EsTable) Catalog.getCurrentCatalog()
-                                            .getDb(CatalogTestUtil.testDb1)
-                                            .getTable(CatalogTestUtil.testPartitionedEsTable1);
-        boolean hasException = false;
-        EsTableState esTableState = null;
-        try {
-            esTableState = esStateStore.getTableState(clusterStateStr2, esTable);
-        } catch (Exception e) {
-            hasException = true;
-        }
-        assertTrue(hasException);
-        assertTrue(esTableState == null);
-    }
-    
-    private static String loadJsonFromFile(String fileName) throws IOException, URISyntaxException {
-        File file = new File(EsStateStoreTest.class.getClassLoader().getResource(fileName).toURI());
-        InputStream is = new FileInputStream(file);
-        BufferedReader br = new BufferedReader(new InputStreamReader(is));  
-        StringBuilder jsonStr = new StringBuilder();
-        String line = "";
-        while ((line = br.readLine()) != null)  {
-            jsonStr.append(line);
-        }
-        br.close();
-        is.close();
-        return jsonStr.toString();
-    }
-}
diff --git a/fe/src/test/java/org/apache/doris/es/EsUtilTest.java b/fe/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java
similarity index 97%
rename from fe/src/test/java/org/apache/doris/es/EsUtilTest.java
rename to fe/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java
index 876a8ea..b611ae4 100644
--- a/fe/src/test/java/org/apache/doris/es/EsUtilTest.java
+++ b/fe/src/test/java/org/apache/doris/external/elasticsearch/EsUtilTest.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.es;
+package org.apache.doris.external.elasticsearch;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -25,8 +25,6 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.junit.Test;
 
-import org.apache.doris.external.EsUtil;
-
 public class EsUtilTest {
 
     private String jsonStr = "{\"settings\": {\n" 
diff --git a/fe/src/test/java/org/apache/doris/external/elasticsearch/QueryBuildersTest.java b/fe/src/test/java/org/apache/doris/external/elasticsearch/QueryBuildersTest.java
new file mode 100644
index 0000000..ebd0243
--- /dev/null
+++ b/fe/src/test/java/org/apache/doris/external/elasticsearch/QueryBuildersTest.java
@@ -0,0 +1,173 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.external.elasticsearch;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.doris.external.elasticsearch.QueryBuilders;
+import org.junit.Test;
+
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Check that internal queries are correctly converted to ES search query (as JSON)
+ */
+public class QueryBuildersTest {
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+
+    @Test
+    public void testTermQuery() throws Exception {
+        assertEquals("{\"term\":{\"k\":\"aaaa\"}}",
+                toJson(QueryBuilders.termQuery("k", "aaaa")));
+        assertEquals("{\"term\":{\"aaaa\":\"k\"}}",
+                toJson(QueryBuilders.termQuery("aaaa", "k")));
+        assertEquals("{\"term\":{\"k\":0}}",
+                toJson(QueryBuilders.termQuery("k", (byte) 0)));
+        assertEquals("{\"term\":{\"k\":123}}",
+                toJson(QueryBuilders.termQuery("k", (long) 123)));
+        assertEquals("{\"term\":{\"k\":41}}",
+                toJson(QueryBuilders.termQuery("k", (short) 41)));
+        assertEquals("{\"term\":{\"k\":128}}",
+                toJson(QueryBuilders.termQuery("k", 128)));
+        assertEquals("{\"term\":{\"k\":42.42}}",
+                toJson(QueryBuilders.termQuery("k", 42.42D)));
+        assertEquals("{\"term\":{\"k\":1.1}}",
+                toJson(QueryBuilders.termQuery("k", 1.1F)));
+        assertEquals("{\"term\":{\"k\":1}}",
+                toJson(QueryBuilders.termQuery("k", new BigDecimal(1))));
+        assertEquals("{\"term\":{\"k\":121}}",
+                toJson(QueryBuilders.termQuery("k", new BigInteger("121"))));
+        assertEquals("{\"term\":{\"k\":true}}",
+                toJson(QueryBuilders.termQuery("k", new AtomicBoolean(true))));
+    }
+
+    @Test
+    public void testTermsQuery() throws Exception {
+
+        assertEquals("{\"terms\":{\"k\":[]}}",
+                toJson(QueryBuilders.termsQuery("k", Collections.emptySet())));
+
+        assertEquals("{\"terms\":{\"k\":[0]}}",
+                toJson(QueryBuilders.termsQuery("k", Collections.singleton(0))));
+
+        assertEquals("{\"terms\":{\"k\":[\"aaa\"]}}",
+                toJson(QueryBuilders.termsQuery("k", Collections.singleton("aaa"))));
+
+        assertEquals("{\"terms\":{\"k\":[\"aaa\",\"bbb\",\"ccc\"]}}",
+                toJson(QueryBuilders.termsQuery("k", Arrays.asList("aaa", "bbb", "ccc"))));
+
+        assertEquals("{\"terms\":{\"k\":[1,2,3]}}",
+                toJson(QueryBuilders.termsQuery("k", Arrays.asList(1, 2, 3))));
+
+        assertEquals("{\"terms\":{\"k\":[1.1,2.2,3.3]}}",
+                toJson(QueryBuilders.termsQuery("k", Arrays.asList(1.1f, 2.2f, 3.3f))));
+
+        assertEquals("{\"terms\":{\"k\":[1.1,2.2,3.3]}}",
+                toJson(QueryBuilders.termsQuery("k", Arrays.asList(1.1d, 2.2d, 3.3d))));
+    }
+
+    @Test
+    public void testBoolQuery() throws Exception {
+        QueryBuilders.QueryBuilder q1 = QueryBuilders.boolQuery()
+                .must(QueryBuilders.termQuery("k", "aaa"));
+
+        assertEquals("{\"bool\":{\"must\":{\"term\":{\"k\":\"aaa\"}}}}",
+                toJson(q1));
+
+        QueryBuilders.QueryBuilder q2 = QueryBuilders.boolQuery()
+                .must(QueryBuilders.termQuery("k1", "aaa")).must(QueryBuilders.termQuery("k2", "bbb"));
+
+        assertEquals("{\"bool\":{\"must\":[{\"term\":{\"k1\":\"aaa\"}},{\"term\":{\"k2\":\"bbb\"}}]}}",
+                toJson(q2));
+
+        QueryBuilders.QueryBuilder q3 = QueryBuilders.boolQuery()
+                .mustNot(QueryBuilders.termQuery("k", "fff"));
+
+        assertEquals("{\"bool\":{\"must_not\":{\"term\":{\"k\":\"fff\"}}}}",
+                toJson(q3));
+
+        QueryBuilders.QueryBuilder q4 = QueryBuilders.rangeQuery("k1").lt(200).gt(-200);
+        QueryBuilders.QueryBuilder q5 = QueryBuilders.termsQuery("k2", Arrays.asList("aaa", "bbb", "ccc"));
+        QueryBuilders.QueryBuilder q6 = QueryBuilders.boolQuery().must(q4).should(q5);
+        assertEquals("{\"bool\":{\"must\":{\"range\":{\"k1\":{\"gt\":-200,\"lt\":200}}},\"should\":{\"terms\":{\"k2\":[\"aaa\",\"bbb\",\"ccc\"]}}}}", toJson(q6));
+        assertEquals("{\"bool\":{\"filter\":[{\"range\":{\"k1\":{\"gt\":-200,\"lt\":200}}},{\"terms\":{\"k2\":[\"aaa\",\"bbb\",\"ccc\"]}}]}}", toJson(QueryBuilders.boolQuery().filter(q4).filter(q5)));
+        assertEquals("{\"bool\":{\"filter\":{\"range\":{\"k1\":{\"gt\":-200,\"lt\":200}}},\"must_not\":{\"terms\":{\"k2\":[\"aaa\",\"bbb\",\"ccc\"]}}}}", toJson(QueryBuilders.boolQuery().filter(q4).mustNot(q5)));
+
+    }
+
+    @Test
+    public void testExistsQuery() throws Exception {
+        assertEquals("{\"exists\":{\"field\":\"k\"}}",
+                toJson(QueryBuilders.existsQuery("k")));
+    }
+
+    @Test
+    public void testRangeQuery() throws Exception {
+        assertEquals("{\"range\":{\"k\":{\"lt\":123}}}",
+                toJson(QueryBuilders.rangeQuery("k").lt(123)));
+        assertEquals("{\"range\":{\"k\":{\"gt\":123}}}",
+                toJson(QueryBuilders.rangeQuery("k").gt(123)));
+        assertEquals("{\"range\":{\"k\":{\"gte\":12345678}}}",
+                toJson(QueryBuilders.rangeQuery("k").gte(12345678)));
+        assertEquals("{\"range\":{\"k\":{\"lte\":12345678}}}",
+                toJson(QueryBuilders.rangeQuery("k").lte(12345678)));
+        assertEquals("{\"range\":{\"k\":{\"gt\":123,\"lt\":345}}}",
+                toJson(QueryBuilders.rangeQuery("k").gt(123).lt(345)));
+        assertEquals("{\"range\":{\"k\":{\"gt\":-456.6,\"lt\":12.3}}}",
+                toJson(QueryBuilders.rangeQuery("k").lt(12.3f).gt(-456.6f)));
+        assertEquals("{\"range\":{\"k\":{\"gt\":6789.33,\"lte\":9999.99}}}",
+                toJson(QueryBuilders.rangeQuery("k").gt(6789.33f).lte(9999.99f)));
+        assertEquals("{\"range\":{\"k\":{\"gte\":1,\"lte\":\"zzz\"}}}",
+                toJson(QueryBuilders.rangeQuery("k").gte(1).lte("zzz")));
+        assertEquals("{\"range\":{\"k\":{\"gte\":\"zzz\"}}}",
+                toJson(QueryBuilders.rangeQuery("k").gte("zzz")));
+        assertEquals("{\"range\":{\"k\":{\"gt\":\"aaa\",\"lt\":\"zzz\"}}}",
+                toJson(QueryBuilders.rangeQuery("k").gt("aaa").lt("zzz")));
+    }
+
+    @Test
+    public void testMatchAllQuery() throws IOException {
+        assertEquals("{\"match_all\":{}}",
+                toJson(QueryBuilders.matchAllQuery()));
+    }
+
+    @Test
+    public void testWildCardQuery() throws IOException {
+        assertEquals("{\"wildcard\":{\"k1\":\"?aa*\"}}",
+                toJson(QueryBuilders.wildcardQuery("k1", "?aa*")));
+    }
+
+    private String toJson(QueryBuilders.QueryBuilder builder) throws IOException {
+        StringWriter writer = new StringWriter();
+        JsonGenerator gen = mapper.getFactory().createGenerator(writer);
+        builder.toJson(gen);
+        gen.flush();
+        gen.close();
+        return writer.toString();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org