You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2021/09/01 13:35:58 UTC

[skywalking] branch feature/elasticsearch-client updated (3198dc9 -> 95a7c15)

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

kezhenxu94 pushed a change to branch feature/elasticsearch-client
in repository https://gitbox.apache.org/repos/asf/skywalking.git.


 discard 3198dc9  Rebuilt ElasticSearch client on top of their REST API
     new 95a7c15  Rebuilt ElasticSearch client on top of their REST API

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (3198dc9)
            \
             N -- N -- N   refs/heads/feature/elasticsearch-client (95a7c15)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../library/client/elasticsearch/ITElasticSearchClient.java       | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

[skywalking] 01/01: Rebuilt ElasticSearch client on top of their REST API

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch feature/elasticsearch-client
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 95a7c15ad3774b882dd890b4c33b92ca99e78ccf
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sat Aug 21 10:29:31 2021 +0800

    Rebuilt ElasticSearch client on top of their REST API
---
 .github/workflows/e2e.istio.yaml                   |   4 +-
 Makefile                                           |   9 +-
 apm-dist-es7/pom.xml                               | 105 ----
 apm-dist-es7/src/main/assembly/binary-es7.xml      | 103 ----
 dist-material/release-docs/LICENSE                 |  13 -
 docker/README.md                                   |  21 -
 docker/oap/log4j2.xml                              |   1 -
 docs/en/setup/envoy/examples/metrics/log4j2.xml    |   1 -
 oap-server-bom-es7/pom.xml                         |  56 ---
 oap-server-bom/pom.xml                             |  27 +-
 .../skywalking/oap/meter/analyzer/Analyzer.java    |  13 +-
 .../oap/meter/analyzer/MetricConvert.java          |   4 +-
 oap-server/pom.xml                                 |   1 -
 oap-server/server-alarm-plugin/pom.xml             |   6 +-
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../server-bootstrap/src/main/resources/log4j2.xml |   3 +-
 .../configuration-apollo/pom.xml                   |   5 +
 .../storage/type/StorageDataComplexObject.java     |  18 +
 .../oap/server/core/remote/JettyServerTest.java    | 145 ++----
 oap-server/server-library/library-client/pom.xml   | 114 +----
 .../client/elasticsearch/ElasticSearchClient.java  | 554 ++++++---------------
 ...InsertRequest.java => IndexRequestWrapper.java} |  25 +-
 .../client/elasticsearch/UpdateRequestWrapper.java |  37 ++
 .../elasticsearch/ITElasticSearchClient.java       | 298 +++++------
 .../library-elasticsearch-client}/pom.xml          |  30 +-
 .../library/elasticsearch/ElasticSearchClient.java | 153 ++++++
 .../elasticsearch/ElasticSearchClientBuilder.java  | 150 ++++++
 .../elasticsearch/ElasticSearchVersion.java        |  80 +++
 .../library/elasticsearch/bulk/BulkProcessor.java  | 135 +++++
 .../elasticsearch/bulk/BulkProcessorBuilder.java   |  63 +++
 .../library/elasticsearch/client/AliasClient.java  |  65 +++
 .../elasticsearch/client/DocumentClient.java       | 129 +++++
 .../library/elasticsearch/client/IndexClient.java  | 121 +++++
 .../library/elasticsearch/client/SearchClient.java |  66 +++
 .../elasticsearch/client/TemplateClient.java       | 128 +++++
 .../elasticsearch/requests/IndexRequest.java}      |  19 +-
 .../elasticsearch/requests/UpdateRequest.java}     |  19 +-
 .../requests/factory/AliasFactory.java}            |  16 +-
 .../requests/factory/BulkFactory.java}             |  14 +-
 .../elasticsearch/requests/factory/Codec.java}     |  22 +-
 .../requests/factory/DocumentFactory.java          |  57 +++
 .../requests/factory/IndexFactory.java             |  51 ++
 .../requests/factory/RequestFactory.java           |  92 ++++
 .../requests/factory/SearchFactory.java}           |  26 +-
 .../requests/factory/TemplateFactory.java}         |  31 +-
 .../requests/factory/v6/V6AliasFactory.java}       |  24 +-
 .../requests/factory/v6/V6BulkFactory.java}        |  32 +-
 .../requests/factory/v6/V6DocumentFactory.java     | 167 +++++++
 .../requests/factory/v6/V6IndexFactory.java        | 103 ++++
 .../requests/factory/v6/V6RequestFactory.java      |  67 +++
 .../requests/factory/v6/V6SearchFactory.java       |  55 ++
 .../requests/factory/v6/V6TemplateFactory.java     |  80 +++
 .../requests/factory/v6/V7DocumentFactory.java     | 161 ++++++
 .../requests/factory/v6/V7IndexFactory.java        | 101 ++++
 .../requests/factory/v6/V7RequestFactory.java      |  67 +++
 .../requests/factory/v6/V7TemplateFactory.java     |  84 ++++
 .../factory/v6/codec/BoolQuerySerializer.java      |  68 +++
 .../v6/codec/IndexRequestDeserializer.java}        |  23 +-
 .../factory/v6/codec/MappingsSerializer.java       |  43 ++
 .../factory/v6/codec/RangeQuerySerializer.java     |  62 +++
 .../requests/factory/v6/codec/TermSerializer.java  |  44 ++
 .../requests/factory/v6/codec/V6Codec.java         |  96 ++++
 .../factory/v6/codec/V6IndexRequestSerializer.java |  48 ++
 .../factory/v6/codec/V6MappingsDeserializer.java   |  54 ++
 .../v6/codec/V6UpdateRequestSerializer.java        |  54 ++
 .../requests/factory/v6/codec/V7Codec.java         |  92 ++++
 .../factory/v6/codec/V7IndexRequestSerializer.java |  47 ++
 .../factory/v6/codec/V7MappingsDeserializer.java   |  44 ++
 .../v6/codec/V7UpdateRequestSerializer.java        |  53 ++
 .../elasticsearch/requests/search/BoolQuery.java}  |  18 +-
 .../requests/search/BoolQueryBuilder.java          | 133 +++++
 .../elasticsearch/requests/search/IdsQuery.java    |  49 ++
 .../requests/search/MatchPhaseQuery.java           |  49 ++
 .../elasticsearch/requests/search/MatchQuery.java  |  49 ++
 .../elasticsearch/requests/search/Query.java       |  80 +++
 .../requests/search/QueryBuilder.java}             |  13 +-
 .../elasticsearch/requests/search/RangeQuery.java} |  19 +-
 .../requests/search/RangeQueryBuilder.java         |  70 +++
 .../elasticsearch/requests/search/Search.java}     |  28 +-
 .../requests/search/SearchBuilder.java             | 114 +++++
 .../elasticsearch/requests/search/Sort.java}       |  29 +-
 .../elasticsearch/requests/search/Sorts.java       |  70 +++
 .../elasticsearch/requests/search/TermQuery.java}  |  15 +-
 .../elasticsearch/requests/search/TermsQuery.java} |  16 +-
 .../requests/search/aggregation/Aggregation.java   |  50 ++
 .../search/aggregation/AggregationBuilder.java}    |  10 +-
 .../search/aggregation/AvgAggregation.java         |  57 +++
 .../search/aggregation/AvgAggregationBuilder.java} |  29 +-
 .../requests/search/aggregation/BucketOrder.java}  |  21 +-
 .../search/aggregation/MaxAggregation.java         |  57 +++
 .../search/aggregation/MaxAggregationBuilder.java} |  27 +-
 .../search/aggregation/MinAggregation.java         |  57 +++
 .../search/aggregation/MinAggregationBuilder.java} |  27 +-
 .../search/aggregation/SumAggregation.java         |  57 +++
 .../search/aggregation/SumAggregationBuilder.java} |  27 +-
 .../search/aggregation/TermsAggregation.java       |  65 +++
 .../aggregation/TermsAggregationBuilder.java       |  87 ++++
 .../library/elasticsearch/response/Document.java}  |  19 +-
 .../library/elasticsearch/response/Documents.java} |  16 +-
 .../library/elasticsearch/response/Index.java}     |  12 +-
 .../elasticsearch/response/IndexTemplate.java}     |  17 +-
 .../library/elasticsearch/response/Mappings.java}  |  35 +-
 .../library/elasticsearch/response/NodeInfo.java}  |  14 +-
 .../elasticsearch/response/search/SearchHit.java}  |  40 +-
 .../elasticsearch/response/search/SearchHits.java  |  66 +++
 .../response/search/SearchResponse.java}           |  15 +-
 .../elasticsearch/ITElasticSearchClientTest.java   | 106 ++++
 oap-server/server-library/pom.xml                  |   3 +-
 .../pom.xml                                        |   2 +-
 .../discovery/AgentConfigurationsReader.java       |  12 +-
 .../discovery/AgentConfigurationsWatcher.java      |  12 +-
 oap-server/server-starter-es7/pom.xml              |  92 ----
 .../src/main/assembly/assembly.xml                 |  33 --
 oap-server/server-storage-plugin/pom.xml           |   3 +-
 .../storage-elasticsearch-plugin/pom.xml           |   8 +-
 .../StorageModuleElasticsearchProvider.java        |  10 +-
 .../elasticsearch/base/BatchProcessEsDAO.java      |  12 +-
 .../storage/plugin/elasticsearch/base/EsDAO.java   |  22 -
 .../elasticsearch/base/HistoryDeleteEsDAO.java     |   5 +-
 .../plugin/elasticsearch/base/IndexStructures.java | 109 ++--
 .../plugin/elasticsearch/base/ManagementEsDAO.java |  16 +-
 .../plugin/elasticsearch/base/MetricsEsDAO.java    |  23 +-
 .../plugin/elasticsearch/base/NoneStreamEsDAO.java |   7 +-
 .../plugin/elasticsearch/base/RecordEsDAO.java     |   6 +-
 .../elasticsearch/base/StorageEsInstaller.java     |  36 +-
 .../cache/NetworkAddressAliasEsDAO.java            |  25 +-
 .../elasticsearch/query/AggregationQueryEsDAO.java | 109 ++--
 .../elasticsearch/query/AlarmQueryEsDAO.java       |  51 +-
 .../elasticsearch/query/BrowserLogQueryEsDAO.java  |  55 +-
 .../elasticsearch/query/ESEventQueryDAO.java       | 139 +++---
 .../plugin/elasticsearch/query/LogQueryEsDAO.java  |  90 ++--
 .../elasticsearch/query/MetadataQueryEsDAO.java    | 165 +++---
 .../elasticsearch/query/MetricsQueryEsDAO.java     | 191 +++----
 .../elasticsearch/query/ProfileTaskLogEsDAO.java   |  40 +-
 .../elasticsearch/query/ProfileTaskQueryEsDAO.java |  91 ++--
 .../query/ProfileThreadSnapshotQueryEsDAO.java     | 216 ++++----
 .../elasticsearch/query/TopNRecordsQueryEsDAO.java |  50 +-
 .../elasticsearch/query/TopologyQueryEsDAO.java    | 287 ++++++-----
 .../elasticsearch/query/TraceQueryEsDAO.java       | 109 ++--
 .../query/UITemplateManagementEsDAO.java           |  82 +--
 .../elasticsearch/base/IndexStructuresTest.java    |  87 +++-
 .../elasticsearch/base/TimeSeriesUtilsTest.java    |   2 +-
 .../storage-elasticsearch7-plugin/pom.xml          |  53 --
 .../StorageModuleElasticsearch7Provider.java       | 240 ---------
 .../elasticsearch7/base/StorageEs7Installer.java   |  40 --
 .../client/ElasticSearch7Client.java               | 429 ----------------
 .../plugin/elasticsearch7/dao/MetricsEs7DAO.java   |  31 --
 .../plugin/elasticsearch7/dao/StorageEs7DAO.java   |  63 ---
 .../query/AggregationQueryEs7DAO.java              | 120 -----
 .../elasticsearch7/query/AlarmQueryEs7DAO.java     | 107 ----
 .../query/BrowserLogQueryEs7DAO.java               |  96 ----
 .../elasticsearch7/query/ES7EventQueryDAO.java     |  62 ---
 .../elasticsearch7/query/LogQueryEs7DAO.java       | 165 ------
 .../elasticsearch7/query/MetricsQueryEs7DAO.java   | 102 ----
 .../query/ProfileThreadSnapshotQueryEs7DAO.java    |  48 --
 .../elasticsearch7/query/TraceQueryEs7DAO.java     | 151 ------
 ...alking.oap.server.library.module.ModuleProvider |  19 -
 .../storage/plugin/influxdb/query/AlarmQuery.java  |   5 +-
 .../storage/plugin/influxdb/query/LogQuery.java    |   2 +-
 .../influxdb/query/ProfileThreadSnapshotQuery.java |   2 +-
 .../storage/plugin/influxdb/query/TraceQuery.java  |   2 +-
 .../plugin/jdbc/h2/dao/H2AlarmQueryDAO.java        |  21 +-
 .../storage/plugin/jdbc/h2/dao/H2LogQueryDAO.java  |   3 +-
 .../h2/dao/H2ProfileThreadSnapshotQueryDAO.java    |   6 +-
 .../plugin/jdbc/h2/dao/H2TraceQueryDAO.java        |   5 +-
 .../storage-zipkin-elasticsearch7-plugin/pom.xml   |  13 +-
 .../ZipkinStorageModuleElasticsearchProvider.java  |   7 +-
 .../elasticsearch/ZipkinTraceQueryEs7DAO.java      |  79 ++-
 .../tool-profile-snapshot-exporter-es7/pom.xml     |   9 +-
 pom.xml                                            |   4 -
 .../e2e-test/docker/alarm/docker-compose.es7.yml   |   2 +-
 test/e2e/e2e-test/docker/base-compose.yml          |  22 -
 .../e2e-test/docker/browser/docker-compose.es7.yml |   4 +-
 .../docker/cluster/docker-compose.zk.es7.yml       |   4 +-
 .../e2e-test/docker/event/docker-compose.es7.0.yml |   2 +-
 .../e2e-test/docker/log/docker-compose.es7.14.yml  |   2 +-
 .../e2e/e2e-test/docker/log/docker-compose.es7.yml |   2 +-
 .../e2e-test/docker/profile/docker-compose.es7.yml |   2 +-
 .../docker/storage/docker-compose.es7.0.yml        |   2 +-
 .../docker/storage/docker-compose.es7.10.yml       |   2 +-
 .../docker/storage/docker-compose.es7.14.yml       |   2 +-
 .../docker/storage/docker-compose.opensearch.yml   |   2 +-
 .../e2e/e2e-test/docker/ttl/docker-compose.es7.yml |   2 +-
 tools/dependencies/check-LICENSE.sh                |  15 +-
 .../known-oap-backend-dependencies-es7.txt         | 174 -------
 .../known-oap-backend-dependencies.txt             |  10 -
 186 files changed, 6145 insertions(+), 4551 deletions(-)

diff --git a/.github/workflows/e2e.istio.yaml b/.github/workflows/e2e.istio.yaml
index 004db04..820dafe 100644
--- a/.github/workflows/e2e.istio.yaml
+++ b/.github/workflows/e2e.istio.yaml
@@ -103,7 +103,7 @@ jobs:
                --set ui.image.tag=$TAG \
                --set oap.image.tag=$TAG \
                --set oap.image.repository=skywalking/oap \
-               --set oap.storageType=elasticsearch7
+               --set oap.storageType=elasticsearch
           kubectl -n istio-system get pods
 
           sleep 3
@@ -233,7 +233,7 @@ jobs:
                --set ui.image.tag=$TAG \
                --set oap.image.tag=$TAG \
                --set oap.image.repository=skywalking/oap \
-               --set oap.storageType=elasticsearch7
+               --set oap.storageType=elasticsearch
           kubectl -n istio-system get pods
 
           sleep 3
diff --git a/Makefile b/Makefile
index c870429..51f13ca 100644
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,7 @@ export SW_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
 export SW_OUT:=${SW_ROOT}/dist
 
 SKIP_TEST?=false
+DIST_NAME := apache-skywalking-apm-bin
 
 init:
 	cd $(SW_ROOT) && git submodule update --init --recursive
@@ -42,8 +43,6 @@ HUB?=skywalking
 
 TAG?=latest
 
-ES_VERSION?=es6
-
 .SECONDEXPANSION: #allow $@ to be used in dependency list
 
 .PHONY: docker docker.all docker.oap
@@ -54,12 +53,6 @@ DOCKER_TARGETS:=docker.oap docker.ui
 
 docker.all: $(DOCKER_TARGETS)
 
-ifeq ($(ES_VERSION),es7)
-  DIST_NAME := apache-skywalking-apm-bin-es7
-else
-  DIST_NAME := apache-skywalking-apm-bin
-endif
-
 ifneq ($(SW_OAP_BASE_IMAGE),)
   BUILD_ARGS := $(BUILD_ARGS) --build-arg BASE_IMAGE=$(SW_OAP_BASE_IMAGE)
 endif
diff --git a/apm-dist-es7/pom.xml b/apm-dist-es7/pom.xml
deleted file mode 100644
index 955b1c5..0000000
--- a/apm-dist-es7/pom.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>apm</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>8.8.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>apache-skywalking-apm-es7</artifactId>
-    <packaging>pom</packaging>
-
-    <profiles>
-        <profile>
-            <id>backend</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.apache.skywalking</groupId>
-                    <artifactId>server-starter-es7</artifactId>
-                    <version>${project.version}</version>
-                </dependency>
-            </dependencies>
-        </profile>
-        <profile>
-            <id>ui</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.apache.skywalking</groupId>
-                    <artifactId>apm-webapp</artifactId>
-                    <version>${project.version}</version>
-                </dependency>
-            </dependencies>
-        </profile>
-    </profiles>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>dist-es7</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <configuration>
-                            <finalName>apache-skywalking-apm-bin-es7</finalName>
-                            <descriptors>
-                                <descriptor>${project.basedir}/src/main/assembly/binary-es7.xml</descriptor>
-                            </descriptors>
-                        </configuration>
-                    </execution>
-                </executions>
-                <configuration>
-                    <attach>true</attach>
-                    <tarLongFileMode>posix</tarLongFileMode>
-                    <runOnlyAtExecutionRoot>false</runOnlyAtExecutionRoot>
-                    <appendAssemblyId>false</appendAssemblyId>
-                </configuration>
-            </plugin>
-            <plugin>
-                <artifactId>maven-antrun-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>dist-es7</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>run</goal>
-                        </goals>
-                        <configuration>
-                            <target>
-                                <copy file="${project.build.directory}/apache-skywalking-apm-bin-es7.tar.gz" tofile="${project.basedir}/../dist/apache-skywalking-apm-bin-es7.tar.gz" overwrite="true" />
-                            </target>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/apm-dist-es7/src/main/assembly/binary-es7.xml b/apm-dist-es7/src/main/assembly/binary-es7.xml
deleted file mode 100644
index d19cb1d..0000000
--- a/apm-dist-es7/src/main/assembly/binary-es7.xml
+++ /dev/null
@@ -1,103 +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.
-  ~
-  -->
-
-<assembly
-        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
-    <id>dist</id>
-    <formats>
-        <format>tar.gz</format>
-    </formats>
-    <fileSets>
-        <fileSet>
-            <directory>${project.basedir}/../dist-material/bin</directory>
-            <outputDirectory>bin</outputDirectory>
-            <includes>
-                <include>*.sh</include>
-                <include>*.bat</include>
-            </includes>
-            <fileMode>0755</fileMode>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/../dist-material</directory>
-            <outputDirectory>config</outputDirectory>
-            <includes>
-                <include>log4j2.xml</include>
-                <include>alarm-settings.yml</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/../dist-material</directory>
-            <outputDirectory/>
-            <includes>
-                <include>config-examples/*</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/../oap-server/server-bootstrap/src/main/resources</directory>
-            <includes>
-                <include>application.yml</include>
-                <include>component-libraries.yml</include>
-                <include>gateways.yml</include>
-                <include>service-apdex-threshold.yml</include>
-                <include>endpoint-name-grouping.yml</include>
-                <include>metadata-service-mapping.yaml</include>
-                <include>trace-sampling-policy-settings.yml</include>
-                <include>oal/*.oal</include>
-                <include>fetcher-prom-rules/*.yaml</include>
-                <include>envoy-metrics-rules/*.yaml</include>
-                <include>meter-analyzer-config/*.yaml</include>
-                <include>zabbix-rules/*.yaml</include>
-                <include>openapi-definitions/*</include>
-                <include>otel-oc-rules/*</include>
-                <include>ui-initialized-templates/*</include>
-                <include>lal/*</include>
-                <include>log-mal-rules/*</include>
-            </includes>
-            <outputDirectory>config</outputDirectory>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/../oap-server/server-starter-es7/target/skywalking-oap-assembly/skywalking-oap/libs</directory>
-            <outputDirectory>oap-libs</outputDirectory>
-        </fileSet>
-
-        <!-- Profile exporter tools -->
-        <fileSet>
-            <directory>${project.basedir}/../tools/profile-exporter</directory>
-            <outputDirectory>tools/profile-exporter</outputDirectory>
-        </fileSet>
-
-        <fileSet>
-            <directory>${project.basedir}/../dist-material/release-docs</directory>
-            <outputDirectory/>
-        </fileSet>
-    </fileSets>
-    <files>
-        <file>
-            <source>${project.basedir}/../apm-webapp/target/skywalking-webapp.jar</source>
-            <outputDirectory>webapp</outputDirectory>
-            <fileMode>0644</fileMode>
-        </file>
-        <file>
-            <source>${project.basedir}/../apm-webapp/src/main/assembly/webapp.yml</source>
-            <outputDirectory>webapp</outputDirectory>
-            <fileMode>0644</fileMode>
-        </file>
-    </files>
-</assembly>
diff --git a/dist-material/release-docs/LICENSE b/dist-material/release-docs/LICENSE
index 97c7696..733b380 100755
--- a/dist-material/release-docs/LICENSE
+++ b/dist-material/release-docs/LICENSE
@@ -233,19 +233,6 @@ The text of each license is the standard Apache 2.0 license.
     Google: proto-google-common-protos 1.17.0: https://github.com/googleapis/googleapis , Apache 2.0
     Google: jsr305 3.0.2: http://central.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.0/jsr305-3.0.0.pom , Apache 2.0
     Google: flatbuffers-java 1.12.0: https://github.com/google/flatbuffers/ , Apache 2.0
-    Elasticsearch BV (Elasticsearch) 6.3.2: https://www.elastic.co/products/elasticsearch , Apache 2.0
-    Elasticsearch BV (Elasticsearch) 7.5.0: https://www.elastic.co/products/elasticsearch , Apache 2.0
-    aggs-matrix-stats-client 6.3.2, 7.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/aggs-matrix-stats Apache 2.0
-    lang-mustache-client 7.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/lang-mustache Apache 2.0
-    mapper-extras-client 7.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/mapper-extras Apache 2.0
-    parent-join-client 6.3.2, 7.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/parent-join , Apache 2.0
-    rank-eval-client 6.3.2, 7.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/rank-eval , Apache 2.0
-    reindex-client 5.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/reindex , Apache 2.0
-    percolator-client 5.5.0: https://github.com/elastic/elasticsearch/tree/master/modules/percolator , Apache 2.0
-    rest 5.5.0: https://github.com/elastic/elasticsearch/tree/master/client/rest , Apache 2.0
-    transport 5.5.0: https://github.com/elastic/elasticsearch/tree/master/client/transport , Apache 2.0
-    securesm 1.1: https://github.com/elastic/securesm/blob/master/pom.xml , Apache 2.0
-    LMAX Ltd.(disruptor) 3.3.6: https://github.com/LMAX-Exchange/disruptor , Apache 2.0
     Eclipse (Jetty) 9.4.40.v20210413: https://www.eclipse.org/jetty/ , Apache 2.0 and Eclipse Public License 1.0
     SnakeYAML 1.28: http://www.snakeyaml.org , Apache 2.0
     Joda-Time 2.10.5: http://www.joda.org/joda-time/ , Apache 2.0
diff --git a/docker/README.md b/docker/README.md
index 00699ba..7708307 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -29,27 +29,6 @@ The hub of docker image. The default value is `skywalking`.
 
 The tag of docker image. The default value is `latest`.
 
-### ES_VERSION
-
-The elasticsearch version this image supports. The default value is `es6`, available values are `es6` and `es7`.
-
-
-For example, if we want to build images with a hub `foo.io` and a tag `bar`, and it supports elasticsearch 7 at the same time.
-We can issue the following commands.
-
-```
-export HUB=foo.io && export TAG=bar && export ES_VERSION=es7 && make docker
-```
-
-Let's check out the result:
-```
-docker image ls | grep foo.io
-foo.io/ui                                       bar                 a14db4e1d70d        9 minutes ago       800MB
-foo.io/oap                                      bar                 2a6084450b44        9 minutes ago       862MB
-```
-
-From the output, we can find out the building tool adopts the files stored in `oap-es7`.
-
 ## Running containers with docker-compose
 
 We can start up backend cluster by docker-compose
diff --git a/docker/oap/log4j2.xml b/docker/oap/log4j2.xml
index 06242e5..a699804 100644
--- a/docker/oap/log4j2.xml
+++ b/docker/oap/log4j2.xml
@@ -26,7 +26,6 @@
     <Loggers>
         <logger name="org.eclipse.jetty" level="INFO"/>
         <logger name="org.apache.zookeeper" level="INFO"/>
-        <logger name="org.elasticsearch.common.network.IfConfig" level="INFO"/>
         <logger name="io.grpc.netty" level="INFO"/>
         <logger name="org.apache.skywalking.oap.meter.analyzer" level="DEBUG"/>
         <logger name="org.apache.skywalking.oap.server.receiver.istio.telemetry" level="DEBUG"/>
diff --git a/docs/en/setup/envoy/examples/metrics/log4j2.xml b/docs/en/setup/envoy/examples/metrics/log4j2.xml
index 6c3774e..9525011 100644
--- a/docs/en/setup/envoy/examples/metrics/log4j2.xml
+++ b/docs/en/setup/envoy/examples/metrics/log4j2.xml
@@ -26,7 +26,6 @@
     <Loggers>
         <logger name="org.eclipse.jetty" level="INFO"/>
         <logger name="org.apache.zookeeper" level="INFO"/>
-        <logger name="org.elasticsearch.common.network.IfConfig" level="INFO"/>
         <logger name="io.grpc.netty" level="INFO"/>
         <logger name="org.apache.skywalking.oap.server.receiver.istio.telemetry" level="DEBUG"/>
         <!-- We make envoy metrics receiver to log at DEBUG level -->
diff --git a/oap-server-bom-es7/pom.xml b/oap-server-bom-es7/pom.xml
deleted file mode 100644
index f2de14f..0000000
--- a/oap-server-bom-es7/pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>apm</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>8.8.0-SNAPSHOT</version>
-    </parent>
-    <packaging>pom</packaging>
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>oap-server-bom-es7</artifactId>
-
-    <properties>
-        <elasticsearch.version>7.10.2</elasticsearch.version>
-    </properties>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.elasticsearch.client</groupId>
-                <artifactId>elasticsearch-rest-high-level-client</artifactId>
-                <version>${elasticsearch.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>commons-logging</groupId>
-                        <artifactId>commons-logging</artifactId>
-                    </exclusion>
-                </exclusions>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.skywalking</groupId>
-                <artifactId>oap-server-bom</artifactId>
-                <version>${project.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-</project>
diff --git a/oap-server-bom/pom.xml b/oap-server-bom/pom.xml
index 5b4e179..3808998 100644
--- a/oap-server-bom/pom.xml
+++ b/oap-server-bom/pom.xml
@@ -33,9 +33,9 @@
         <graphql-java-tools.version>5.2.3</graphql-java-tools.version>
         <graphql-java.version>8.0</graphql-java.version>
         <okhttp.version>3.14.9</okhttp.version>
+        <httpclient.version>4.5.3</httpclient.version>
         <h2.version>1.4.196</h2.version>
         <joda-time.version>2.10.5</joda-time.version>
-        <elasticsearch.version>6.3.2</elasticsearch.version>
         <zookeeper.version>3.5.7</zookeeper.version>
         <guava.version>28.1-jre</guava.version>
         <snakeyaml.version>1.28</snakeyaml.version>
@@ -72,7 +72,7 @@
         <flatbuffers-java.version>1.12.0</flatbuffers-java.version>
         <postgresql.version>42.2.18</postgresql.version>
         <jetcd.version>0.5.3</jetcd.version>
-        <testcontainers.version>1.15.3</testcontainers.version>
+        <testcontainers.version>1.16.0</testcontainers.version>
     </properties>
 
     <dependencyManagement>
@@ -140,17 +140,6 @@
                 <version>${joda-time.version}</version>
             </dependency>
             <dependency>
-                <groupId>org.elasticsearch.client</groupId>
-                <artifactId>elasticsearch-rest-high-level-client</artifactId>
-                <version>${elasticsearch.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>commons-logging</groupId>
-                        <artifactId>commons-logging</artifactId>
-                    </exclusion>
-                </exclusions>
-            </dependency>
-            <dependency>
                 <groupId>org.apache.zookeeper</groupId>
                 <artifactId>zookeeper</artifactId>
                 <version>${zookeeper.version}</version>
@@ -480,6 +469,12 @@
             </dependency>
 
             <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>${httpclient.version}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>com.google.flatbuffers</groupId>
                 <artifactId>flatbuffers-java</artifactId>
                 <version>${flatbuffers-java.version}</version>
@@ -497,6 +492,12 @@
                 <version>${testcontainers.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>org.testcontainers</groupId>
+                <artifactId>elasticsearch</artifactId>
+                <version>${testcontainers.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 </project>
diff --git a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
index 5364b0c..cd803e8 100644
--- a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
+++ b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
@@ -23,10 +23,15 @@ import io.vavr.Tuple;
 import io.vavr.Tuple2;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import lombok.AccessLevel;
 import lombok.RequiredArgsConstructor;
 import lombok.ToString;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.skywalking.oap.meter.analyzer.dsl.DSL;
 import org.apache.skywalking.oap.meter.analyzer.dsl.DownsamplingType;
 import org.apache.skywalking.oap.meter.analyzer.dsl.Expression;
@@ -50,12 +55,6 @@ import org.apache.skywalking.oap.server.core.analysis.meter.function.BucketedVal
 import org.apache.skywalking.oap.server.core.analysis.meter.function.PercentileArgument;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
-import org.elasticsearch.common.Strings;
-
-import java.util.Objects;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.groupingBy;
@@ -232,7 +231,7 @@ public class Analyzer {
                               final String dataType,
                               final DownsamplingType downsamplingType) {
         String functionName = String.format(
-            FUNCTION_NAME_TEMP, downsamplingType.toString().toLowerCase(), Strings.capitalize(dataType));
+            FUNCTION_NAME_TEMP, downsamplingType.toString().toLowerCase(), StringUtils.capitalize(dataType));
         meterSystem.create(metricName, functionName, scopeType);
     }
 
diff --git a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/MetricConvert.java b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/MetricConvert.java
index 599ef09..c7bec66 100644
--- a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/MetricConvert.java
+++ b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/MetricConvert.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.meter.analyzer;
 
 import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import io.vavr.control.Try;
 import java.util.List;
@@ -27,7 +28,6 @@ import java.util.stream.Stream;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.meter.analyzer.dsl.SampleFamily;
 import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
-import org.elasticsearch.common.Strings;
 
 import static java.util.stream.Collectors.toList;
 
@@ -51,7 +51,7 @@ public class MetricConvert {
         this.analyzers = rule.getMetricsRules().stream().map(
             r -> Analyzer.build(
                 formatMetricName(rule, r.getName()),
-                Strings.isEmpty(rule.getExpSuffix()) ?
+                Strings.isNullOrEmpty(rule.getExpSuffix()) ?
                     r.getExp() : String.format("(%s).%s", r.getExp(), rule.getExpSuffix()),
                 service
             )
diff --git a/oap-server/pom.xml b/oap-server/pom.xml
index 6318e02..c554f3c 100755
--- a/oap-server/pom.xml
+++ b/oap-server/pom.xml
@@ -35,7 +35,6 @@
         <module>server-storage-plugin</module>
         <module>server-library</module>
         <module>server-starter</module>
-        <module>server-starter-es7</module>
         <module>server-query-plugin</module>
         <module>server-alarm-plugin</module>
         <module>server-testing</module>
diff --git a/oap-server/server-alarm-plugin/pom.xml b/oap-server/server-alarm-plugin/pom.xml
index 45f7902..ac86ac6 100644
--- a/oap-server/server-alarm-plugin/pom.xml
+++ b/oap-server/server-alarm-plugin/pom.xml
@@ -51,6 +51,10 @@
             <groupId>org.mvel</groupId>
             <artifactId>mvel2</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
@@ -83,4 +87,4 @@
         </plugins>
     </build>
 
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-alarm-plugin/src/test/resources/log4j2-test.xml b/oap-server/server-alarm-plugin/src/test/resources/log4j2-test.xml
index b440b5e..e819176 100644
--- a/oap-server/server-alarm-plugin/src/test/resources/log4j2-test.xml
+++ b/oap-server/server-alarm-plugin/src/test/resources/log4j2-test.xml
@@ -26,7 +26,6 @@
     <Loggers>
         <logger name="org.eclipse.jetty" level="INFO"/>
         <logger name="org.apache.zookeeper" level="INFO"/>
-        <logger name="org.elasticsearch.common.network.IfConfig" level="INFO"/>
         <logger name="io.grpc.netty" level="INFO"/>
         <logger name="org.apache.skywalking.oap.server.core.alarm.provider" level="TRACE"/>
         <Root level="INFO">
diff --git a/oap-server/server-bootstrap/src/main/resources/log4j2.xml b/oap-server/server-bootstrap/src/main/resources/log4j2.xml
index 92c8884..ef141a1 100644
--- a/oap-server/server-bootstrap/src/main/resources/log4j2.xml
+++ b/oap-server/server-bootstrap/src/main/resources/log4j2.xml
@@ -26,8 +26,6 @@
     <Loggers>
         <logger name="org.eclipse.jetty" level="INFO"/>
         <logger name="org.apache.zookeeper" level="INFO"/>
-        <logger name="org.elasticsearch.common.network.IfConfig" level="INFO"/>
-        <logger name="org.elasticsearch.client.RestClient" level="INFO"/>
         <logger name="io.grpc.netty" level="INFO"/>
         <logger name="io.netty" level="INFO"/>
         <logger name="org.apache.http" level="INFO"/>
@@ -39,6 +37,7 @@
         <logger name="org.apache.skywalking.oap.server.library.buffer" level="INFO"/>
         <logger name="org.apache.skywalking.oap.server.receiver.envoy.MetricServiceGRPCHandler" level="INFO"/>
         <logger name="org.apache.skywalking.oap.meter.analyzer.prometheus.PrometheusMetricConverter" level="INFO"/>
+        <logger name="org.elasticsearch.client" level="TRACE"/>
         <Root level="DEBUG">
             <AppenderRef ref="Console"/>
         </Root>
diff --git a/oap-server/server-configuration/configuration-apollo/pom.xml b/oap-server/server-configuration/configuration-apollo/pom.xml
index 1dff076..9b4439f 100644
--- a/oap-server/server-configuration/configuration-apollo/pom.xml
+++ b/oap-server/server-configuration/configuration-apollo/pom.xml
@@ -54,6 +54,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java
index ebad19e..7a8d4a5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java
@@ -18,9 +18,16 @@
 
 package org.apache.skywalking.oap.server.core.storage.type;
 
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+
 /**
  * StorageDataComplexObject implementation supports String-Object interconversion.
  */
+@JsonSerialize(using = StorageDataComplexObject.Serializer.class)
 public interface StorageDataComplexObject<T> {
     /**
      * @return string representing this object.
@@ -36,4 +43,15 @@ public interface StorageDataComplexObject<T> {
      * Initialize the object based on the given source.
      */
     void copyFrom(T source);
+
+    final class Serializer extends JsonSerializer<StorageDataComplexObject<?>> {
+        @Override
+        public void serialize(
+            final StorageDataComplexObject value,
+            final JsonGenerator gen,
+            final SerializerProvider provider)
+            throws IOException {
+            gen.writeString(value.toStorageData());
+        }
+    }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/JettyServerTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/JettyServerTest.java
index 64d8132..be93963 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/JettyServerTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/remote/JettyServerTest.java
@@ -18,20 +18,9 @@
 
 package org.apache.skywalking.oap.server.core.remote;
 
-import java.io.IOException;
-import javax.servlet.ServletException;
+import com.linecorp.armeria.client.WebClient;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpOptions;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpTrace;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.skywalking.oap.server.library.server.jetty.JettyHandler;
 import org.apache.skywalking.oap.server.library.server.jetty.JettyServer;
 import org.apache.skywalking.oap.server.library.server.jetty.JettyServerConfig;
@@ -66,88 +55,62 @@ public class JettyServerTest {
     }
 
     @Test
-    public void test() {
+    public void test() throws Exception {
 
         String rootURI = "http://localhost:12800";
         String testHandlerURI = "http://localhost:12800/test";
         String testNoHandlerURI = "http://localhost:12800/test/noHandler";
-        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
-        HttpGet httpGet = new HttpGet(rootURI);
-        HttpPost httpPost = new HttpPost(rootURI);
-        HttpPost httpPostTestHandler = new HttpPost(testHandlerURI);
-        HttpPost httpPostTestNoHandler = new HttpPost(testNoHandlerURI);
-        HttpTrace httpTrace = new HttpTrace(testHandlerURI);
-        HttpTrace httpTraceRoot = new HttpTrace(rootURI);
-        HttpPut httpPut = new HttpPut(testHandlerURI);
-        HttpDelete httpDelete = new HttpDelete(testHandlerURI);
-        HttpOptions httpOptions = new HttpOptions(testHandlerURI);
-        HttpHead httpHead = new HttpHead(testHandlerURI);
-        CloseableHttpResponse response = null;
-        try {
-            //get
-            response = httpClient.execute(httpGet);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //post root
-            response = httpClient.execute(httpPost);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 404);
-            response.close();
-
-            //post
-            response = httpClient.execute(httpPostTestHandler);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 200);
-            response.close();
-
-            //post no handler
-            response = httpClient.execute(httpPostTestNoHandler);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 404);
-            response.close();
-
-            //trace
-            response = httpClient.execute(httpTrace);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //trace root
-            response = httpClient.execute(httpTraceRoot);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //put
-            response = httpClient.execute(httpPut);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //delete
-            response = httpClient.execute(httpDelete);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //options
-            response = httpClient.execute(httpOptions);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-
-            //head
-            response = httpClient.execute(httpHead);
-            Assert.assertEquals(response.getStatusLine().getStatusCode(), 405);
-            response.close();
-        } catch (IOException e) {
-            Assert.fail("Test failed!");
-            e.printStackTrace();
-        } finally {
-            try {
-                if (httpClient != null) {
-                    httpClient.close();
-                }
-                if (response != null) {
-                    response.close();
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
+
+        Assert.assertEquals(
+            WebClient.of().get(rootURI).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().post(rootURI, new byte[0]).aggregate().get().status().code(),
+            404
+        );
+
+        Assert.assertEquals(
+            WebClient.of().post(testHandlerURI, new byte[0]).aggregate().get().status().code(),
+            200
+        );
+
+        Assert.assertEquals(
+            WebClient.of().post(testNoHandlerURI, new byte[0]).aggregate().get().status()
+                     .code(),
+            404
+        );
+
+        Assert.assertEquals(
+            WebClient.of().trace(testNoHandlerURI).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().trace(rootURI).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().put(testHandlerURI, new byte[0]).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().delete(testHandlerURI).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().options(testHandlerURI).aggregate().get().status().code(),
+            405
+        );
+
+        Assert.assertEquals(
+            WebClient.of().head(testHandlerURI).aggregate().get().status().code(),
+            405
+        );
     }
 
     static class TestPostHandler extends JettyHandler {
@@ -159,7 +122,7 @@ public class JettyServerTest {
 
         @Override
         protected void doPost(final HttpServletRequest req,
-                              final HttpServletResponse resp) throws ServletException, IOException {
+                              final HttpServletResponse resp) {
             resp.setStatus(HttpServletResponse.SC_OK);
         }
 
diff --git a/oap-server/server-library/library-client/pom.xml b/oap-server/server-library/library-client/pom.xml
index d5c6b82..5bfef63 100755
--- a/oap-server/server-library/library-client/pom.xml
+++ b/oap-server/server-library/library-client/pom.xml
@@ -40,6 +40,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-elasticsearch-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>io.grpc</groupId>
             <artifactId>grpc-core</artifactId>
         </dependency>
@@ -72,110 +78,14 @@
             <artifactId>commons-dbcp</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.elasticsearch.client</groupId>
-            <artifactId>elasticsearch-rest-high-level-client</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
         </dependency>
-    </dependencies>
 
-    <profiles>
-        <profile>
-            <id>CI-with-IT</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>io.fabric8</groupId>
-                        <artifactId>docker-maven-plugin</artifactId>
-                        <configuration>
-                            <sourceMode>all</sourceMode>
-                            <logDate>default</logDate>
-                            <verbose>true</verbose>
-                            <imagePullPolicy>IfNotPresent</imagePullPolicy>
-                        </configuration>
-                        <executions>
-                            <execution>
-                                <id>prepare-elasticsearch</id>
-                                <phase>pre-integration-test</phase>
-                                <goals>
-                                    <goal>start</goal>
-                                </goals>
-                                <configuration>
-                                    <images>
-                                        <image>
-                                            <name>elastic/elasticsearch:${test.elasticsearch.version}</name>
-                                            <alias>elastic-client-integration-test</alias>
-                                            <run>
-                                                <ports>
-                                                    <port>es-port:9200</port>
-                                                </ports>
-                                                <wait>
-                                                    <log>started</log>
-                                                    <time>60000</time>
-                                                </wait>
-                                                <env>
-                                                    <discovery.type>single-node</discovery.type>
-                                                </env>
-                                            </run>
-                                        </image>
-                                    </images>
-                                </configuration>
-                            </execution>
-                            <execution>
-                                <id>remove-it-database</id>
-                                <phase>post-integration-test</phase>
-                                <goals>
-                                    <goal>stop</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <groupId>org.codehaus.gmaven</groupId>
-                        <artifactId>gmaven-plugin</artifactId>
-                        <version>${gmaven-plugin.version}</version>
-                        <executions>
-                            <execution>
-                                <id>add-default-properties</id>
-                                <phase>initialize</phase>
-                                <goals>
-                                    <goal>execute</goal>
-                                </goals>
-                                <configuration>
-                                    <providerSelection>2.0</providerSelection>
-                                    <source>
-                                        project.properties.setProperty('docker.hostname', 'localhost')
-                                    </source>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-failsafe-plugin</artifactId>
-                        <configuration>
-                            <systemPropertyVariables>
-                                <elastic.search.address>
-                                    ${docker.hostname}:${es-port}
-                                </elastic.search.address>
-                                <elastic.search.protocol>
-                                    http
-                                </elastic.search.protocol>
-                            </systemPropertyVariables>
-                        </configuration>
-                        <executions>
-                            <execution>
-                                <goals>
-                                    <goal>integration-test</goal>
-                                    <goal>verify</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchClient.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchClient.java
index 38e3af6..cb13e2d 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchClient.java
+++ b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchClient.java
@@ -18,86 +18,32 @@
 
 package org.apache.skywalking.oap.server.library.client.elasticsearch;
 
-import com.google.common.base.Splitter;
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.google.gson.reflect.TypeToken;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Type;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.util.ArrayList;
+import com.google.common.collect.ImmutableMap;
+import java.time.Duration;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.locks.ReentrantLock;
-import javax.net.ssl.SSLContext;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpStatus;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.entity.ContentType;
-import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.nio.entity.NStringEntity;
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.SSLContexts;
 import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.library.elasticsearch.bulk.BulkProcessor;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.response.Document;
+import org.apache.skywalking.library.elasticsearch.response.Documents;
+import org.apache.skywalking.library.elasticsearch.response.Index;
+import org.apache.skywalking.library.elasticsearch.response.IndexTemplate;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.library.client.Client;
 import org.apache.skywalking.oap.server.library.client.healthcheck.DelegatedHealthChecker;
 import org.apache.skywalking.oap.server.library.client.healthcheck.HealthCheckable;
-import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
-import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
 import org.apache.skywalking.oap.server.library.util.HealthChecker;
-import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
-import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
-import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
-import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
-import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
-import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
-import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
-import org.elasticsearch.action.bulk.BackoffPolicy;
-import org.elasticsearch.action.bulk.BulkProcessor;
-import org.elasticsearch.action.bulk.BulkRequest;
-import org.elasticsearch.action.bulk.BulkResponse;
-import org.elasticsearch.action.get.GetRequest;
-import org.elasticsearch.action.get.GetResponse;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.search.SearchRequest;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.support.ActiveShardCount;
-import org.elasticsearch.action.support.IndicesOptions;
-import org.elasticsearch.action.support.WriteRequest;
-import org.elasticsearch.client.Response;
-import org.elasticsearch.client.ResponseException;
-import org.elasticsearch.client.RestClient;
-import org.elasticsearch.client.RestClientBuilder;
-import org.elasticsearch.client.RestHighLevelClient;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 
 /**
  * ElasticSearchClient connects to the ES server by using ES client APIs.
@@ -106,22 +52,34 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
 @RequiredArgsConstructor
 public class ElasticSearchClient implements Client, HealthCheckable {
     public static final String TYPE = "type";
+
     protected final String clusterNodes;
+
     protected final String protocol;
+
     private final String trustStorePath;
+
     @Setter
     private volatile String trustStorePass;
+
     @Setter
     private volatile String user;
+
     @Setter
     private volatile String password;
+
     private final List<IndexNameConverter> indexNameConverters;
-    protected volatile RestHighLevelClient client;
+
     protected DelegatedHealthChecker healthChecker = new DelegatedHealthChecker();
+
     protected final ReentrantLock connectLock = new ReentrantLock();
+
     private final int connectTimeout;
+
     private final int socketTimeout;
 
+    org.apache.skywalking.library.elasticsearch.ElasticSearchClient esClient;
+
     public ElasticSearchClient(String clusterNodes,
                                String protocol,
                                String trustStorePath,
@@ -133,379 +91,201 @@ public class ElasticSearchClient implements Client, HealthCheckable {
                                int socketTimeout) {
         this.clusterNodes = clusterNodes;
         this.protocol = protocol;
+        this.trustStorePath = trustStorePath;
+        this.trustStorePass = trustStorePass;
         this.user = user;
         this.password = password;
         this.indexNameConverters = indexNameConverters;
-        this.trustStorePath = trustStorePath;
-        this.trustStorePass = trustStorePass;
         this.connectTimeout = connectTimeout;
         this.socketTimeout = socketTimeout;
     }
 
     @Override
-    public void connect() throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException {
+    public void connect() {
         connectLock.lock();
         try {
-            List<HttpHost> hosts = parseClusterNodes(protocol, clusterNodes);
-            if (client != null) {
+            if (esClient != null) {
                 try {
-                    client.close();
+                    esClient.close();
                 } catch (Throwable t) {
                     log.error("ElasticSearch client reconnection fails based on new config", t);
                 }
             }
-            client = createClient(hosts);
-            client.ping();
+            esClient = org.apache.skywalking.library.elasticsearch.ElasticSearchClient
+                .builder()
+                .endpoints(clusterNodes.split(","))
+                .protocol(protocol)
+                .trustStorePath(trustStorePath)
+                .trustStorePass(trustStorePass)
+                .username(user)
+                .password(password)
+                .connectTimeout(connectTimeout)
+                .build();
+            esClient.connect();
         } finally {
             connectLock.unlock();
         }
     }
 
-    protected RestHighLevelClient createClient(
-        final List<HttpHost> pairsList) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException {
-        RestClientBuilder builder;
-        if (StringUtil.isNotEmpty(user) && StringUtil.isNotEmpty(password)) {
-            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, password));
-
-            if (StringUtil.isEmpty(trustStorePath)) {
-                builder = RestClient.builder(pairsList.toArray(new HttpHost[0]))
-                                    .setHttpClientConfigCallback(
-                                        httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(
-                                            credentialsProvider));
-            } else {
-                KeyStore truststore = KeyStore.getInstance("jks");
-                try (InputStream is = Files.newInputStream(Paths.get(trustStorePath))) {
-                    truststore.load(is, trustStorePass.toCharArray());
-                }
-                SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
-                final SSLContext sslContext = sslBuilder.build();
-                builder = RestClient.builder(pairsList.toArray(new HttpHost[0]))
-                                    .setHttpClientConfigCallback(
-                                        httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(
-                                            credentialsProvider)
-                                                                              .setSSLContext(sslContext));
-            }
-        } else {
-            builder = RestClient.builder(pairsList.toArray(new HttpHost[0]));
-        }
-        builder.setRequestConfigCallback(
-            requestConfigBuilder -> requestConfigBuilder
-                .setConnectTimeout(connectTimeout)
-                .setSocketTimeout(socketTimeout)
-        );
-
-        return new RestHighLevelClient(builder);
-    }
-
     @Override
-    public void shutdown() throws IOException {
-        client.close();
+    public void shutdown() {
+        esClient.close();
     }
 
-    public static List<HttpHost> parseClusterNodes(String protocol, String nodes) {
-        List<HttpHost> httpHosts = new LinkedList<>();
-        log.info("elasticsearch cluster nodes: {}", nodes);
-        List<String> nodesSplit = Splitter.on(",").omitEmptyStrings().splitToList(nodes);
-
-        for (String node : nodesSplit) {
-            String host = node.split(":")[0];
-            String port = node.split(":")[1];
-            httpHosts.add(new HttpHost(host, Integer.parseInt(port), protocol));
-        }
-
-        return httpHosts;
+    public boolean createIndex(String indexName) {
+        return createIndex(indexName, null, null);
     }
 
-    public boolean createIndex(String indexName) throws IOException {
+    public boolean createIndex(String indexName,
+                               Mappings mappings,
+                               Map<String, ?> settings) {
         indexName = formatIndexName(indexName);
 
-        CreateIndexRequest request = new CreateIndexRequest(indexName);
-        CreateIndexResponse response = client.indices().create(request);
-        log.debug("create {} index finished, isAcknowledged: {}", indexName, response.isAcknowledged());
-        return response.isAcknowledged();
+        return esClient.index().create(indexName, mappings, settings);
     }
 
-    public boolean updateIndexMapping(String indexName, Map<String, Object> mapping) throws IOException {
+    public boolean updateIndexMapping(String indexName, Mappings mapping) {
         indexName = formatIndexName(indexName);
-        Map<String, Object> properties = (Map<String, Object>) mapping.get(ElasticSearchClient.TYPE);
-        PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
-        Gson gson = new Gson();
-        putMappingRequest.type(ElasticSearchClient.TYPE);
-        putMappingRequest.source(gson.toJson(properties), XContentType.JSON);
-        PutMappingResponse response = client.indices().putMapping(putMappingRequest);
-        log.debug("put {} index mapping finished, isAcknowledged: {}", indexName, response.isAcknowledged());
-        return response.isAcknowledged();
+
+        return esClient.index().putMapping(indexName, TYPE, mapping);
     }
 
-    public Map<String, Object> getIndex(String indexName) throws IOException {
+    public Optional<Index> getIndex(String indexName) {
         if (StringUtil.isBlank(indexName)) {
-            return new HashMap<>();
+            return Optional.empty();
         }
         indexName = formatIndexName(indexName);
         try {
-            Response response = client.getLowLevelClient()
-                                      .performRequest(HttpGet.METHOD_NAME, "/" + indexName);
-            int statusCode = response.getStatusLine().getStatusCode();
-            if (statusCode != HttpStatus.SC_OK) {
-                healthChecker.health();
-                throw new IOException(
-                    "The response status code of template exists request should be 200, but it is " + statusCode);
-            }
-            Type type = new TypeToken<HashMap<String, Object>>() {
-            }.getType();
-            Map<String, Object> templates = new Gson().<HashMap<String, Object>>fromJson(
-                new InputStreamReader(response.getEntity().getContent()),
-                type
-            );
-            return (Map<String, Object>) Optional.ofNullable(templates.get(indexName)).orElse(new HashMap<>());
-        } catch (ResponseException e) {
-            if (e.getResponse().getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
-                return new HashMap<>();
-            }
-            healthChecker.unHealth(e);
-            throw e;
-        } catch (IOException t) {
+            return esClient.index().get(indexName);
+        } catch (Exception t) {
             healthChecker.unHealth(t);
             throw t;
         }
     }
 
-    public boolean createIndex(String indexName, Map<String, Object> settings,
-                               Map<String, Object> mapping) throws IOException {
-        indexName = formatIndexName(indexName);
-        CreateIndexRequest request = new CreateIndexRequest(indexName);
-        Gson gson = new Gson();
-        request.settings(gson.toJson(settings), XContentType.JSON);
-        request.mapping(TYPE, gson.toJson(mapping), XContentType.JSON);
-        CreateIndexResponse response = client.indices().create(request);
-        log.debug("create {} index finished, isAcknowledged: {}", indexName, response.isAcknowledged());
-        return response.isAcknowledged();
-    }
-
-    public List<String> retrievalIndexByAliases(String aliases) throws IOException {
+    public Collection<String> retrievalIndexByAliases(String aliases) {
         aliases = formatIndexName(aliases);
-        Response response;
-        try {
-            response = client.getLowLevelClient().performRequest(HttpGet.METHOD_NAME, "/_alias/" + aliases);
-            healthChecker.health();
-        } catch (Throwable t) {
-            healthChecker.unHealth(t);
-            throw t;
-        }
-        if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
-            Gson gson = new Gson();
-            InputStreamReader reader;
-            try {
-                reader = new InputStreamReader(response.getEntity().getContent());
-            } catch (Throwable t) {
-                healthChecker.unHealth(t);
-                throw t;
-            }
-            JsonObject responseJson = gson.fromJson(reader, JsonObject.class);
-            log.debug("retrieval indexes by aliases {}, response is {}", aliases, responseJson);
-            return new ArrayList<>(responseJson.keySet());
-        }
-        return Collections.emptyList();
+
+        return esClient.alias().indices(aliases).keySet();
     }
 
     /**
-     * If your indexName is retrieved from elasticsearch through {@link #retrievalIndexByAliases(String)} or some other
-     * method and it already contains namespace. Then you should delete the index by this method, this method will no
-     * longer concatenate namespace.
+     * If your indexName is retrieved from elasticsearch through {@link
+     * #retrievalIndexByAliases(String)} or some other method and it already contains namespace.
+     * Then you should delete the index by this method, this method will no longer concatenate
+     * namespace.
      * <p>
      * https://github.com/apache/skywalking/pull/3017
      */
-    public boolean deleteByIndexName(String indexName) throws IOException {
+    public boolean deleteByIndexName(String indexName) {
         return deleteIndex(indexName, false);
     }
 
     /**
-     * If your indexName is obtained from metadata or configuration and without namespace. Then you should delete the
-     * index by this method, this method automatically concatenates namespace.
+     * If your indexName is obtained from metadata or configuration and without namespace. Then you
+     * should delete the index by this method, this method automatically concatenates namespace.
      * <p>
      * https://github.com/apache/skywalking/pull/3017
      */
-    public boolean deleteByModelName(String modelName) throws IOException {
+    public boolean deleteByModelName(String modelName) {
         return deleteIndex(modelName, true);
     }
 
-    protected boolean deleteIndex(String indexName, boolean formatIndexName) throws IOException {
+    protected boolean deleteIndex(String indexName, boolean formatIndexName) {
         if (formatIndexName) {
             indexName = formatIndexName(indexName);
         }
-        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
-        DeleteIndexResponse response;
-        response = client.indices().delete(request);
-        log.debug("delete {} index finished, isAcknowledged: {}", indexName, response.isAcknowledged());
-        return response.isAcknowledged();
+        return esClient.index().delete(indexName);
     }
 
-    public boolean isExistsIndex(String indexName) throws IOException {
+    public boolean isExistsIndex(String indexName) {
         indexName = formatIndexName(indexName);
-        GetIndexRequest request = new GetIndexRequest();
-        request.indices(indexName);
-        return client.indices().exists(request);
+
+        return esClient.index().exists(indexName);
     }
 
-    public Map<String, Object> getTemplate(String name) throws IOException {
+    public Optional<IndexTemplate> getTemplate(String name) {
         name = formatIndexName(name);
+
         try {
-            Response response = client.getLowLevelClient()
-                                      .performRequest(HttpGet.METHOD_NAME, "/_template/" + name);
-            int statusCode = response.getStatusLine().getStatusCode();
-            if (statusCode != HttpStatus.SC_OK) {
-                healthChecker.health();
-                throw new IOException(
-                    "The response status code of template exists request should be 200, but it is " + statusCode);
-            }
-            Type type = new TypeToken<HashMap<String, Object>>() {
-            }.getType();
-            Map<String, Object> templates = new Gson().<HashMap<String, Object>>fromJson(
-                new InputStreamReader(response.getEntity().getContent()),
-                type
-            );
-            if (templates.containsKey(name)) {
-                return (Map<String, Object>) templates.get(name);
-            }
-            return new HashMap<>();
-        } catch (ResponseException e) {
-            if (e.getResponse().getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
-                return new HashMap<>();
-            }
+            return esClient.templates().get(name);
+        } catch (Exception e) {
             healthChecker.unHealth(e);
             throw e;
-        } catch (IOException t) {
-            healthChecker.unHealth(t);
-            throw t;
         }
     }
 
-    public boolean isExistsTemplate(String indexName) throws IOException {
+    public boolean isExistsTemplate(String indexName) {
         indexName = formatIndexName(indexName);
 
-        Response response = client.getLowLevelClient().performRequest(HttpHead.METHOD_NAME, "/_template/" + indexName);
-
-        int statusCode = response.getStatusLine().getStatusCode();
-        if (statusCode == HttpStatus.SC_OK) {
-            return true;
-        } else if (statusCode == HttpStatus.SC_NOT_FOUND) {
-            return false;
-        } else {
-            throw new IOException(
-                "The response status code of template exists request should be 200 or 404, but it is " + statusCode);
-        }
+        return esClient.templates().exists(indexName);
     }
 
     public boolean createOrUpdateTemplate(String indexName, Map<String, Object> settings,
-                                          Map<String, Object> mapping, int order) throws IOException {
+                                          Mappings mapping, int order) {
         indexName = formatIndexName(indexName);
 
-        String[] patterns = new String[] {indexName + "-*"};
-
-        Map<String, Object> aliases = new HashMap<>();
-        aliases.put(indexName, new JsonObject());
-
-        Map<String, Object> template = new HashMap<>();
-        template.put("index_patterns", patterns);
-        template.put("aliases", aliases);
-        template.put("settings", settings);
-        template.put("mappings", mapping);
-        template.put("order", order);
-
-        HttpEntity entity = new NStringEntity(new Gson().toJson(template), ContentType.APPLICATION_JSON);
-
-        Response response = client.getLowLevelClient()
-                                  .performRequest(
-                                      HttpPut.METHOD_NAME, "/_template/" + indexName, Collections.emptyMap(), entity);
-        return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
+        return esClient.templates().createOrUpdate(indexName, settings, mapping, order);
     }
 
-    public boolean deleteTemplate(String indexName) throws IOException {
+    public boolean deleteTemplate(String indexName) {
         indexName = formatIndexName(indexName);
-        Response response = client.getLowLevelClient()
-                                  .performRequest(HttpDelete.METHOD_NAME, "/_template/" + indexName);
-        return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
+
+        return esClient.templates().delete(indexName);
     }
 
-    public SearchResponse search(IndexNameMaker indexNameMaker,
-                                 SearchSourceBuilder searchSourceBuilder) throws IOException {
-        String[] indexNames = Arrays.stream(indexNameMaker.make()).map(this::formatIndexName).toArray(String[]::new);
-        return doSearch(searchSourceBuilder, indexNames);
+    public SearchResponse search(IndexNameMaker indexNameMaker, Search search) {
+        final String[] indexNames =
+            Arrays.stream(indexNameMaker.make())
+                  .map(this::formatIndexName)
+                  .toArray(String[]::new);
+        return doSearch(search, indexNames);
     }
 
-    public SearchResponse search(String indexName, SearchSourceBuilder searchSourceBuilder) throws IOException {
+    public SearchResponse search(String indexName, Search search) {
         indexName = formatIndexName(indexName);
-        return doSearch(searchSourceBuilder, indexName);
+        return esClient.search(search, indexName);
+    }
+
+    protected SearchResponse doSearch(Search search, String... indexNames) {
+        return esClient.search(
+            search,
+            ImmutableMap.of(
+                "ignore_unavailable", true,
+                "allow_no_indices", true,
+                "expand_wildcards", "open"
+            ),
+            indexNames
+        );
     }
 
-    protected SearchResponse doSearch(SearchSourceBuilder searchSourceBuilder,
-                                      String... indexNames) throws IOException {
-        SearchRequest searchRequest = new SearchRequest(indexNames);
-        searchRequest.indicesOptions(IndicesOptions.fromOptions(true, true, true, false));
-        searchRequest.types(TYPE);
-        searchRequest.source(searchSourceBuilder);
-        try {
-            SearchResponse response = client.search(searchRequest);
-            healthChecker.health();
-            return response;
-        } catch (Throwable t) {
-            healthChecker.unHealth(t);
-            handleIOPoolStopped(t);
-            throw t;
-        }
-    }
+    public Optional<Document> get(String indexName, String id) {
+        indexName = formatIndexName(indexName);
 
-    protected void handleIOPoolStopped(Throwable t) throws IOException {
-        if (!(t instanceof IllegalStateException)) {
-            return;
-        }
-        IllegalStateException ise = (IllegalStateException) t;
-        // Fixed the issue described in https://github.com/elastic/elasticsearch/issues/39946
-        if (ise.getMessage().contains("I/O reactor status: STOPPED") &&
-            connectLock.tryLock()) {
-            try {
-                connect();
-            } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException | CertificateException e) {
-                throw new IllegalStateException("Can't reconnect to Elasticsearch", e);
-            }
-        }
+        return esClient.documents().get(indexName, TYPE, id);
     }
 
-    public GetResponse get(String indexName, String id) throws IOException {
+    public boolean existDoc(String indexName, String id) {
         indexName = formatIndexName(indexName);
-        GetRequest request = new GetRequest(indexName, TYPE, id);
-        try {
-            GetResponse response = client.get(request);
-            healthChecker.health();
-            return response;
-        } catch (Throwable t) {
-            healthChecker.unHealth(t);
-            throw t;
-        }
+
+        return esClient.documents().exists(indexName, TYPE, id);
     }
 
-    public SearchResponse ids(String indexName, String[] ids) throws IOException {
+    public Optional<Documents> ids(String indexName, Iterable<String> ids) {
         indexName = formatIndexName(indexName);
 
-        SearchRequest searchRequest = new SearchRequest(indexName);
-        searchRequest.types(TYPE);
-        searchRequest.source().query(QueryBuilders.idsQuery().addIds(ids)).size(ids.length);
-        try {
-            SearchResponse response = client.search(searchRequest);
-            healthChecker.health();
-            return response;
-        } catch (Throwable t) {
-            healthChecker.unHealth(t);
-            throw t;
-        }
+        return esClient.documents().mget(indexName, TYPE, ids);
     }
 
-    public void forceInsert(String indexName, String id, XContentBuilder source) throws IOException {
-        IndexRequest request = (IndexRequest) prepareInsert(indexName, id, source);
-        request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+    public Optional<Documents> ids(String indexName, String[] ids) {
+        return ids(indexName, Arrays.asList(ids));
+    }
+
+    public void forceInsert(String indexName, String id, Map<String, Object> source) {
+        IndexRequestWrapper wrapper = prepareInsert(indexName, id, source);
+        Map<String, Object> params = ImmutableMap.of("refresh", "true");
         try {
-            client.index(request);
+            esClient.documents().index(wrapper.getRequest(), params);
             healthChecker.health();
         } catch (Throwable t) {
             healthChecker.unHealth(t);
@@ -513,12 +293,11 @@ public class ElasticSearchClient implements Client, HealthCheckable {
         }
     }
 
-    public void forceUpdate(String indexName, String id, XContentBuilder source) throws IOException {
-        org.elasticsearch.action.update.UpdateRequest request = (org.elasticsearch.action.update.UpdateRequest) prepareUpdate(
-            indexName, id, source);
-        request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+    public void forceUpdate(String indexName, String id, Map<String, Object> source) {
+        UpdateRequestWrapper wrapper = prepareUpdate(indexName, id, source);
+        Map<String, Object> params = ImmutableMap.of("refresh", "true");
         try {
-            client.update(request);
+            esClient.documents().update(wrapper.getRequest(), params);
             healthChecker.health();
         } catch (Throwable t) {
             healthChecker.unHealth(t);
@@ -526,85 +305,34 @@ public class ElasticSearchClient implements Client, HealthCheckable {
         }
     }
 
-    public InsertRequest prepareInsert(String indexName, String id, XContentBuilder source) {
+    public IndexRequestWrapper prepareInsert(String indexName, String id,
+                                             Map<String, Object> source) {
         indexName = formatIndexName(indexName);
-        return new ElasticSearchInsertRequest(indexName, TYPE, id).source(source);
+        return new IndexRequestWrapper(indexName, TYPE, id, source);
     }
 
-    public UpdateRequest prepareUpdate(String indexName, String id, XContentBuilder source) {
+    public UpdateRequestWrapper prepareUpdate(String indexName, String id,
+                                              Map<String, Object> source) {
         indexName = formatIndexName(indexName);
-        return new ElasticSearchUpdateRequest(indexName, TYPE, id).doc(source);
+        return new UpdateRequestWrapper(indexName, TYPE, id, source);
     }
 
-    public int delete(String indexName, String timeBucketColumnName, long endTimeBucket) throws IOException {
+    public void delete(String indexName, String timeBucketColumnName, long endTimeBucket) {
         indexName = formatIndexName(indexName);
-        Map<String, String> params = Collections.singletonMap("conflicts", "proceed");
-        String jsonString = "{" + "  \"query\": {" + "    \"range\": {" + "      \"" + timeBucketColumnName + "\": {" + "        \"lte\": " + endTimeBucket + "      }" + "    }" + "  }" + "}";
-        HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
-        Response response = client.getLowLevelClient()
-                                  .performRequest(
-                                      HttpPost.METHOD_NAME, "/" + indexName + "/_delete_by_query", params, entity);
-        log.debug("delete indexName: {}, jsonString : {}", indexName, jsonString);
-        return response.getStatusLine().getStatusCode();
-    }
+        final Map<String, Object> params = Collections.singletonMap("conflicts", "proceed");
+        final Query query = Query.range(timeBucketColumnName).lte(endTimeBucket).build();
 
-    /**
-     * @since 8.7.0 SkyWalking don't use sync bulk anymore. This method is just kept for unexpected case in the future.
-     */
-    @Deprecated
-    public void synchronousBulk(BulkRequest request) {
-        request.timeout(TimeValue.timeValueMinutes(2));
-        request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
-        request.waitForActiveShards(ActiveShardCount.ONE);
-        try {
-            int size = request.requests().size();
-            BulkResponse responses = client.bulk(request);
-            log.info("Synchronous bulk took time: {} millis, size: {}", responses.getTook().getMillis(), size);
-            healthChecker.health();
-        } catch (Throwable t) {
-            healthChecker.unHealth(t);
-        }
-    }
-
-    public BulkProcessor createBulkProcessor(int bulkActions, int flushInterval, int concurrentRequests) {
-        BulkProcessor.Listener listener = createBulkListener();
-
-        return BulkProcessor.builder(client::bulkAsync, listener)
-                            .setBulkActions(bulkActions)
-                            .setFlushInterval(TimeValue.timeValueSeconds(flushInterval))
-                            .setConcurrentRequests(concurrentRequests)
-                            .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
-                            .build();
+        esClient.documents().delete(indexName, TYPE, query, params);
     }
 
-    protected BulkProcessor.Listener createBulkListener() {
-        return new BulkProcessor.Listener() {
-            @Override
-            public void beforeBulk(long executionId, BulkRequest request) {
-                int numberOfActions = request.numberOfActions();
-                log.debug("Executing bulk [{}] with {} requests", executionId, numberOfActions);
-            }
-
-            @Override
-            public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
-                if (response.hasFailures()) {
-                    log.warn("Bulk [{}] executed with failures:[{}]", executionId, response.buildFailureMessage());
-                } else {
-                    log.info(
-                        "Bulk execution id [{}] completed in {} milliseconds, size: {}", executionId, response.getTook()
-                                                                                                              .getMillis(),
-                        request
-                            .requests()
-                            .size()
-                    );
-                }
-            }
-
-            @Override
-            public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
-                log.error("Failed to execute bulk", failure);
-            }
-        };
+    public BulkProcessor createBulkProcessor(int bulkActions,
+                                             int flushInterval,
+                                             int concurrentRequests) {
+        return esClient.bulkProcessor()
+                       .bulkActions(bulkActions)
+                       .flushInterval(Duration.ofSeconds(flushInterval))
+                       .concurrentRequests(concurrentRequests)
+                       .build();
     }
 
     public String formatIndexName(String indexName) {
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchInsertRequest.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/IndexRequestWrapper.java
similarity index 61%
rename from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchInsertRequest.java
rename to oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/IndexRequestWrapper.java
index 9c0655c..3e2cbf7 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchInsertRequest.java
+++ b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/IndexRequestWrapper.java
@@ -17,19 +17,22 @@
 
 package org.apache.skywalking.oap.server.library.client.elasticsearch;
 
+import java.util.Map;
+import lombok.Getter;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
 
-public class ElasticSearchInsertRequest extends IndexRequest implements InsertRequest {
+@Getter
+public class IndexRequestWrapper implements InsertRequest {
+    private final IndexRequest request;
 
-    public ElasticSearchInsertRequest(String index, String type, String id) {
-        super(index, type, id);
-    }
-
-    @Override
-    public ElasticSearchInsertRequest source(XContentBuilder sourceBuilder) {
-        super.source(sourceBuilder);
-        return this;
+    public IndexRequestWrapper(String index, String type, String id,
+                               Map<String, ?> source) {
+        request = IndexRequest.builder()
+                              .index(index)
+                              .type(type)
+                              .id(id)
+                              .doc(source)
+                              .build();
     }
 }
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/UpdateRequestWrapper.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/UpdateRequestWrapper.java
new file mode 100644
index 0000000..3241aa8
--- /dev/null
+++ b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/UpdateRequestWrapper.java
@@ -0,0 +1,37 @@
+/*
+ * 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.skywalking.oap.server.library.client.elasticsearch;
+
+import java.util.Map;
+import lombok.Getter;
+import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
+
+@Getter
+public class UpdateRequestWrapper implements UpdateRequest {
+    private final org.apache.skywalking.library.elasticsearch.requests.UpdateRequest request;
+
+    public UpdateRequestWrapper(String index, String type, String id,
+                                Map<String, Object> source) {
+        request = org.apache.skywalking.library.elasticsearch.requests.UpdateRequest.builder()
+                                                                                    .index(index)
+                                                                                    .type(type)
+                                                                                    .id(id)
+                                                                                    .doc(source)
+                                                                                    .build();
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClient.java b/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClient.java
index ae9a9a2..1ce392a 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClient.java
+++ b/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClient.java
@@ -18,58 +18,69 @@
 
 package org.apache.skywalking.oap.server.library.client.elasticsearch;
 
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
+import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import org.apache.http.client.methods.HttpGet;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.util.StringUtil;
-import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
-import org.elasticsearch.action.bulk.BulkProcessor;
-import org.elasticsearch.action.get.GetResponse;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.client.Response;
-import org.elasticsearch.client.RestHighLevelClient;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.apache.skywalking.library.elasticsearch.bulk.BulkProcessor;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.response.Document;
+import org.apache.skywalking.library.elasticsearch.response.Index;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.powermock.reflect.Whitebox;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.utility.DockerImageName;
+
+@Slf4j
+@RequiredArgsConstructor
+@RunWith(Parameterized.class)
 public class ITElasticSearchClient {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(ITElasticSearchClient.class);
-
-    private ElasticSearchClient client;
+    @Parameterized.Parameters(name = "version: {0}, namespace: {1}")
+    public static Collection<Object[]> versions() {
+        return Arrays.asList(new Object[][] {
+            {"6.3.2", ""},
+            {"6.3.2", "test"},
+            {"7.8.0", ""},
+            {"7.8.0", "test"}
+        });
+    }
 
+    private final String version;
     private final String namespace;
 
-    public ITElasticSearchClient() {
-        namespace = "default-test-namespace";
-    }
+    private ElasticsearchContainer server;
 
-    protected ITElasticSearchClient(String namespace) {
-        this.namespace = namespace;
-    }
+    private ElasticSearchClient client;
 
     @Before
     public void before() throws Exception {
-        final String esAddress = System.getProperty("elastic.search.address");
-        final String esProtocol = System.getProperty("elastic.search.protocol");
-        client = new ElasticSearchClient(esAddress, esProtocol, "", "", "test", "test",
-                                         indexNameConverters(namespace), 500, 6000
+        server = new ElasticsearchContainer(
+            DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch-oss")
+                           .withTag(version)
+        );
+        server.start();
+
+        client = new ElasticSearchClient(
+            server.getHttpHostAddress(),
+            "http", "", "", "test", "test",
+            indexNameConverters(namespace), 500, 6000
         );
         client.connect();
     }
@@ -77,130 +88,125 @@ public class ITElasticSearchClient {
     @After
     public void after() throws IOException {
         client.shutdown();
+        server.stop();
     }
 
     @Test
-    public void indexOperate() throws IOException {
+    public void indexOperate() {
         Map<String, Object> settings = new HashMap<>();
         settings.put("number_of_shards", 2);
         settings.put("number_of_replicas", 2);
 
-        Map<String, Object> doc = new HashMap<>();
-
-        JsonObject properties = new JsonObject();
-        doc.put("properties", properties);
-
-        JsonObject column = new JsonObject();
-        column.addProperty("type", "text");
-        properties.add("column1", column);
+        final Mappings mappings =
+            Mappings.builder()
+                    .type("type")
+                    .properties(ImmutableMap.of(
+                        "column1",
+                        ImmutableMap.of("type", "text")
+                    ))
+                    .build();
 
         String indexName = "test_index_operate";
-        client.createIndex(indexName, settings, doc);
+        client.createIndex(indexName, mappings, settings);
         Assert.assertTrue(client.isExistsIndex(indexName));
 
-        JsonObject index = getIndex(indexName);
-        LOGGER.info(index.toString());
-
-        Assert.assertEquals(2, index.getAsJsonObject(indexName)
-                                    .getAsJsonObject("settings")
-                                    .getAsJsonObject("index")
-                                    .get("number_of_shards")
-                                    .getAsInt());
-        Assert.assertEquals(2, index.getAsJsonObject(indexName)
-                                    .getAsJsonObject("settings")
-                                    .getAsJsonObject("index")
-                                    .get("number_of_replicas")
-                                    .getAsInt());
-
-        Assert.assertEquals("text", index.getAsJsonObject(indexName)
-                                         .getAsJsonObject("mappings")
-                                         .getAsJsonObject("type")
-                                         .getAsJsonObject("properties")
-                                         .getAsJsonObject("column1")
-                                         .get("type")
-                                         .getAsString());
+        Index index = client.getIndex(indexName).get();
+        log.info(index.toString());
+
+        Assert.assertEquals(
+            "2",
+            ((Map<String, ?>) index.getSettings().get("index")).get("number_of_shards")
+        );
+        Assert.assertEquals(
+            "2",
+            ((Map<String, ?>) index.getSettings().get("index")).get("number_of_replicas")
+        );
+
+        Assert.assertEquals(
+            "text",
+            ((Map<String, ?>) index.getMappings().getProperties().get("column1")).get("type")
+        );
 
         Assert.assertTrue(client.deleteByModelName(indexName));
     }
 
     @Test
-    public void documentOperate() throws IOException {
+    public void documentOperate() {
         String id = String.valueOf(System.currentTimeMillis());
 
-        XContentBuilder builder = XContentFactory.jsonBuilder()
-                                                 .startObject()
-                                                 .field("user", "kimchy")
-                                                 .field("post_date", "2009-11-15T14:12:12")
-                                                 .field("message", "trying out Elasticsearch")
-                                                 .endObject();
+        Map<String, Object> builder = ImmutableMap.<String, Object>builder()
+                                                  .put("user", "kimchy")
+                                                  .put("post_date", "2009-11-15T14:12:12")
+                                                  .put("message", "trying out Elasticsearch")
+                                                  .build();
 
         String indexName = "test_document_operate";
         client.forceInsert(indexName, id, builder);
 
-        GetResponse response = client.get(indexName, id);
-        Assert.assertEquals("kimchy", response.getSource().get("user"));
-        Assert.assertEquals("trying out Elasticsearch", response.getSource().get("message"));
+        Optional<Document> response = client.get(indexName, id);
+        Assert.assertEquals("kimchy", response.get().getSource().get("user"));
+        Assert.assertEquals("trying out Elasticsearch", response.get().getSource().get("message"));
 
-        builder = XContentFactory.jsonBuilder().startObject().field("user", "pengys").endObject();
+        builder = ImmutableMap.<String, Object>builder().put("user", "pengys").build();
         client.forceUpdate(indexName, id, builder);
 
         response = client.get(indexName, id);
-        Assert.assertEquals("pengys", response.getSource().get("user"));
-        Assert.assertEquals("trying out Elasticsearch", response.getSource().get("message"));
-
-        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
-        sourceBuilder.query(QueryBuilders.termQuery("user", "pengys"));
-        SearchResponse searchResponse = client.search(indexName, sourceBuilder);
-        Assert.assertEquals("trying out Elasticsearch", searchResponse.getHits().getHits()[0].getSourceAsMap()
-                                                                                             .get("message"));
+        Assert.assertEquals("pengys", response.get().getSource().get("user"));
+        Assert.assertEquals("trying out Elasticsearch", response.get().getSource().get("message"));
+
+        SearchBuilder sourceBuilder = Search.builder();
+        sourceBuilder.query(Query.term("user", "pengys"));
+        SearchResponse searchResponse = client.search(indexName, sourceBuilder.build());
+        Assert.assertEquals("trying out Elasticsearch", searchResponse.getHits()
+                                                                      .getHits()
+                                                                      .iterator()
+                                                                      .next()
+                                                                      .getSource()
+                                                                      .get("message"));
     }
 
     @Test
-    public void templateOperate() throws IOException {
+    public void templateOperate() {
         Map<String, Object> settings = new HashMap<>();
         settings.put("number_of_shards", 1);
         settings.put("number_of_replicas", 0);
         settings.put("index.refresh_interval", "3s");
         settings.put("analysis.analyzer.oap_analyzer.type", "stop");
 
-        Map<String, Object> mapping = new HashMap<>();
-        Map<String, Object> doc = new HashMap<>();
-        mapping.put("type", doc);
-
-        JsonObject properties = new JsonObject();
-        doc.put("properties", properties);
-
-        JsonObject column = new JsonObject();
-        column.addProperty("type", "text");
-        properties.add("name", column);
-
+        Mappings mapping =
+            Mappings.builder()
+                    .type("type")
+                    .properties(
+                        ImmutableMap.of(
+                            "name", ImmutableMap.of("type", "text")
+                        )
+                    )
+                    .build();
         String indexName = "template_operate";
 
         client.createOrUpdateTemplate(indexName, settings, mapping, 0);
 
         Assert.assertTrue(client.isExistsTemplate(indexName));
 
-        XContentBuilder builder = XContentFactory.jsonBuilder().startObject().field("name", "pengys").endObject();
+        Map<String, Object> builder = ImmutableMap.of("name", "pengys");
         client.forceInsert(indexName + "-2019", "testid", builder);
-        JsonObject index = getIndex(indexName + "-2019");
-        LOGGER.info(index.toString());
-
-        Assert.assertEquals(1, index.getAsJsonObject(indexName + "-2019")
-                                    .getAsJsonObject("settings")
-                                    .getAsJsonObject("index")
-                                    .get("number_of_shards")
-                                    .getAsInt());
-        Assert.assertEquals(0, index.getAsJsonObject(indexName + "-2019")
-                                    .getAsJsonObject("settings")
-                                    .getAsJsonObject("index")
-                                    .get("number_of_replicas")
-                                    .getAsInt());
+        Index index = client.getIndex(indexName + "-2019").get();
+        log.info(index.toString());
+
+        Assert.assertEquals(
+            "1",
+            ((Map<String, Object>) index.getSettings().get("index")).get("number_of_shards")
+        );
+        Assert.assertEquals(
+            "0",
+            ((Map<String, ?>) index.getSettings().get("index")).get("number_of_replicas")
+        );
         client.deleteTemplate(indexName);
         Assert.assertFalse(client.isExistsTemplate(indexName));
     }
 
     @Test
-    public void bulk() throws InterruptedException {
+    public void bulk() {
         BulkProcessor bulkProcessor = client.createBulkProcessor(2000, 10, 2);
 
         Map<String, String> source = new HashMap<>();
@@ -208,80 +214,38 @@ public class ITElasticSearchClient {
         source.put("column2", "value2");
 
         for (int i = 0; i < 100; i++) {
-            IndexRequest indexRequest = new IndexRequest("bulk_insert_test", "type", String.valueOf(i));
-            indexRequest.source(source);
-            bulkProcessor.add(indexRequest);
+            IndexRequestWrapper
+                indexRequest =
+                new IndexRequestWrapper("bulk_insert_test", "type", String.valueOf(i), source);
+            bulkProcessor.add(indexRequest.getRequest());
         }
 
         bulkProcessor.flush();
-        bulkProcessor.awaitClose(2, TimeUnit.SECONDS);
     }
 
     @Test
-    public void timeSeriesOperate() throws IOException {
-        String indexName = "test_time_series_operate";
-        String timeSeriesIndexName = indexName + "-2019";
-
-        Map<String, Object> mapping = new HashMap<>();
-        Map<String, Object> doc = new HashMap<>();
-        mapping.put("type", doc);
-
-        JsonObject properties = new JsonObject();
-        doc.put("properties", properties);
-
-        JsonObject column = new JsonObject();
-        column.addProperty("type", "text");
-        properties.add("name", column);
+    public void timeSeriesOperate() {
+        final String indexName = "test_time_series_operate";
+        final String timeSeriesIndexName = indexName + "-2019";
+        final Mappings mapping =
+            Mappings.builder()
+                    .type("type")
+                    .properties(ImmutableMap.of("name", ImmutableMap.of("type", "text")))
+                    .build();
 
         client.createOrUpdateTemplate(indexName, new HashMap<>(), mapping, 0);
 
-        XContentBuilder builder = XContentFactory.jsonBuilder().startObject().field("name", "pengys").endObject();
+        Map<String, Object> builder = ImmutableMap.of("name", "pengys");
         client.forceInsert(timeSeriesIndexName, "testid", builder);
 
-        List<String> indexes = client.retrievalIndexByAliases(indexName);
+        Collection<String> indexes = client.retrievalIndexByAliases(indexName);
         Assert.assertEquals(1, indexes.size());
-        String index = indexes.get(0);
+        String index = indexes.iterator().next();
         Assert.assertTrue(client.deleteByIndexName(index));
         Assert.assertFalse(client.isExistsIndex(timeSeriesIndexName));
         client.deleteTemplate(indexName);
     }
 
-    private JsonObject getIndex(String indexName) throws IOException {
-        indexName = client.formatIndexName(indexName);
-        GetIndexRequest request = new GetIndexRequest();
-        request.indices(indexName);
-
-        Response response = getRestHighLevelClient().getLowLevelClient()
-                                                    .performRequest(HttpGet.METHOD_NAME, "/" + indexName);
-        InputStreamReader reader = new InputStreamReader(response.getEntity().getContent());
-        Gson gson = new Gson();
-        return undoFormatIndexName(gson.fromJson(reader, JsonObject.class));
-    }
-
-    private RestHighLevelClient getRestHighLevelClient() {
-        return (RestHighLevelClient) Whitebox.getInternalState(client, "client");
-    }
-
-    private JsonObject undoFormatIndexName(JsonObject index) {
-        if (StringUtil.isNotEmpty(namespace) && index != null && index.size() > 0) {
-            LOGGER.info("UndoFormatIndexName before " + index.toString());
-            String namespacePrefix = namespace + "_";
-            index.entrySet().forEach(entry -> {
-                String oldIndexName = entry.getKey();
-                if (oldIndexName.startsWith(namespacePrefix)) {
-                    index.add(oldIndexName.substring(namespacePrefix.length()), entry.getValue());
-                    index.remove(oldIndexName);
-                } else {
-                    throw new RuntimeException(
-                        "The indexName must contain the " + namespace + " prefix, but it is " + entry
-                            .getKey());
-                }
-            });
-            LOGGER.info("UndoFormatIndexName after " + index.toString());
-        }
-        return index;
-    }
-
     private static List<IndexNameConverter> indexNameConverters(String namespace) {
         List<IndexNameConverter> converters = new ArrayList<>();
         converters.add(new NamespaceConverter(namespace));
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-exporter-es7/pom.xml b/oap-server/server-library/library-elasticsearch-client/pom.xml
similarity index 59%
copy from oap-server/server-tools/profile-exporter/tool-profile-snapshot-exporter-es7/pom.xml
copy to oap-server/server-library/library-elasticsearch-client/pom.xml
index d69b307..7da3ed1 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-exporter-es7/pom.xml
+++ b/oap-server/server-library/library-elasticsearch-client/pom.xml
@@ -17,30 +17,34 @@
   ~
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
-        <artifactId>profile-exporter</artifactId>
+        <artifactId>server-library</artifactId>
         <groupId>org.apache.skywalking</groupId>
         <version>8.8.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>org.apache.skywalking</groupId>
-    <artifactId>tool-profile-snapshot-exporter-es7</artifactId>
-    <version>8.8.0-SNAPSHOT</version>
+    <artifactId>library-elasticsearch-client</artifactId>
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>tool-profile-snapshot-bootstrap</artifactId>
-            <version>${project.version}</version>
+            <groupId>com.linecorp.armeria</groupId>
+            <artifactId>armeria</artifactId>
+            <version>1.11.0</version>
         </dependency>
 
         <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-elasticsearch7-plugin</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
-
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClient.java
new file mode 100644
index 0000000..0d97995
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClient.java
@@ -0,0 +1,153 @@
+/*
+ * 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.skywalking.library.elasticsearch;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.linecorp.armeria.client.ClientFactory;
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.client.WebClientBuilder;
+import com.linecorp.armeria.client.endpoint.EndpointGroup;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.SessionProtocol;
+import com.linecorp.armeria.common.auth.BasicToken;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.library.elasticsearch.bulk.BulkProcessorBuilder;
+import org.apache.skywalking.library.elasticsearch.client.AliasClient;
+import org.apache.skywalking.library.elasticsearch.client.DocumentClient;
+import org.apache.skywalking.library.elasticsearch.client.IndexClient;
+import org.apache.skywalking.library.elasticsearch.client.SearchClient;
+import org.apache.skywalking.library.elasticsearch.client.TemplateClient;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.response.NodeInfo;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
+
+@Slf4j
+public final class ElasticSearchClient implements AutoCloseable {
+    private final ObjectMapper mapper = new ObjectMapper()
+        .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    private final WebClient client;
+
+    private final ClientFactory clientFactory;
+
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final TemplateClient templateClient;
+
+    private final IndexClient indexClient;
+
+    private final DocumentClient documentClient;
+
+    private final AliasClient aliasClient;
+
+    private final SearchClient searchClient;
+
+    ElasticSearchClient(SessionProtocol protocol,
+                        String username, String password,
+                        EndpointGroup endpointGroup,
+                        ClientFactory clientFactory) {
+        this.clientFactory = clientFactory;
+        this.requestFactory = new CompletableFuture<>();
+
+        final WebClientBuilder builder = WebClient.builder(protocol, endpointGroup);
+        if (StringUtil.isNotBlank(username) && StringUtil.isNotBlank(password)) {
+            builder.auth(BasicToken.of(username, password));
+        }
+        builder.factory(clientFactory);
+        client = builder.build();
+
+        templateClient = new TemplateClient(requestFactory, client);
+        documentClient = new DocumentClient(requestFactory, client);
+        indexClient = new IndexClient(requestFactory, client);
+        aliasClient = new AliasClient(requestFactory, client);
+        searchClient = new SearchClient(requestFactory, client);
+    }
+
+    public static ElasticSearchClientBuilder builder() {
+        return new ElasticSearchClientBuilder();
+    }
+
+    public void connect() {
+        final CompletableFuture<Void> future =
+            client.get("/").aggregate().thenAcceptAsync(response -> {
+                final HttpStatus status = response.status();
+                if (status != HttpStatus.OK) {
+                    throw new RuntimeException(
+                        "Failed to connect to ElasticSearch server: " + status);
+                }
+                try (final HttpData content = response.content();
+                     final InputStream is = content.toInputStream()) {
+                    final NodeInfo node = mapper.readValue(is, NodeInfo.class);
+                    final String v = node.getVersion().getNumber();
+                    final ElasticSearchVersion version = ElasticSearchVersion.from(v);
+                    requestFactory.complete(RequestFactory.of(version));
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+        future.exceptionally(throwable -> {
+            log.error("Failed to determine ElasticSearch version", throwable);
+            requestFactory.completeExceptionally(throwable);
+            return null;
+        });
+        future.join();
+    }
+
+    public TemplateClient templates() {
+        return templateClient;
+    }
+
+    public DocumentClient documents() {
+        return documentClient;
+    }
+
+    public IndexClient index() {
+        return indexClient;
+    }
+
+    public AliasClient alias() {
+        return aliasClient;
+    }
+
+    public SearchResponse search(Search search, Map<String, ?> params, String... index) {
+        return searchClient.search(search, params, index);
+    }
+
+    public SearchResponse search(Search search, String... index) {
+        return search(search, null, index);
+    }
+
+    public BulkProcessorBuilder bulkProcessor() {
+        return new BulkProcessorBuilder(requestFactory, client);
+    }
+
+    @Override
+    public void close() {
+        clientFactory.close();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClientBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClientBuilder.java
new file mode 100644
index 0000000..bb2c4d0
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchClientBuilder.java
@@ -0,0 +1,150 @@
+/*
+ * 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.skywalking.library.elasticsearch;
+
+import com.google.common.collect.ImmutableList;
+import com.linecorp.armeria.client.ClientFactory;
+import com.linecorp.armeria.client.ClientFactoryBuilder;
+import com.linecorp.armeria.client.Endpoint;
+import com.linecorp.armeria.client.endpoint.EndpointGroup;
+import com.linecorp.armeria.client.endpoint.healthcheck.HealthCheckedEndpointGroup;
+import com.linecorp.armeria.common.SessionProtocol;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.net.ssl.TrustManagerFactory;
+import lombok.SneakyThrows;
+import org.apache.skywalking.apm.util.StringUtil;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static org.apache.skywalking.apm.util.StringUtil.isNotBlank;
+
+public final class ElasticSearchClientBuilder {
+    private SessionProtocol protocol = SessionProtocol.HTTP;
+
+    private String username;
+
+    private String password;
+
+    private Duration healthCheckRetryInterval = Duration.ofSeconds(30);
+
+    private final ImmutableList.Builder<String> endpoints = ImmutableList.builder();
+
+    private String trustStorePath;
+
+    private String trustStorePass;
+
+    private Duration connectTimeout = Duration.ofMillis(500);
+
+    public ElasticSearchClientBuilder protocol(String protocol) {
+        checkArgument(isNotBlank(protocol), "protocol cannot be blank");
+        this.protocol = SessionProtocol.of(protocol);
+        return this;
+    }
+
+    public ElasticSearchClientBuilder username(String username) {
+        this.username = requireNonNull(username, "username");
+        return this;
+    }
+
+    public ElasticSearchClientBuilder password(String password) {
+        this.password = requireNonNull(password, "password");
+        return this;
+    }
+
+    public ElasticSearchClientBuilder endpoints(Iterable<String> endpoints) {
+        requireNonNull(endpoints, "endpoints");
+        this.endpoints.addAll(endpoints);
+        return this;
+    }
+
+    public ElasticSearchClientBuilder endpoints(String... endpoints) {
+        return endpoints(Arrays.asList(endpoints));
+    }
+
+    public ElasticSearchClientBuilder healthCheckRetryInterval(Duration healthCheckRetryInterval) {
+        requireNonNull(healthCheckRetryInterval, "healthCheckRetryInterval");
+        this.healthCheckRetryInterval = healthCheckRetryInterval;
+        return this;
+    }
+
+    public ElasticSearchClientBuilder trustStorePath(String trustStorePath) {
+        requireNonNull(trustStorePath, "trustStorePath");
+        this.trustStorePath = trustStorePath;
+        return this;
+    }
+
+    public ElasticSearchClientBuilder trustStorePass(String trustStorePass) {
+        requireNonNull(trustStorePass, "trustStorePass");
+        this.trustStorePass = trustStorePass;
+        return this;
+    }
+
+    public ElasticSearchClientBuilder connectTimeout(int connectTimeout) {
+        checkArgument(connectTimeout > 0, "connectTimeout must be positive");
+        this.connectTimeout = Duration.ofMillis(connectTimeout);
+        return this;
+    }
+
+    @SneakyThrows
+    public ElasticSearchClient build() {
+        final List<Endpoint> endpoints =
+            this.endpoints.build().stream().filter(StringUtil::isNotBlank).map(it -> {
+                final String[] parts = it.split(":", 2);
+                if (parts.length == 2) {
+                    return Endpoint.of(parts[0], Integer.parseInt(parts[1]));
+                }
+                return Endpoint.of(parts[0]);
+            }).collect(Collectors.toList());
+        final HealthCheckedEndpointGroup endpointGroup =
+            HealthCheckedEndpointGroup.builder(EndpointGroup.of(endpoints), "_cluster/health")
+                                      .protocol(protocol)
+                                      .useGet(true)
+                                      .retryInterval(healthCheckRetryInterval)
+                                      .build();
+        final ClientFactoryBuilder factoryBuilder = ClientFactory.builder();
+        factoryBuilder.connectTimeout(connectTimeout);
+
+        if (StringUtil.isNotBlank(trustStorePath)) {
+            final TrustManagerFactory trustManagerFactory =
+                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            final KeyStore truststore = KeyStore.getInstance("jks");
+            try (final InputStream is = Files.newInputStream(Paths.get(trustStorePath))) {
+                truststore.load(is, trustStorePass.toCharArray());
+            } // TODO: test
+            trustManagerFactory.init(truststore);
+
+            factoryBuilder.tlsCustomizer(
+                sslContextBuilder -> sslContextBuilder.trustManager(trustManagerFactory));
+        }
+
+        return new ElasticSearchClient(
+            protocol,
+            username,
+            password,
+            endpointGroup,
+            factoryBuilder.build()
+        );
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchVersion.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchVersion.java
new file mode 100644
index 0000000..777dc5c
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/ElasticSearchVersion.java
@@ -0,0 +1,80 @@
+/*
+ * 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.skywalking.library.elasticsearch;
+
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public final class ElasticSearchVersion implements Comparable<ElasticSearchVersion> {
+    public static final ElasticSearchVersion UNKNOWN = new ElasticSearchVersion(-1, -1);
+
+    public static final ElasticSearchVersion V6_0 = new ElasticSearchVersion(6, 0);
+
+    public static final ElasticSearchVersion V7_0 = new ElasticSearchVersion(7, 0);
+
+    public static final ElasticSearchVersion V8_0 = new ElasticSearchVersion(8, 0);
+
+    private final int major;
+
+    private final int minor;
+
+    @Override
+    public int compareTo(final ElasticSearchVersion o) {
+        if (major != o.major) {
+            return Integer.compare(major, o.major);
+        }
+        return Integer.compare(minor, o.minor);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final ElasticSearchVersion that = (ElasticSearchVersion) o;
+        return major == that.major && minor == that.minor;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(major, minor);
+    }
+
+    @Override
+    public String toString() {
+        return major + "." + minor;
+    }
+
+    private static final Pattern REGEX = Pattern.compile("(\\d+)\\.(\\d+).*");
+
+    public static ElasticSearchVersion from(String version) {
+        final Matcher matcher = REGEX.matcher(version);
+        if (!matcher.matches()) {
+            throw new IllegalArgumentException("Failed to parse version: " + version);
+        }
+        final int major = Integer.parseInt(matcher.group(1));
+        final int minor = Integer.parseInt(matcher.group(2));
+        return new ElasticSearchVersion(major, minor);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessor.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessor.java
new file mode 100644
index 0000000..01cf307
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessor.java
@@ -0,0 +1,135 @@
+/*
+ * 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.skywalking.library.elasticsearch.bulk;
+
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.util.Exceptions;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+
+import static java.util.Objects.requireNonNull;
+
+@Slf4j
+public final class BulkProcessor {
+    private final ArrayBlockingQueue<Object> requests;
+
+    private final CompletableFuture<RequestFactory> requestFactory;
+    private final WebClient client;
+
+    private final int bulkActions;
+    private final int concurrentRequests;
+
+    public BulkProcessor(
+        final CompletableFuture<RequestFactory> requestFactory,
+        final WebClient client, final int bulkActions,
+        final Duration flushInterval, final int concurrentRequests) {
+        this.requestFactory = requireNonNull(requestFactory, "requestFactory");
+        this.client = requireNonNull(client, "client");
+        this.bulkActions = bulkActions;
+
+        requireNonNull(flushInterval, "flushInterval");
+
+        this.concurrentRequests = concurrentRequests;
+        this.requests = new ArrayBlockingQueue<>(bulkActions + 1);
+        Executors.newSingleThreadScheduledExecutor(r -> {
+            final Thread thread = new Thread(r);
+            thread.setName("ElasticSearch BulkProcessor");
+            return thread;
+        }).scheduleWithFixedDelay(
+            this::flush,
+            0, flushInterval.getSeconds(),
+            TimeUnit.SECONDS
+        );
+    }
+
+    public BulkProcessor add(IndexRequest request) {
+        internalAdd(request);
+        return this;
+    }
+
+    public BulkProcessor add(UpdateRequest request) {
+        internalAdd(request);
+        return this;
+    }
+
+    private void internalAdd(Object request) {
+        requireNonNull(request, "request");
+        requests.add(request);
+        flushIfNeeded();
+    }
+
+    @SneakyThrows
+    private void flushIfNeeded() {
+        if (requests.size() >= bulkActions) {
+            flush();
+        }
+    }
+
+    public void flush() {
+        if (this.requests.isEmpty()) {
+            return;
+        }
+
+        final List<Object> requests = new ArrayList<>(this.requests.size());
+        this.requests.drainTo(requests);
+
+        log.debug("Executing bulk with {} requests", requests.size());
+
+        final CompletableFuture<Void> future = requestFactory.thenCompose(rf -> {
+            try {
+                final List<byte[]> bs = new ArrayList<>();
+                for (final Object request : requests) {
+                    bs.add(rf.codec().encode(request));
+                    bs.add("\n".getBytes());
+                }
+                final ByteBuf content = Unpooled.wrappedBuffer(bs.toArray(new byte[0][]));
+                return client.execute(rf.bulk().bulk(content))
+                             .aggregate().thenAccept(response -> {
+                        final HttpStatus status = response.status();
+                        if (status != HttpStatus.OK) {
+                            throw new RuntimeException(
+                                "Failed to process bulk request: " + status);
+                        }
+                    });
+            } catch (Exception e) {
+                return Exceptions.throwUnsafely(e);
+            }
+        });
+        future.whenComplete((result, e) -> {
+            if (e != null) {
+                log.error("Failed to execute bulk", e);
+            } else {
+                log.debug("Succeeded executing {} requests in bulk", requests.size());
+            }
+        });
+        future.join();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessorBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessorBuilder.java
new file mode 100644
index 0000000..9c3d633
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/bulk/BulkProcessorBuilder.java
@@ -0,0 +1,63 @@
+/*
+ * 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.skywalking.library.elasticsearch.bulk;
+
+import com.linecorp.armeria.client.WebClient;
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class BulkProcessorBuilder {
+    private final CompletableFuture<RequestFactory> requestFactory;
+    private final WebClient client;
+
+    private int bulkActions = -1;
+    private Duration flushInterval;
+    private int concurrentRequests = 1;
+
+    // TODO: backoff
+
+    public BulkProcessorBuilder bulkActions(int bulkActions) {
+        checkArgument(bulkActions > 0, "bulkActions must be positive");
+        this.bulkActions = bulkActions;
+        return this;
+    }
+
+    public BulkProcessorBuilder flushInterval(Duration flushInterval) {
+        this.flushInterval = requireNonNull(flushInterval, "flushInterval");
+        return this;
+    }
+
+    public BulkProcessorBuilder concurrentRequests(int concurrentRequests) {
+        checkArgument(concurrentRequests > 0, "concurrentRequests must be positive");
+        this.concurrentRequests = concurrentRequests;
+        return this;
+    }
+
+    public BulkProcessor build() {
+        return new BulkProcessor(
+            requestFactory, client, bulkActions, flushInterval, concurrentRequests);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/AliasClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/AliasClient.java
new file mode 100644
index 0000000..1cdf405
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/AliasClient.java
@@ -0,0 +1,65 @@
+/*
+ * 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.skywalking.library.elasticsearch.client;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class AliasClient {
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final WebClient client;
+
+    @SneakyThrows
+    public Map<String, Object> indices(String name) {
+        // noinspection unchecked
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.alias().indices(name))
+                        .aggregate().thenApply(response -> {
+                    final HttpStatus status = response.status();
+                    if (status != HttpStatus.OK) {
+                        throw new RuntimeException("Failed to get alias indices: " + status);
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        return rf.codec().decode(is, new TypeReference<Map<String, Object>>() {
+                        }); // TODO
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return Collections.<String, Object>emptyMap();
+                    }
+
+                }).exceptionally(e -> {
+                    log.error("Failed to check whether index exists", e);
+                    return Collections.emptyMap();
+                })).get();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/DocumentClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/DocumentClient.java
new file mode 100644
index 0000000..aab6ceb
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/DocumentClient.java
@@ -0,0 +1,129 @@
+/*
+ * 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.skywalking.library.elasticsearch.client;
+
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.response.Document;
+import org.apache.skywalking.library.elasticsearch.response.Documents;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class DocumentClient {
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final WebClient client;
+
+    @SneakyThrows
+    public boolean exists(String index, String type, String id) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.document().exist(index, type, id))
+                        .aggregate().thenApply(response -> response.status() == HttpStatus.OK)
+                        .exceptionally(e -> {
+                            log.error("Failed to check whether document exists", e);
+                            return false;
+                        })).get();
+    }
+
+    @SneakyThrows
+    public Optional<Document> get(String index, String type, String id) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.document().get(index, type, id))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() != HttpStatus.OK) {
+                        return Optional.<Document>empty();
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        return Optional.of(rf.codec().decode(is, Document.class));
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return Optional.<Document>empty();
+                    }
+                })).get();
+    }
+
+    @SneakyThrows
+    public Optional<Documents> mget(String index, String type, Iterable<String> ids) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.document().mget(index, type, ids))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() != HttpStatus.OK) {
+                        return Optional.<Documents>empty();
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        return Optional.of(rf.codec().decode(is, Documents.class));
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return Optional.<Documents>empty();
+                    }
+                })).get();
+    }
+
+    @SneakyThrows
+    public void index(IndexRequest request, Map<String, Object> params) {
+        requestFactory.thenCompose(
+            rf -> client.execute(rf.document().index(request, params))
+                        .aggregate().thenAccept(response -> {
+                    final HttpStatus status = response.status();
+                    if (status != HttpStatus.CREATED && status != HttpStatus.OK) {
+                        throw new RuntimeException("Failed to index doc: " + status);
+                    }
+                })).join();
+    }
+
+    @SneakyThrows
+    public void update(UpdateRequest request, Map<String, Object> params) {
+        requestFactory.thenCompose(
+            rf -> client.execute(rf.document().update(request, params))
+                        .aggregate().thenAccept(response -> {
+                    final HttpStatus status = response.status();
+                    if (status != HttpStatus.OK) {
+                        throw new RuntimeException("Failed to update doc: " + status);
+                    }
+                })).join();
+    }
+
+    @SneakyThrows
+    public void delete(String index, String type, Query query,
+                       Map<String, Object> params) {
+        requestFactory.thenCompose(
+            rf -> client.execute(rf.document().delete(index, type, query, params))
+                        .aggregate().thenAccept(response -> {
+                    final HttpStatus status = response.status();
+                    if (status != HttpStatus.OK) {
+                        throw new RuntimeException("Failed to delete docs by query: " + status);
+                    }
+                })).join();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/IndexClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/IndexClient.java
new file mode 100644
index 0000000..92f3e97
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/IndexClient.java
@@ -0,0 +1,121 @@
+/*
+ * 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.skywalking.library.elasticsearch.client;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.response.Index;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class IndexClient {
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final WebClient client;
+
+    @SneakyThrows
+    public boolean exists(String name) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.index().exists(name))
+                        .aggregate().thenApply(response -> response.status() == HttpStatus.OK)
+                        .exceptionally(e -> {
+                            log.error("Failed to check whether index exists", e);
+                            return false;
+                        })).get();
+    }
+
+    @SneakyThrows
+    public Optional<Index> get(String name) {
+        final TypeReference<Map<String, Index>> type =
+            new TypeReference<Map<String, Index>>() {
+            };
+        final CompletableFuture<Optional<Index>> future = requestFactory.thenCompose(
+            rf -> client.execute(rf.index().get(name))
+                        .aggregate().thenApply(response -> {
+                    final HttpStatus status = response.status();
+                    if (status == HttpStatus.NOT_FOUND) {
+                        return Optional.empty();
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        final Map<String, Index> indices = rf.codec().decode(is, type);
+                        return Optional.ofNullable(indices.get(name));
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return Optional.empty();
+                    }
+                }));
+
+        return future.get();
+    }
+
+    @SneakyThrows
+    public boolean create(String name,
+                          Mappings mappings,
+                          Map<String, ?> settings) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.index().create(name, mappings, settings))
+                        .aggregate().thenApply(response -> response.status() == HttpStatus.OK)
+                        .exceptionally(e -> {
+                            log.error("Failed to check whether index exists", e);
+                            return false;
+                        })).get();
+    }
+
+    @SneakyThrows
+    public boolean delete(String name) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.index().delete(name))
+                        .aggregate().thenApply(response -> response.status() == HttpStatus.OK)
+                        .exceptionally(e -> {
+                            log.error("Failed to delete whether index exists", e);
+                            return false;
+                        })).get();
+    }
+
+    @SneakyThrows
+    public boolean putMapping(String name, String type, Mappings mapping) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.index().putMapping(name, type, mapping))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() == HttpStatus.OK) {
+                        return true;
+                    }
+                    log.error(
+                        "Failed to update index mapping.",
+                        new RuntimeException(response.contentUtf8())
+                    );
+                    return false;
+                }).exceptionally(e -> {
+                    log.error("Failed to update index mapping", e);
+                    return false;
+                })).get();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/SearchClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/SearchClient.java
new file mode 100644
index 0000000..1a604a5
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/SearchClient.java
@@ -0,0 +1,66 @@
+/*
+ * 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.skywalking.library.elasticsearch.client;
+
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class SearchClient {
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final WebClient client;
+
+    @SneakyThrows
+    public SearchResponse search(Search criteria,
+                                 Map<String, ?> params,
+                                 String... index) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.search().search(criteria, params, index))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() != HttpStatus.OK) {
+                        throw new RuntimeException(
+                            "Failed to search documents: " + Arrays.toString(index) + ". " +
+                                response.contentUtf8());
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        return rf.codec().decode(is, SearchResponse.class);
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return new SearchResponse();
+                    }
+                }).exceptionally(e -> {
+                    log.error("Failed to search documents", e);
+                    return new SearchResponse();
+                })).get();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/TemplateClient.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/TemplateClient.java
new file mode 100644
index 0000000..ac77365
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/client/TemplateClient.java
@@ -0,0 +1,128 @@
+/*
+ * 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.skywalking.library.elasticsearch.client;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.linecorp.armeria.client.WebClient;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.response.IndexTemplate;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+@Slf4j
+@RequiredArgsConstructor
+public final class TemplateClient {
+    private final CompletableFuture<RequestFactory> requestFactory;
+
+    private final WebClient client;
+
+    @SneakyThrows
+    public boolean exists(String name) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.template().exists(name))
+                        .aggregate().thenApply(response -> {
+                    final HttpStatus status = response.status();
+                    if (status == HttpStatus.OK) {
+                        return true;
+                    } else if (status == HttpStatus.NOT_FOUND) {
+                        return false;
+                    }
+                    throw new RuntimeException(
+                        "Response status code of template exists request should be 200 or 404," +
+                            " but it was: " + status.code());
+                }).exceptionally(e -> {
+                    log.error("Failed to check whether template exists", e);
+                    return false;
+                })).get();
+    }
+
+    @SneakyThrows
+    public Optional<IndexTemplate> get(String name) {
+        final TypeReference<Map<String, IndexTemplate>> type =
+            new TypeReference<Map<String, IndexTemplate>>() {
+            };
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.template().get(name))
+                        .aggregate().thenApply(response -> {
+                    final HttpStatus status = response.status();
+                    if (status != HttpStatus.OK) {
+                        return Optional.<IndexTemplate>empty();
+                    }
+
+                    try (final HttpData content = response.content();
+                         final InputStream is = content.toInputStream()) {
+                        final Map<String, IndexTemplate> templates = rf.codec().decode(is, type);
+                        return Optional.ofNullable(templates.get(name));
+                    } catch (Exception e) {
+                        log.error("Failed to close input stream", e);
+                        return Optional.<IndexTemplate>empty();
+                    }
+                }).exceptionally(e -> {
+                    log.error("Failed to check whether template exists", e);
+                    return Optional.empty();
+                })).get();
+    }
+
+    @SneakyThrows
+    public boolean delete(String name) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.template().delete(name))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() == HttpStatus.OK) {
+                        return true;
+                    }
+                    log.error(
+                        "Failed to check whether template exists. {}",
+                        response.contentUtf8()
+                    );
+                    return false;
+                }).exceptionally(e -> {
+                    log.error("Failed to check whether template exists", e);
+                    return false;
+                })).get();
+    }
+
+    @SneakyThrows
+    public boolean createOrUpdate(String name, Map<String, Object> settings,
+                                  Mappings mappings, int order) {
+        return requestFactory.thenCompose(
+            rf -> client.execute(rf.template().createOrUpdate(name, settings, mappings, order))
+                        .aggregate().thenApply(response -> {
+                    if (response.status() == HttpStatus.OK) {
+                        return true;
+                    }
+                    log.error(
+                        "Failed to create or update template.",
+                        new RuntimeException(response.contentUtf8())
+                    );
+                    return false;
+                }).exceptionally(e -> {
+                    log.error("Failed to create or update template", e);
+                    return false;
+                })).get();
+    }
+
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/IndexRequest.java
similarity index 70%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/IndexRequest.java
index 7960299..818c3b9 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/IndexRequest.java
@@ -13,14 +13,21 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import java.util.Map;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@Setter
+@Builder
+public final class IndexRequest {
+    private final String index;
+    private final String type;
+    private final String id;
+    private final Map<String, ?> doc;
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/UpdateRequest.java
similarity index 69%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/UpdateRequest.java
index 7960299..37bed7e 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/UpdateRequest.java
@@ -13,14 +13,21 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import java.util.Map;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@Setter
+@Builder
+public final class UpdateRequest {
+    private final String index;
+    private final String type;
+    private final String id;
+    private final Map<String, Object> doc;
 }
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/ClientException.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/AliasFactory.java
similarity index 73%
rename from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/ClientException.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/AliasFactory.java
index 6374b9f..6ccf6b8 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/ClientException.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/AliasFactory.java
@@ -13,17 +13,15 @@
  * 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.skywalking.oap.server.library.client;
+package org.apache.skywalking.library.elasticsearch.requests.factory;
 
-public abstract class ClientException extends Exception {
-    public ClientException(String message) {
-        super(message);
-    }
+import com.linecorp.armeria.common.HttpRequest;
 
-    public ClientException(String message, Throwable cause) {
-        super(message, cause);
-    }
+public interface AliasFactory {
+    /**
+     * Returns a request to list all indices behind the {@code alias}.
+     */
+    HttpRequest indices(String alias);
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/BulkFactory.java
similarity index 70%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/BulkFactory.java
index 7960299..9b64ab1 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/BulkFactory.java
@@ -13,14 +13,16 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.factory;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import com.linecorp.armeria.common.HttpRequest;
+import io.netty.buffer.ByteBuf;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+public interface BulkFactory {
+    /**
+     * Returns a request to perform multiple indexing or delete operations in a single API call.
+     */
+    HttpRequest bulk(ByteBuf content);
 }
diff --git a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/Codec.java
similarity index 58%
copy from oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/Codec.java
index f91f5f8..e69678b 100644
--- a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/Codec.java
@@ -13,17 +13,25 @@
  * 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.skywalking.oap.server.starter;
+package org.apache.skywalking.library.elasticsearch.requests.factory;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.io.InputStream;
 
 /**
- * OAP starter specific for the ES7 storage. This includes the same code of OAPServerStartUp in the `server-starter`
- * module.
+ * Responsible to encode requests and decode responses.
  */
-public class OAPServerStartUp {
-    public static void main(String[] args) {
-        OAPServerBootstrap.start();
+public interface Codec {
+    byte[] encode(Object request) throws Exception;
+
+    <T> T decode(InputStream inputStream, TypeReference<T> type) throws Exception;
+
+    <T> T decode(InputStream inputStream, Class<T> type) throws Exception;
+
+    default <T> T decode(InputStream inputStream) throws Exception {
+        return decode(inputStream, new TypeReference<T>() {
+        });
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/DocumentFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/DocumentFactory.java
new file mode 100644
index 0000000..ae77b97
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/DocumentFactory.java
@@ -0,0 +1,57 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory;
+
+import com.linecorp.armeria.common.HttpRequest;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+
+public interface DocumentFactory {
+    /**
+     * Returns a request to check whether the document exists in the {@code index} or not.
+     */
+    HttpRequest exist(String index, String type, String id);
+
+    /**
+     * Returns a request to get a document of {@code id} in {@code index}.
+     */
+    HttpRequest get(String index, String type, String id);
+
+    /**
+     * Returns a request to get multiple documents of {@code ids} in {@code index}.
+     */
+    HttpRequest mget(String index, String type, Iterable<String> ids);
+
+    /**
+     * Returns a request to index a document with {@link IndexRequest}.
+     */
+    HttpRequest index(IndexRequest request, Map<String, ?> params);
+
+    /**
+     * Returns a request to update a document with {@link UpdateRequest}.
+     */
+    HttpRequest update(UpdateRequest request, Map<String, ?> params);
+
+    /**
+     * Returns a request to delete documents matching the given {@code query} in {@code index}.
+     */
+    HttpRequest delete(String index, String type, Query query,
+                       Map<String, ?> params);
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/IndexFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/IndexFactory.java
new file mode 100644
index 0000000..955e447
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/IndexFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory;
+
+import com.linecorp.armeria.common.HttpRequest;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+public interface IndexFactory {
+    /**
+     * Returns a request to check whether the {@code index} exists or not.
+     */
+    HttpRequest exists(String index);
+
+    /**
+     * Returns a request to get an index of name {@code index}.
+     */
+    HttpRequest get(String index);
+
+    /**
+     * Returns a request to create an index of name {@code index}.
+     */
+    HttpRequest create(String index,
+                       Mappings mappings,
+                       Map<String, ?> settings);
+
+    /**
+     * Returns a request to delete an index of name {@code index}.
+     */
+    HttpRequest delete(String index);
+
+    /**
+     * Returns a request to update the {@code mappings} of an index of name {@code index}.
+     */
+    HttpRequest putMapping(String index, String type, Mappings mappings);
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/RequestFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/RequestFactory.java
new file mode 100644
index 0000000..65cd3b1
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/RequestFactory.java
@@ -0,0 +1,92 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory;
+
+import org.apache.skywalking.library.elasticsearch.ElasticSearchVersion;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.V6RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.V7RequestFactory;
+
+import static java.util.Objects.requireNonNull;
+import static org.apache.skywalking.library.elasticsearch.ElasticSearchVersion.V6_0;
+import static org.apache.skywalking.library.elasticsearch.ElasticSearchVersion.V7_0;
+import static org.apache.skywalking.library.elasticsearch.ElasticSearchVersion.V8_0;
+
+public interface RequestFactory {
+    /**
+     * Returns a {@link RequestFactory} that is responsible to compose correct requests according to
+     * the syntax of specific {@link ElasticSearchVersion}.
+     */
+    static RequestFactory of(ElasticSearchVersion version) {
+        requireNonNull(version, "version");
+        if (version.compareTo(V6_0) >= 0 && version.compareTo(V7_0) < 0) {
+            return V6RequestFactory.INSTANCE;
+        }
+        if (version.compareTo(V7_0) >= 0 && version.compareTo(V8_0) < 0) {
+            return V7RequestFactory.INSTANCE;
+        }
+
+        throw new UnsupportedOperationException("Version " + version + " is not supported.");
+    }
+
+    /**
+     * Returns a {@link TemplateFactory} that is dedicated to compose template-related requests.
+     *
+     * @see TemplateFactory
+     */
+    TemplateFactory template();
+
+    /**
+     * Returns a {@link IndexFactory} that is dedicated to compose index-related requests.
+     *
+     * @see IndexFactory
+     */
+    IndexFactory index();
+
+    /**
+     * Returns a {@link AliasFactory} that is dedicated to compose alias-related requests.
+     *
+     * @see AliasFactory
+     */
+    AliasFactory alias();
+
+    /**
+     * Returns a {@link DocumentFactory} that is dedicated to compose document-related requests.
+     *
+     * @see DocumentFactory
+     */
+    DocumentFactory document();
+
+    /**
+     * Returns a {@link SearchFactory} that is dedicated to compose searching-related requests.
+     *
+     * @see DocumentFactory
+     */
+    SearchFactory search();
+
+    /**
+     * Returns a {@link SearchFactory} that is dedicated to compose bulk-related requests.
+     *
+     * @see DocumentFactory
+     */
+    BulkFactory bulk();
+
+    /**
+     * Returns a {@link Codec} to encode the requests and decode the response.
+     */
+    Codec codec();
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7UpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/SearchFactory.java
similarity index 59%
rename from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7UpdateRequest.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/SearchFactory.java
index f53c8bd..3824a4b 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7UpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/SearchFactory.java
@@ -15,20 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.client;
+package org.apache.skywalking.library.elasticsearch.requests.factory;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.linecorp.armeria.common.HttpRequest;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
 
-public class ElasticSearch7UpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+public interface SearchFactory {
+    /**
+     * Returns a request to search documents.
+     */
+    HttpRequest search(Search search, Map<String, ?> queryParams, String... index);
 
-    public ElasticSearch7UpdateRequest(String index, String id) {
-        super(index, id);
-    }
-
-    @Override
-    public ElasticSearch7UpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
-        return this;
+    /**
+     * Returns a request to search documents.
+     */
+    default HttpRequest search(Search search, String... index) {
+        return search(search, null, index);
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/TemplateFactory.java
similarity index 50%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/TemplateFactory.java
index ebad19e..3fb7a66 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/type/StorageDataComplexObject.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/TemplateFactory.java
@@ -13,27 +13,34 @@
  * 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.skywalking.oap.server.core.storage.type;
+package org.apache.skywalking.library.elasticsearch.requests.factory;
+
+import com.linecorp.armeria.common.HttpRequest;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+public interface TemplateFactory {
+    /**
+     * Returns a request to check whether the template exists or not.
+     */
+    HttpRequest exists(String name);
 
-/**
- * StorageDataComplexObject implementation supports String-Object interconversion.
- */
-public interface StorageDataComplexObject<T> {
     /**
-     * @return string representing this object.
+     * Returns a request to get a template of {@code name}.
      */
-    String toStorageData();
+    HttpRequest get(String name);
 
     /**
-     * Initialize this object based on the given string data.
+     * Returns a request to delete a template of {@code name}.
      */
-    void toObject(String data);
+    HttpRequest delete(String name);
 
     /**
-     * Initialize the object based on the given source.
+     * Returns a request to create or update a template of {@code name} with the given {@code
+     * settings}, {@code mapping} and {@code order}.
      */
-    void copyFrom(T source);
+    HttpRequest createOrUpdate(String name, Map<String, ?> settings,
+                               Mappings mappings, int order);
 }
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6AliasFactory.java
similarity index 53%
copy from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6AliasFactory.java
index 2663856..f22a0e5 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6AliasFactory.java
@@ -15,20 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.factory.v6;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.google.common.base.Strings;
+import com.linecorp.armeria.common.HttpRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.AliasFactory;
 
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+import static com.google.common.base.Preconditions.checkArgument;
 
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
-    }
+final class V6AliasFactory implements AliasFactory {
+    static final AliasFactory INSTANCE = new V6AliasFactory();
 
     @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
-        return this;
+    public HttpRequest indices(String alias) {
+        checkArgument(!Strings.isNullOrEmpty(alias), "alias cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .get("/_alias/{name}")
+                          .pathParam("name", alias)
+                          .build();
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6BulkFactory.java
similarity index 53%
copy from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6BulkFactory.java
index 0b2501d..3bfcac1 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6BulkFactory.java
@@ -13,28 +13,26 @@
  * 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.skywalking.oap.server.storage.plugin.elasticsearch7.base;
-
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexStructures;
+package org.apache.skywalking.library.elasticsearch.requests.factory.v6;
 
-public class IndexEs7Structures extends IndexStructures {
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.MediaType;
+import io.netty.buffer.ByteBuf;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.BulkFactory;
 
-    @Override
-    protected PropertiesExtractor doGetPropertiesExtractor() {
-        return mapping -> (Map<String, Object>) mapping.get("properties");
-    }
+final class V6BulkFactory implements BulkFactory {
+    static final BulkFactory INSTANCE = new V6BulkFactory();
 
+    @SneakyThrows
     @Override
-    protected PropertiesWrapper doGetPropertiesWrapper() {
-        return properties -> {
-            HashMap<String, Object> mappings = new HashMap<>();
-            mappings.put("properties", properties);
-            return mappings;
-        };
+    public HttpRequest bulk(ByteBuf content) {
+        return HttpRequest.builder()
+                          .post("/_bulk")
+                          .content(MediaType.JSON, HttpData.wrap(content))
+                          .build();
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6DocumentFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6DocumentFactory.java
new file mode 100644
index 0000000..d215ba3
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6DocumentFactory.java
@@ -0,0 +1,167 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpRequestBuilder;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.DocumentFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V6Codec;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static com.google.common.collect.Iterables.isEmpty;
+import static java.util.Objects.requireNonNull;
+
+final class V6DocumentFactory implements DocumentFactory {
+    static final DocumentFactory INSTANCE = new V6DocumentFactory();
+
+    @Override
+    public HttpRequest exist(String index, String type, String id) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .head("/{index}/{type}/{id}")
+                          .pathParam("index", index)
+                          .pathParam("type", type)
+                          .pathParam("id", id)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(String index, String type, String id) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .get("/{index}/{type}/{id}")
+                          .pathParam("index", index)
+                          .pathParam("type", type)
+                          .pathParam("id", id)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest mget(String index, String type, Iterable<String> ids) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(ids != null && !isEmpty(ids), "ids cannot be null or empty");
+
+        final Map<String, Iterable<String>> m = ImmutableMap.of("ids", ids);
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(m);
+        return HttpRequest.builder()
+                          .get("/{index}/{type}/_mget")
+                          .pathParam("index", index)
+                          .pathParam("type", type)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest index(IndexRequest request, Map<String, ?> params) {
+        requireNonNull(request, "request");
+
+        final String index = request.getIndex();
+        final String type = request.getType();
+        final String id = request.getId();
+        final Map<String, ?> doc = request.getDoc();
+
+        checkArgument(!isNullOrEmpty(index), "request.index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "request.type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "request.id cannot be null or empty");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(doc);
+
+        builder.put("/{index}/{type}/{id}")
+               .pathParam("index", index)
+               .pathParam("type", type)
+               .pathParam("id", id)
+               .content(MediaType.JSON, content);
+
+        return builder.build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest update(UpdateRequest request, Map<String, ?> params) {
+        requireNonNull(request, "request");
+
+        final String index = request.getIndex();
+        final String type = request.getType();
+        final String id = request.getId();
+        final Map<String, Object> doc = request.getDoc();
+
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+        checkArgument(doc != null && !isEmpty(doc.entrySet()), "doc cannot be null or empty");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(
+            ImmutableMap.of("doc", doc)
+        );
+
+        builder.post("/{index}/{type}/{id}/_update")
+               .pathParam("index", index)
+               .pathParam("type", type)
+               .pathParam("id", id)
+               .content(MediaType.JSON, content);
+
+        return builder.build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest delete(String index, String type, Query query,
+                              Map<String, ?> params) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        requireNonNull(query, "query");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(ImmutableMap.of("query", query));
+
+        return builder.delete("/{index}/{type}/_delete_by_query")
+                      .pathParam("index", index)
+                      .pathParam("type", type)
+                      .content(MediaType.JSON, content)
+                      .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6IndexFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6IndexFactory.java
new file mode 100644
index 0000000..ddcbbda
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6IndexFactory.java
@@ -0,0 +1,103 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.IndexFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V6Codec;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+final class V6IndexFactory implements IndexFactory {
+    static final IndexFactory INSTANCE = new V6IndexFactory();
+
+    @Override
+    public HttpRequest exists(String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .head("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(final String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .get("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest create(String index,
+                              Mappings mappings,
+                              Map<String, ?> settings) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        final ImmutableMap.Builder<String, Object> bodyBuilder = ImmutableMap.builder();
+        if (mappings != null) {
+            bodyBuilder.put("mappings", mappings);
+        }
+        if (settings != null) {
+            bodyBuilder.put("settings", settings);
+        }
+        final ImmutableMap<String, Object> body = bodyBuilder.build();
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(body);
+
+        return HttpRequest.builder()
+                          .put("/{index}")
+                          .pathParam("index", index)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest delete(String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .delete("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest putMapping(String index, String type, Mappings mapping) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!Strings.isNullOrEmpty(type), "type cannot be null or empty");
+
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(mapping);
+        return HttpRequest.builder()
+                          .put("/{index}/_mapping/{type}")
+                          .pathParam("index", index)
+                          .pathParam("type", type)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6RequestFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6RequestFactory.java
new file mode 100644
index 0000000..aa50d43
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6RequestFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import org.apache.skywalking.library.elasticsearch.requests.factory.AliasFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.BulkFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.Codec;
+import org.apache.skywalking.library.elasticsearch.requests.factory.DocumentFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.IndexFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.SearchFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.TemplateFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V6Codec;
+
+public final class V6RequestFactory implements RequestFactory {
+    public static final RequestFactory INSTANCE = new V6RequestFactory();
+
+    @Override
+    public TemplateFactory template() {
+        return V6TemplateFactory.INSTANCE;
+    }
+
+    @Override
+    public IndexFactory index() {
+        return V6IndexFactory.INSTANCE;
+    }
+
+    @Override
+    public AliasFactory alias() {
+        return V6AliasFactory.INSTANCE;
+    }
+
+    @Override
+    public DocumentFactory document() {
+        return V6DocumentFactory.INSTANCE;
+    }
+
+    @Override
+    public SearchFactory search() {
+        return V6SearchFactory.INSTANCE;
+    }
+
+    @Override
+    public BulkFactory bulk() {
+        return V6BulkFactory.INSTANCE;
+    }
+
+    @Override
+    public Codec codec() {
+        return V6Codec.INSTANCE;
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6SearchFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6SearchFactory.java
new file mode 100644
index 0000000..32bb238
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6SearchFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpRequestBuilder;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.SearchFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V6Codec;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+
+final class V6SearchFactory implements SearchFactory {
+    static final SearchFactory INSTANCE = new V6SearchFactory();
+
+    @SneakyThrows
+    @Override
+    public HttpRequest search(Search search,
+                              Map<String, ?> queryParams,
+                              String... indices) {
+        final HttpRequestBuilder builder = HttpRequest.builder();
+
+        if (indices == null || indices.length == 0) {
+            builder.get("/_search");
+        } else {
+            builder.get("/{indices}/_search")
+                   .pathParam("indices", String.join(",", indices));
+        }
+
+        if (queryParams != null && !queryParams.isEmpty()) {
+            queryParams.forEach(builder::queryParam);
+        }
+
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(search);
+
+        return builder.content(MediaType.JSON, content)
+                      .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6TemplateFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6TemplateFactory.java
new file mode 100644
index 0000000..1015cd5
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V6TemplateFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Collections;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.TemplateFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V6Codec;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+final class V6TemplateFactory implements TemplateFactory {
+    static final TemplateFactory INSTANCE = new V6TemplateFactory();
+
+    @Override
+    public HttpRequest exists(String name) {
+        return HttpRequest.builder()
+                          .get("/_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(final String name) {
+        return HttpRequest.builder()
+                          .get("/_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest delete(final String name) {
+        return HttpRequest.builder()
+                          .delete("/_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest createOrUpdate(String name, Map<String, ?> settings,
+                                      Mappings mappings, int order) {
+        final String[] patterns = new String[] {name + "-*"};
+        final Map<String, Object> aliases = ImmutableMap.of(name, Collections.emptyMap());
+        final Map<String, Object> template =
+            ImmutableMap.<String, Object>builder()
+                        .put("index_patterns", patterns)
+                        .put("aliases", aliases)
+                        .put("settings", settings)
+                        .put("mappings", mappings)
+                        .put("order", order)
+                        .build();
+
+        final byte[] content = V6Codec.MAPPER.writeValueAsBytes(template);
+
+        return HttpRequest.builder()
+                          .put("/_template/{name}")
+                          .pathParam("name", name)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7DocumentFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7DocumentFactory.java
new file mode 100644
index 0000000..813637e
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7DocumentFactory.java
@@ -0,0 +1,161 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.HttpRequestBuilder;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.DocumentFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V7Codec;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static com.google.common.collect.Iterables.isEmpty;
+import static java.util.Objects.requireNonNull;
+
+final class V7DocumentFactory implements DocumentFactory {
+    static final DocumentFactory INSTANCE = new V7DocumentFactory();
+
+    @Override
+    public HttpRequest exist(String index, String type, String id) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .head("/{index}/_doc/{id}")
+                          .pathParam("index", index)
+                          .pathParam("id", id)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(String index, String type, String id) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .get("/{index}/_doc/{id}")
+                          .pathParam("index", index)
+                          .pathParam("id", id)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest mget(String index, String type, Iterable<String> ids) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(ids != null && !isEmpty(ids), "ids cannot be null or empty");
+
+        final Map<String, Iterable<String>> m = ImmutableMap.of("ids", ids);
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(m);
+        return HttpRequest.builder()
+                          .get("/{index}/_doc/_mget")
+                          .pathParam("index", index)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest index(IndexRequest request, Map<String, ?> params) {
+        requireNonNull(request, "request");
+
+        final String index = request.getIndex();
+        final String type = request.getType();
+        final String id = request.getId();
+        final Map<String, ?> doc = request.getDoc();
+
+        checkArgument(!isNullOrEmpty(index), "request.index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "request.type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "request.id cannot be null or empty");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(doc);
+
+        builder.put("/{index}/_doc/{id}")
+               .pathParam("index", index)
+               .pathParam("id", id)
+               .content(MediaType.JSON, content);
+
+        return builder.build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest update(UpdateRequest request, Map<String, ?> params) {
+        requireNonNull(request, "request");
+
+        final String index = request.getIndex();
+        final String type = request.getType();
+        final String id = request.getId();
+        final Map<String, Object> doc = request.getDoc();
+
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        checkArgument(!isNullOrEmpty(id), "id cannot be null or empty");
+        checkArgument(doc != null && !isEmpty(doc.entrySet()), "doc cannot be null or empty");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(
+            ImmutableMap.of("doc", doc)
+        );
+
+        builder.post("/{index}/_doc/{id}/_update")
+               .pathParam("index", index)
+               .pathParam("id", id)
+               .content(MediaType.JSON, content);
+
+        return builder.build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest delete(String index, String type, Query query,
+                              Map<String, ?> params) {
+        checkArgument(!isNullOrEmpty(index), "index cannot be null or empty");
+        checkArgument(!isNullOrEmpty(type), "type cannot be null or empty");
+        requireNonNull(query, "query");
+
+        final HttpRequestBuilder builder = HttpRequest.builder();
+        if (params != null) {
+            params.forEach(builder::queryParam);
+        }
+
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(ImmutableMap.of("query", query));
+
+        return builder.delete("/{index}/_doc/_delete_by_query")
+                      .pathParam("index", index)
+                      .content(MediaType.JSON, content)
+                      .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7IndexFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7IndexFactory.java
new file mode 100644
index 0000000..7922427
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7IndexFactory.java
@@ -0,0 +1,101 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.IndexFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V7Codec;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+final class V7IndexFactory implements IndexFactory {
+    static final IndexFactory INSTANCE = new V7IndexFactory();
+
+    @Override
+    public HttpRequest exists(String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .head("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(final String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .get("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest create(String index,
+                              Mappings mappings,
+                              Map<String, ?> settings) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        final ImmutableMap.Builder<String, Object> bodyBuilder = ImmutableMap.builder();
+        if (mappings != null) {
+            bodyBuilder.put("mappings", mappings);
+        }
+        if (settings != null) {
+            bodyBuilder.put("settings", settings);
+        }
+        final ImmutableMap<String, Object> body = bodyBuilder.build();
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(body);
+
+        return HttpRequest.builder()
+                          .put("/{index}")
+                          .pathParam("index", index)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest delete(String index) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        return HttpRequest.builder()
+                          .delete("/{index}")
+                          .pathParam("index", index)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest putMapping(String index, String type, Mappings mapping) {
+        checkArgument(!Strings.isNullOrEmpty(index), "index cannot be null or empty");
+
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(mapping);
+        return HttpRequest.builder()
+                          .put("/{index}/_mapping")
+                          .pathParam("index", index)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7RequestFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7RequestFactory.java
new file mode 100644
index 0000000..c7b2b8d
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7RequestFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import org.apache.skywalking.library.elasticsearch.requests.factory.AliasFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.BulkFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.Codec;
+import org.apache.skywalking.library.elasticsearch.requests.factory.DocumentFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.IndexFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.RequestFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.SearchFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.TemplateFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V7Codec;
+
+public final class V7RequestFactory implements RequestFactory {
+    public static final RequestFactory INSTANCE = new V7RequestFactory();
+
+    @Override
+    public TemplateFactory template() {
+        return V7TemplateFactory.INSTANCE;
+    }
+
+    @Override
+    public IndexFactory index() {
+        return V7IndexFactory.INSTANCE;
+    }
+
+    @Override
+    public AliasFactory alias() {
+        return V6AliasFactory.INSTANCE;
+    }
+
+    @Override
+    public DocumentFactory document() {
+        return V7DocumentFactory.INSTANCE;
+    }
+
+    @Override
+    public SearchFactory search() {
+        return V6SearchFactory.INSTANCE;
+    }
+
+    @Override
+    public BulkFactory bulk() {
+        return V6BulkFactory.INSTANCE;
+    }
+
+    @Override
+    public Codec codec() {
+        return V7Codec.INSTANCE;
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7TemplateFactory.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7TemplateFactory.java
new file mode 100644
index 0000000..4e751e1
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/V7TemplateFactory.java
@@ -0,0 +1,84 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6;
+
+import com.google.common.collect.ImmutableMap;
+import com.linecorp.armeria.common.HttpRequest;
+import com.linecorp.armeria.common.MediaType;
+import java.util.Collections;
+import java.util.Map;
+import lombok.SneakyThrows;
+import org.apache.skywalking.library.elasticsearch.requests.factory.TemplateFactory;
+import org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec.V7Codec;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+final class V7TemplateFactory implements TemplateFactory {
+    static final TemplateFactory INSTANCE = new V7TemplateFactory();
+
+    @Override
+    public HttpRequest exists(String name) {
+        return HttpRequest.builder()
+                          .get("/_index_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest get(final String name) {
+        return HttpRequest.builder()
+                          .get("/_index_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @Override
+    public HttpRequest delete(final String name) {
+        return HttpRequest.builder()
+                          .delete("/_index_template/{name}")
+                          .pathParam("name", name)
+                          .build();
+    }
+
+    @SneakyThrows
+    @Override
+    public HttpRequest createOrUpdate(String name, Map<String, ?> settings,
+                                      Mappings mappings, int order) {
+        final String[] patterns = new String[] {name + "-*"};
+        final Map<String, Object> aliases = ImmutableMap.of(name, Collections.emptyMap());
+        final Map<String, Object> template =
+            ImmutableMap.<String, Object>builder()
+                        .put("index_patterns", patterns)
+                        .put(
+                            "template",
+                            ImmutableMap.builder()
+                                        .put("aliases", aliases)
+                                        .put("settings", settings)
+                                        .put("mappings", mappings)
+                                        .build()
+                        )
+                        .build();
+
+        final byte[] content = V7Codec.MAPPER.writeValueAsBytes(template);
+
+        return HttpRequest.builder()
+                          .put("/_index_template/{name}")
+                          .pathParam("name", name)
+                          .content(MediaType.JSON, content)
+                          .build();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/BoolQuerySerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/BoolQuerySerializer.java
new file mode 100644
index 0000000..3eb5860
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/BoolQuerySerializer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import java.util.List;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQuery;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+
+public final class BoolQuerySerializer extends JsonSerializer<BoolQuery> {
+    static final String NAME = "bool";
+    static final String MUST = "must";
+    static final String MUST_NOT = "must_not";
+    static final String SHOULD = "should";
+    static final String SHOULD_NOT = "should_not";
+
+    @Override
+    public void serialize(final BoolQuery value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.writeStartObject();
+        {
+            gen.writeFieldName(NAME);
+            gen.writeStartObject();
+            {
+                writeArray(gen, MUST, value.getMust());
+                writeArray(gen, MUST_NOT, value.getMustNot());
+                writeArray(gen, SHOULD, value.getShould());
+                writeArray(gen, SHOULD_NOT, value.getShouldNot());
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+    }
+
+    private void writeArray(final JsonGenerator gen, final String name,
+                            final List<Query> array) throws IOException {
+        if (array == null) {
+            return;
+        }
+
+        gen.writeFieldName(name);
+        gen.writeStartArray();
+        {
+            for (final Query query : array) {
+                gen.writeObject(query);
+            }
+        }
+        gen.writeEndArray();
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/IndexRequestDeserializer.java
similarity index 56%
copy from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/IndexRequestDeserializer.java
index 2663856..78d8f71 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/IndexRequestDeserializer.java
@@ -15,20 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.factory.v6.codec;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
-
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
-    }
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
 
+final class IndexRequestDeserializer extends JsonDeserializer<IndexRequest> {
     @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
-        return this;
+    public IndexRequest deserialize(final JsonParser p, final DeserializationContext ctxt)
+        throws IOException, JsonProcessingException {
+        return null;
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/MappingsSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/MappingsSerializer.java
new file mode 100644
index 0000000..3a9264d
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/MappingsSerializer.java
@@ -0,0 +1,43 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+final class MappingsSerializer extends JsonSerializer<Mappings> {
+
+    @Override
+    public void serialize(final Mappings value, final JsonGenerator gen,
+                          final SerializerProvider serializers)
+        throws IOException {
+        gen.writeStartObject();
+        {
+            gen.writeFieldName(value.getType());
+            gen.writeStartObject();
+            {
+                gen.writeObjectField("properties", value.getProperties());
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/RangeQuerySerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/RangeQuerySerializer.java
new file mode 100644
index 0000000..dffc76c
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/RangeQuerySerializer.java
@@ -0,0 +1,62 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.search.RangeQuery;
+
+public final class RangeQuerySerializer extends JsonSerializer<RangeQuery> {
+    static final String NAME = "range";
+
+    @Override
+    public void serialize(final RangeQuery value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.writeStartObject();
+        {
+            gen.writeFieldName(NAME);
+            gen.writeStartObject();
+            {
+                gen.writeFieldName(value.getName());
+                gen.writeStartObject();
+
+                if (value.getGte() != null) {
+                    provider.defaultSerializeField("gte", value.getGte(), gen);
+                }
+                if (value.getLte() != null) {
+                    provider.defaultSerializeField("lte", value.getLte(), gen);
+                }
+                if (value.getGt() != null) {
+                    provider.defaultSerializeField("gt", value.getGt(), gen);
+                }
+                if (value.getLt() != null) {
+                    provider.defaultSerializeField("lt", value.getLt(), gen);
+                }
+                if (value.getBoost() != null) {
+                    provider.defaultSerializeField("boost", value.getBoost(), gen);
+                }
+
+                gen.writeEndObject();
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/TermSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/TermSerializer.java
new file mode 100644
index 0000000..3de2ffa
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/TermSerializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.search.TermQuery;
+
+public final class TermSerializer extends JsonSerializer<TermQuery> {
+    static final String NAME = "term";
+
+    @Override
+    public void serialize(final TermQuery term, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.writeStartObject();
+        {
+            gen.writeFieldName(NAME);
+            gen.writeStartObject();
+            {
+                gen.writeFieldName(term.getName());
+                gen.writeObject(term.getValue());
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6Codec.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6Codec.java
new file mode 100644
index 0000000..24003f7
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6Codec.java
@@ -0,0 +1,96 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import java.io.InputStream;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.Codec;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQuery;
+import org.apache.skywalking.library.elasticsearch.requests.search.RangeQuery;
+import org.apache.skywalking.library.elasticsearch.requests.search.TermQuery;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+public final class V6Codec implements Codec {
+    public static final Codec INSTANCE = new V6Codec();
+
+    public static final ObjectMapper MAPPER = new ObjectMapper()
+        .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+        // We added some serializers here and some in their item classes as annotation (e.g.
+        // org.apache.skywalking.library.elasticsearch.requests.search.Sorts),
+        // the basic idea is, if the item class is very basic and are the same serialization method
+        // in both 6.x and 7.x, we set the serializer in their item class as annotation to make it
+        // shared by 6.x and 7.x, without duplicating the serializer codes, otherwise, we add
+        // serializers for each version explicitly in the object mapper.
+        // The 2 methods to add serializers can be changed if some day the basic serializer cannot
+        // be shared between newer versions of ElasticSearch or vice versa.
+        .registerModule(
+            new SimpleModule()
+                .addSerializer(
+                    IndexRequest.class,
+                    new V6IndexRequestSerializer()
+                )
+                .addSerializer(
+                    UpdateRequest.class,
+                    new V6UpdateRequestSerializer()
+                )
+                .addSerializer(
+                    RangeQuery.class,
+                    new RangeQuerySerializer()
+                )
+                .addSerializer(
+                    TermQuery.class,
+                    new TermSerializer()
+                )
+                .addSerializer(
+                    BoolQuery.class,
+                    new BoolQuerySerializer()
+                )
+                .addSerializer(
+                    Mappings.class,
+                    new MappingsSerializer()
+                )
+                .addDeserializer(
+                    Mappings.class,
+                    new V6MappingsDeserializer()
+                )
+        )
+        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    @Override
+    public byte[] encode(final Object request) throws Exception {
+        return MAPPER.writeValueAsBytes(request);
+    }
+
+    @Override
+    public <T> T decode(final InputStream inputStream,
+                        final TypeReference<T> type) throws Exception {
+        return MAPPER.readValue(inputStream, type);
+    }
+
+    @Override
+    public <T> T decode(final InputStream inputStream,
+                        final Class<T> clazz) throws Exception {
+        return MAPPER.readValue(inputStream, clazz);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6IndexRequestSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6IndexRequestSerializer.java
new file mode 100644
index 0000000..467a444
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6IndexRequestSerializer.java
@@ -0,0 +1,48 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.io.SerializedString;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+
+final class V6IndexRequestSerializer extends JsonSerializer<IndexRequest> {
+    @Override
+    public void serialize(final IndexRequest value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.setRootValueSeparator(new SerializedString("\n"));
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("index");
+            gen.writeStartObject();
+            {
+                gen.writeStringField("_index", value.getIndex());
+                gen.writeStringField("_type", value.getType());
+                gen.writeStringField("_id", value.getId());
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+
+        gen.writeObject(value.getDoc());
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6MappingsDeserializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6MappingsDeserializer.java
new file mode 100644
index 0000000..aedcfb3
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6MappingsDeserializer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+final class V6MappingsDeserializer extends JsonDeserializer<Mappings> {
+    @Override
+    @SuppressWarnings("unchecked")
+    public Mappings deserialize(final JsonParser p, final DeserializationContext ctxt)
+        throws IOException {
+
+        final Map<String, Object> m =
+            p.readValueAs(new TypeReference<Map<String, Object>>() {
+            });
+        final Optional<Map.Entry<String, Object>> typeMapping =
+            m.entrySet()
+             .stream()
+             .filter(it -> it.getValue() instanceof Map)
+             .filter(it -> ((Map<String, Object>) it.getValue()).containsKey("properties"))
+             .peek(it -> it.setValue(((Map<?, ?>) it.getValue()).get("properties")))
+             .findFirst();
+
+        final Optional<Mappings> result = typeMapping.map(it -> {
+            final Mappings mappings = new Mappings();
+            mappings.setType(it.getKey());
+            mappings.setProperties((Map<String, Object>) it.getValue());
+            return mappings;
+        });
+        return result.orElse(null);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6UpdateRequestSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6UpdateRequestSerializer.java
new file mode 100644
index 0000000..38fcb2b
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V6UpdateRequestSerializer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.io.SerializedString;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+
+final class V6UpdateRequestSerializer extends JsonSerializer<UpdateRequest> {
+    @Override
+    public void serialize(final UpdateRequest value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.setRootValueSeparator(new SerializedString("\n"));
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("update");
+            gen.writeStartObject();
+            {
+                gen.writeStringField("_index", value.getIndex());
+                gen.writeStringField("_type", value.getType());
+                gen.writeStringField("_id", value.getId());
+            }
+            gen.writeEndObject();
+        }
+
+        gen.writeEndObject();
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("doc");
+            gen.writeObject(value.getDoc());
+        }
+        gen.writeEndObject();
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7Codec.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7Codec.java
new file mode 100644
index 0000000..9fae2c6
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7Codec.java
@@ -0,0 +1,92 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import java.io.InputStream;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+import org.apache.skywalking.library.elasticsearch.requests.factory.Codec;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQuery;
+import org.apache.skywalking.library.elasticsearch.requests.search.RangeQuery;
+import org.apache.skywalking.library.elasticsearch.requests.search.TermQuery;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+public final class V7Codec implements Codec {
+    public static final Codec INSTANCE = new V7Codec();
+
+    public static final ObjectMapper MAPPER = new ObjectMapper()
+        .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+        // We added some serializers here and some in their item classes as annotation (e.g.
+        // org.apache.skywalking.library.elasticsearch.requests.search.Sorts),
+        // the basic idea is, if the item class is very basic and are the same serialization method
+        // in both 6.x and 7.x, we set the serializer in their item class as annotation to make it
+        // shared by 6.x and 7.x, without duplicating the serializer codes, otherwise, we add
+        // serializers for each version explicitly in the object mapper.
+        // The 2 methods to add serializers can be changed if some day the basic serializer cannot
+        // be shared between newer versions of ElasticSearch or vice versa.
+        .registerModule(
+            new SimpleModule()
+                .addSerializer(
+                    IndexRequest.class,
+                    new V7IndexRequestSerializer()
+                )
+                .addSerializer(
+                    UpdateRequest.class,
+                    new V7UpdateRequestSerializer()
+                )
+                .addSerializer(
+                    RangeQuery.class,
+                    new RangeQuerySerializer()
+                )
+                .addSerializer(
+                    TermQuery.class,
+                    new TermSerializer()
+                )
+                .addSerializer(
+                    BoolQuery.class,
+                    new BoolQuerySerializer()
+                )
+                .addDeserializer(
+                    Mappings.class,
+                    new V7MappingsDeserializer()
+                )
+        )
+        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    @Override
+    public byte[] encode(final Object request) throws Exception {
+        return MAPPER.writeValueAsBytes(request);
+    }
+
+    @Override
+    public <T> T decode(final InputStream inputStream,
+                        final TypeReference<T> type) throws Exception {
+        return MAPPER.readValue(inputStream, type);
+    }
+
+    @Override
+    public <T> T decode(final InputStream inputStream,
+                        final Class<T> clazz) throws Exception {
+        return MAPPER.readValue(inputStream, clazz);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7IndexRequestSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7IndexRequestSerializer.java
new file mode 100644
index 0000000..7fbfe66
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7IndexRequestSerializer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.io.SerializedString;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+
+final class V7IndexRequestSerializer extends JsonSerializer<IndexRequest> {
+    @Override
+    public void serialize(final IndexRequest value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.setRootValueSeparator(new SerializedString("\n"));
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("index");
+            gen.writeStartObject();
+            {
+                gen.writeStringField("_index", value.getIndex());
+                gen.writeStringField("_id", value.getId());
+            }
+            gen.writeEndObject();
+        }
+        gen.writeEndObject();
+
+        gen.writeObject(value.getDoc());
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7MappingsDeserializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7MappingsDeserializer.java
new file mode 100644
index 0000000..23bcf96
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7MappingsDeserializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
+
+final class V7MappingsDeserializer extends JsonDeserializer<Mappings> {
+    @Override
+    @SuppressWarnings("unchecked")
+    public Mappings deserialize(final JsonParser p, final DeserializationContext ctxt)
+        throws IOException {
+
+        final Map<String, Object> m =
+            p.readValueAs(new TypeReference<Map<String, Object>>() {
+            });
+
+        final Map.Entry<String, Object> it = m.entrySet().iterator().next();
+        final Mappings mappings = new Mappings();
+        mappings.setType(it.getKey());
+        mappings.setProperties((Map<String, Object>) it.getValue());
+        return mappings;
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7UpdateRequestSerializer.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7UpdateRequestSerializer.java
new file mode 100644
index 0000000..53a8d70
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/factory/v6/codec/V7UpdateRequestSerializer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.factory.v6.codec;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.io.SerializedString;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+import org.apache.skywalking.library.elasticsearch.requests.UpdateRequest;
+
+final class V7UpdateRequestSerializer extends JsonSerializer<UpdateRequest> {
+    @Override
+    public void serialize(final UpdateRequest value, final JsonGenerator gen,
+                          final SerializerProvider provider) throws IOException {
+        gen.setRootValueSeparator(new SerializedString("\n"));
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("update");
+            gen.writeStartObject();
+            {
+                gen.writeStringField("_index", value.getIndex());
+                gen.writeStringField("_id", value.getId());
+            }
+            gen.writeEndObject();
+        }
+
+        gen.writeEndObject();
+
+        gen.writeStartObject();
+        {
+            gen.writeFieldName("doc");
+            gen.writeObject(value.getDoc());
+        }
+        gen.writeEndObject();
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQuery.java
similarity index 61%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQuery.java
index 7960299..71dc2ae 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQuery.java
@@ -13,14 +13,20 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import com.google.common.collect.ImmutableList;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class BoolQuery extends Query {
+    private final ImmutableList<Query> must;
+    private final ImmutableList<Query> mustNot;
+    private final ImmutableList<Query> should;
+    private final ImmutableList<Query> shouldNot;
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQueryBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQueryBuilder.java
new file mode 100644
index 0000000..aacafaa
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/BoolQueryBuilder.java
@@ -0,0 +1,133 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.google.common.collect.ImmutableList;
+
+import static java.util.Objects.requireNonNull;
+
+public final class BoolQueryBuilder implements QueryBuilder {
+    private ImmutableList.Builder<Query> must;
+    private ImmutableList.Builder<Query> mustNot;
+    private ImmutableList.Builder<Query> should;
+    private ImmutableList.Builder<Query> shouldNot;
+
+    BoolQueryBuilder() {
+    }
+
+    public BoolQueryBuilder must(Query query) {
+        requireNonNull(query, "query");
+        must().add(query);
+        return this;
+    }
+
+    public BoolQueryBuilder must(QueryBuilder queryBuilder) {
+        requireNonNull(queryBuilder, "queryBuilder");
+        return must(queryBuilder.build());
+    }
+
+    public BoolQueryBuilder mustNot(Query query) {
+        requireNonNull(query, "query");
+        mustNot().add(query);
+        return this;
+    }
+
+    public BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
+        requireNonNull(queryBuilder, "queryBuilder");
+        return mustNot(queryBuilder.build());
+    }
+
+    public BoolQueryBuilder should(Query query) {
+        requireNonNull(query, "query");
+        should().add(query);
+        return this;
+    }
+
+    public BoolQueryBuilder should(QueryBuilder queryBuilder) {
+        requireNonNull(queryBuilder, "queryBuilder");
+        return should(queryBuilder.build());
+    }
+
+    public BoolQueryBuilder shouldNot(Query query) {
+        requireNonNull(query, "query");
+        shouldNot().add(query);
+        return this;
+    }
+
+    public BoolQueryBuilder shouldNot(QueryBuilder queryBuilder) {
+        requireNonNull(queryBuilder, "queryBuilder");
+        return shouldNot(queryBuilder.build());
+    }
+
+    private ImmutableList.Builder<Query> must() {
+        if (must == null) {
+            must = ImmutableList.builder();
+        }
+        return must;
+    }
+
+    private ImmutableList.Builder<Query> mustNot() {
+        if (mustNot == null) {
+            mustNot = ImmutableList.builder();
+        }
+        return mustNot;
+    }
+
+    private ImmutableList.Builder<Query> should() {
+        if (should == null) {
+            should = ImmutableList.builder();
+        }
+        return should;
+    }
+
+    private ImmutableList.Builder<Query> shouldNot() {
+        if (shouldNot == null) {
+            shouldNot = ImmutableList.builder();
+        }
+        return shouldNot;
+    }
+
+    @Override
+    public Query build() {
+        final ImmutableList<Query> must;
+        if (this.must == null) {
+            must = null;
+        } else {
+            must = this.must.build();
+        }
+        final ImmutableList<Query> should;
+        if (this.should == null) {
+            should = null;
+        } else {
+            should = this.should.build();
+        }
+        final ImmutableList<Query> mustNot;
+        if (this.mustNot == null) {
+            mustNot = null;
+        } else {
+            mustNot = this.mustNot.build();
+        }
+        final ImmutableList<Query> shouldNot;
+        if (this.shouldNot == null) {
+            shouldNot = null;
+        } else {
+            shouldNot = this.shouldNot.build();
+        }
+        return new BoolQuery(must, mustNot, should, shouldNot);
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/IdsQuery.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/IdsQuery.java
new file mode 100644
index 0000000..b96bd51
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/IdsQuery.java
@@ -0,0 +1,49 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = IdsQuery.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class IdsQuery extends Query {
+    private static final String NAME = "ids";
+
+    private final ImmutableList<String> ids;
+
+    static class Serializer extends JsonSerializer<IdsQuery> {
+        @Override
+        public void serialize(final IdsQuery value, final JsonGenerator gen,
+                              final SerializerProvider provider)
+            throws IOException {
+            gen.writeFieldName(NAME);
+            gen.writeStartObject();
+            gen.writeObjectField("values", ids());
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchPhaseQuery.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchPhaseQuery.java
new file mode 100644
index 0000000..9cb3565
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchPhaseQuery.java
@@ -0,0 +1,49 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = MatchPhaseQuery.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class MatchPhaseQuery extends Query {
+    private final String name;
+    private final String text;
+
+    static class Serializer extends JsonSerializer<MatchPhaseQuery> {
+        @Override
+        public void serialize(final MatchPhaseQuery value, final JsonGenerator gen,
+                              final SerializerProvider provider)
+            throws IOException {
+            gen.writeFieldName("match_phrase");
+            gen.writeStartObject();
+            {
+                gen.writeStringField(value.getName(), value.getText());
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchQuery.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchQuery.java
new file mode 100644
index 0000000..fa44e99
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/MatchQuery.java
@@ -0,0 +1,49 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = MatchQuery.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class MatchQuery extends Query {
+    private final String name;
+    private final String text;
+
+    static class Serializer extends JsonSerializer<MatchQuery> {
+        @Override
+        public void serialize(final MatchQuery value, final JsonGenerator gen,
+                              final SerializerProvider provider)
+            throws IOException {
+            gen.writeFieldName("match");
+            gen.writeStartObject();
+            {
+                gen.writeStringField(value.getName(), value.getText());
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Query.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Query.java
new file mode 100644
index 0000000..5ec0d40
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Query.java
@@ -0,0 +1,80 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Represents criteria when matching documents in ElasticSearch.
+ */
+public abstract class Query {
+    public static RangeQueryBuilder range(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        return new RangeQueryBuilder(name);
+    }
+
+    public static TermQuery term(String name, Object value) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        requireNonNull(value, "value");
+        return new TermQuery(name, value);
+    }
+
+    public static TermsQuery terms(String name, List<?> values) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        requireNonNull(values, "values");
+        return new TermsQuery(name, values);
+    }
+
+    public static MatchQuery match(String name, String text) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        checkArgument(!Strings.isNullOrEmpty(text), "text cannot be blank");
+        return new MatchQuery(name, text);
+    }
+
+    public static MatchQuery match(String name, Object value) {
+        requireNonNull(value, "value");
+        return match(name, value.toString());
+    }
+
+    public static MatchPhaseQuery matchPhrase(String name, String text) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        checkArgument(!Strings.isNullOrEmpty(text), "text cannot be blank");
+        return new MatchPhaseQuery(name, text);
+    }
+
+    public static IdsQuery ids(String... ids) {
+        requireNonNull(ids, "ids");
+        checkArgument(ids.length > 0, "ids cannot be empty");
+        return ids(Arrays.asList(ids));
+    }
+
+    public static IdsQuery ids(Iterable<String> ids) {
+        requireNonNull(ids, "ids");
+        return new IdsQuery(ImmutableList.<String>builder().addAll(ids).build());
+    }
+
+    public static BoolQueryBuilder bool() {
+        return new BoolQueryBuilder();
+    }
+}
diff --git a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/QueryBuilder.java
similarity index 72%
copy from oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/QueryBuilder.java
index f91f5f8..8b7a948 100644
--- a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/QueryBuilder.java
@@ -13,17 +13,10 @@
  * 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.skywalking.oap.server.starter;
+package org.apache.skywalking.library.elasticsearch.requests.search;
 
-/**
- * OAP starter specific for the ES7 storage. This includes the same code of OAPServerStartUp in the `server-starter`
- * module.
- */
-public class OAPServerStartUp {
-    public static void main(String[] args) {
-        OAPServerBootstrap.start();
-    }
+public interface QueryBuilder {
+    Query build();
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQuery.java
similarity index 64%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQuery.java
index 7960299..403f6f8 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQuery.java
@@ -13,14 +13,21 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class RangeQuery extends Query {
+    private final String name;
+    private final Object gte;
+    private final Object gt;
+    private final Object lte;
+    private final Object lt;
+    private final Double boost;
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQueryBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQueryBuilder.java
new file mode 100644
index 0000000..1430862
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/RangeQueryBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.google.common.base.Strings;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public final class RangeQueryBuilder implements QueryBuilder {
+    private final String name;
+    private Object gte;
+    private Object gt;
+    private Object lte;
+    private Object lt;
+    private Double boost;
+
+    RangeQueryBuilder(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be null or empty");
+
+        this.name = name;
+    }
+
+    public RangeQueryBuilder gte(Object gte) {
+        this.gte = requireNonNull(gte, "gte");
+        return this;
+    }
+
+    public RangeQueryBuilder gt(Object gt) {
+        this.gt = requireNonNull(gt, "gt");
+        return this;
+    }
+
+    public RangeQueryBuilder lte(Object lte) {
+        this.lte = requireNonNull(lte, "lte");
+        return this;
+    }
+
+    public RangeQueryBuilder lt(Object lt) {
+        this.lt = requireNonNull(lt, "lt");
+        return this;
+    }
+
+    public RangeQueryBuilder boost(Double boost) {
+        requireNonNull(boost, "boost");
+
+        this.boost = boost;
+        return this;
+    }
+
+    @Override
+    public Query build() {
+        return new RangeQuery(name, gte, gt, lte, lt, boost);
+    }
+}
diff --git a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Search.java
similarity index 50%
rename from oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Search.java
index f91f5f8..7b0aec8 100644
--- a/oap-server/server-starter-es7/src/main/java/org/apache/skywalking/oap/server/starter/OAPServerStartUp.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Search.java
@@ -13,17 +13,31 @@
  * 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.skywalking.oap.server.starter;
+package org.apache.skywalking.library.elasticsearch.requests.search;
+
+import com.google.common.collect.ImmutableMap;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.Aggregation;
 
 /**
- * OAP starter specific for the ES7 storage. This includes the same code of OAPServerStartUp in the `server-starter`
- * module.
+ * Represents the criteria when searching documents in ElasticSearch.
+ *
+ * @see SearchBuilder to build an immutable instance of this class.
  */
-public class OAPServerStartUp {
-    public static void main(String[] args) {
-        OAPServerBootstrap.start();
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class Search {
+    private final Integer from;
+    private final Integer size;
+    private final Query query;
+    private final Sorts sort;
+    private final ImmutableMap<String, Aggregation> aggregations;
+
+    public static SearchBuilder builder() {
+        return new SearchBuilder();
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/SearchBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/SearchBuilder.java
new file mode 100644
index 0000000..11a442d
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/SearchBuilder.java
@@ -0,0 +1,114 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.Aggregation;
+import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.AggregationBuilder;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public final class SearchBuilder {
+    private Integer from;
+    private Integer size;
+    private Query query;
+    private ImmutableList.Builder<Sort> sort;
+    private ImmutableMap.Builder<String, Aggregation> aggregations;
+
+    SearchBuilder() {
+    }
+
+    public SearchBuilder from(Integer from) {
+        requireNonNull(from, "from");
+        checkArgument(from >= 0, "from must be >= 0, but was %s", from);
+        this.from = from;
+        return this;
+    }
+
+    public SearchBuilder size(Integer size) {
+        requireNonNull(size, "size");
+        checkArgument(size >= 0, "size must be positive, but was %s", size);
+        this.size = size;
+        return this;
+    }
+
+    public SearchBuilder sort(String by, Sort.Order order) {
+        checkArgument(!Strings.isNullOrEmpty(by), "by cannot be blank");
+        requireNonNull(order, "order");
+        sort().add(new Sort(by, order));
+        return this;
+    }
+
+    public SearchBuilder query(Query query) {
+        requireNonNull(query, "query");
+        this.query = query;
+        return this;
+    }
+
+    public SearchBuilder query(QueryBuilder queryBuilder) {
+        return query(queryBuilder.build());
+    }
+
+    public SearchBuilder aggregation(Aggregation aggregation) {
+        requireNonNull(aggregation, "aggregation");
+        aggregations().put(aggregation.name(), aggregation);
+        return this;
+    }
+
+    public SearchBuilder aggregation(AggregationBuilder builder) {
+        requireNonNull(builder, "builder");
+        return aggregation(builder.build());
+    }
+
+    public Search build() {
+        final Sorts sorts;
+        if (sort == null) {
+            sorts = null;
+        } else {
+            sorts = new Sorts(sort.build());
+        }
+
+        final ImmutableMap<String, Aggregation> aggregations;
+        if (this.aggregations == null) {
+            aggregations = null;
+        } else {
+            aggregations = aggregations().build();
+        }
+
+        return new Search(
+            from, size, query, sorts, aggregations
+        );
+    }
+
+    private ImmutableList.Builder<Sort> sort() {
+        if (sort == null) {
+            sort = ImmutableList.builder();
+        }
+        return sort;
+    }
+
+    private ImmutableMap.Builder<String, Aggregation> aggregations() {
+        if (aggregations == null) {
+            aggregations = ImmutableMap.builder();
+        }
+        return aggregations;
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/MetadataQueryEs7DAO.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sort.java
similarity index 59%
rename from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/MetadataQueryEs7DAO.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sort.java
index 89813d4..e99bf39 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/MetadataQueryEs7DAO.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sort.java
@@ -13,17 +13,32 @@
  * 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.skywalking.oap.server.storage.plugin.elasticsearch7.query;
+package org.apache.skywalking.library.elasticsearch.requests.search;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class Sort {
+    private final String name;
+    private final Order order;
+
+    public enum Order {
+        ASC("asc"), DESC("desc");
 
-import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
-import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.MetadataQueryEsDAO;
+        final String value;
 
-public class MetadataQueryEs7DAO extends MetadataQueryEsDAO {
+        Order(final String value) {
+            this.value = value;
+        }
 
-    public MetadataQueryEs7DAO(final ElasticSearchClient client, final int queryMaxSize) {
-        super(client, queryMaxSize);
+        @Override
+        public String toString() {
+            return value;
+        }
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sorts.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sorts.java
new file mode 100644
index 0000000..9088363
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/Sorts.java
@@ -0,0 +1,70 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = Sorts.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+final class Sorts implements Iterable<Sort> {
+    private final ImmutableList<Sort> sorts;
+
+    @Override
+    public Iterator<Sort> iterator() {
+        if (sorts == null) {
+            return Collections.emptyIterator();
+        }
+        return sorts.iterator();
+    }
+
+    static class Serializer extends JsonSerializer<Sorts> {
+        @Override
+        public void serialize(final Sorts value, final JsonGenerator gen,
+                              final SerializerProvider provider)
+            throws IOException {
+
+            gen.writeStartArray();
+            {
+                for (final Sort sort : value) {
+                    gen.writeStartObject();
+                    {
+                        gen.writeFieldName(sort.getName());
+                        gen.writeStartObject();
+                        {
+                            gen.writeStringField("order", sort.getOrder().toString());
+                        }
+                        gen.writeEndObject();
+                    }
+                    gen.writeEndObject();
+                }
+            }
+            gen.writeEndArray();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermQuery.java
similarity index 71%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermQuery.java
index 7960299..236c6e5 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermQuery.java
@@ -13,14 +13,17 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class TermQuery extends Query {
+    private final String name;
+    private final Object value;
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermsQuery.java
similarity index 69%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermsQuery.java
index 7960299..f3ca634 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/TermsQuery.java
@@ -13,14 +13,18 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import java.util.List;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class TermsQuery extends Query {
+    private final String name;
+    private final List<?> values;
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/Aggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/Aggregation.java
new file mode 100644
index 0000000..be1c72f
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/Aggregation.java
@@ -0,0 +1,50 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.google.common.base.Strings;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public abstract class Aggregation {
+    public abstract String name();
+
+    public static TermsAggregationBuilder terms(String name) {
+        return new TermsAggregationBuilder(name);
+    }
+
+    public static AvgAggregationBuilder avg(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        return new AvgAggregationBuilder(name);
+    }
+
+    public static AvgAggregationBuilder min(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        return new AvgAggregationBuilder(name);
+    }
+
+    public static MaxAggregationBuilder max(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        return new MaxAggregationBuilder(name);
+    }
+
+    public static SumAggregationBuilder sum(String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        return new SumAggregationBuilder(name);
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AggregationBuilder.java
similarity index 77%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AggregationBuilder.java
index 7960299..732a3b6 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AggregationBuilder.java
@@ -13,14 +13,10 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
-
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+public interface AggregationBuilder {
+    Aggregation build();
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregation.java
new file mode 100644
index 0000000..4319b40
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregation.java
@@ -0,0 +1,57 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+@JsonSerialize(using = AvgAggregation.Serializer.class)
+public final class AvgAggregation extends Aggregation {
+    private final String name;
+    private final String field;
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    static final class Serializer extends JsonSerializer<AvgAggregation> {
+        @Override
+        public void serialize(final AvgAggregation value, final JsonGenerator gen,
+                              final SerializerProvider provider) throws IOException {
+            gen.writeStartObject();
+            {
+                gen.writeFieldName("avg");
+                gen.writeStartObject();
+                {
+                    gen.writeStringField("field", value.getField());
+                }
+                gen.writeEndObject();
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7InsertRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregationBuilder.java
similarity index 57%
rename from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7InsertRequest.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregationBuilder.java
index 720a334..53d050c 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/client/ElasticSearch7InsertRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/AvgAggregationBuilder.java
@@ -15,22 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.client;
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.google.common.base.Strings;
 
-public class ElasticSearch7InsertRequest extends IndexRequest implements InsertRequest {
+import static com.google.common.base.Preconditions.checkArgument;
 
-    public ElasticSearch7InsertRequest(String index, String id) {
-        super(index);
-        id(id);
+public final class AvgAggregationBuilder implements AggregationBuilder {
+    private final String name;
+
+    private String field;
+
+    AvgAggregationBuilder(String name) {
+        this.name = name;
     }
 
-    @Override
-    public ElasticSearch7InsertRequest source(XContentBuilder sourceBuilder) {
-        super.source(sourceBuilder);
+    public AvgAggregationBuilder field(String field) {
+        checkArgument(!Strings.isNullOrEmpty(field), "field cannot be blank");
+        this.field = field;
         return this;
     }
+
+    @Override
+    public AvgAggregation build() {
+        return new AvgAggregation(name, field);
+    }
 }
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClientException.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/BucketOrder.java
similarity index 64%
rename from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClientException.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/BucketOrder.java
index 7b00473..e7e23f4 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/grpc/GRPCClientException.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/BucketOrder.java
@@ -13,20 +13,21 @@
  * 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.skywalking.oap.server.library.client.grpc;
-
-import org.apache.skywalking.oap.server.library.client.ClientException;
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-public class GRPCClientException extends ClientException {
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 
-    public GRPCClientException(String message) {
-        super(message);
-    }
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class BucketOrder {
+    private final String path;
+    private final boolean asc;
 
-    public GRPCClientException(String message, Throwable cause) {
-        super(message, cause);
+    public static BucketOrder aggregation(String path, boolean asc) {
+        return new BucketOrder(path, asc);
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregation.java
new file mode 100644
index 0000000..649ebe1
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregation.java
@@ -0,0 +1,57 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = MaxAggregation.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class MaxAggregation extends Aggregation {
+    private final String name;
+    private final String field;
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    static final class Serializer extends JsonSerializer<MaxAggregation> {
+        @Override
+        public void serialize(final MaxAggregation value, final JsonGenerator gen,
+                              final SerializerProvider provider) throws IOException {
+            gen.writeStartObject();
+            {
+                gen.writeFieldName("max");
+                gen.writeStartObject();
+                {
+                    gen.writeStringField("field", value.getField());
+                }
+                gen.writeEndObject();
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregationBuilder.java
similarity index 57%
copy from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregationBuilder.java
index 2663856..8b74160 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MaxAggregationBuilder.java
@@ -15,20 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.google.common.base.Strings;
 
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+import static com.google.common.base.Preconditions.checkArgument;
 
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
+public final class MaxAggregationBuilder implements AggregationBuilder {
+    private final String name;
+
+    private String field;
+
+    MaxAggregationBuilder(String name) {
+        this.name = name;
     }
 
-    @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
+    public MaxAggregationBuilder field(String field) {
+        checkArgument(!Strings.isNullOrEmpty(field), "field cannot be blank");
+        this.field = field;
         return this;
     }
+
+    @Override
+    public MaxAggregation build() {
+        return new MaxAggregation(name, field);
+    }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregation.java
new file mode 100644
index 0000000..05012a0
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregation.java
@@ -0,0 +1,57 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = MinAggregation.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class MinAggregation extends Aggregation {
+    private final String name;
+    private final String field;
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    static final class Serializer extends JsonSerializer<MinAggregation> {
+        @Override
+        public void serialize(final MinAggregation value, final JsonGenerator gen,
+                              final SerializerProvider provider) throws IOException {
+            gen.writeStartObject();
+            {
+                gen.writeFieldName("min");
+                gen.writeStartObject();
+                {
+                    gen.writeStringField("field", value.getField());
+                }
+                gen.writeEndObject();
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregationBuilder.java
similarity index 57%
copy from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregationBuilder.java
index 2663856..02e2c9e 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/MinAggregationBuilder.java
@@ -15,20 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.google.common.base.Strings;
 
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+import static com.google.common.base.Preconditions.checkArgument;
 
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
+public final class MinAggregationBuilder implements AggregationBuilder {
+    private final String name;
+
+    private String field;
+
+    MinAggregationBuilder(String name) {
+        this.name = name;
     }
 
-    @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
+    public MinAggregationBuilder field(String field) {
+        checkArgument(!Strings.isNullOrEmpty(field), "field cannot be blank");
+        this.field = field;
         return this;
     }
+
+    @Override
+    public MinAggregation build() {
+        return new MinAggregation(name, field);
+    }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregation.java
new file mode 100644
index 0000000..38690e1
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregation.java
@@ -0,0 +1,57 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@JsonSerialize(using = SumAggregation.Serializer.class)
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+public final class SumAggregation extends Aggregation {
+    private final String name;
+    private final String field;
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    static final class Serializer extends JsonSerializer<SumAggregation> {
+        @Override
+        public void serialize(final SumAggregation value, final JsonGenerator gen,
+                              final SerializerProvider provider) throws IOException {
+            gen.writeStartObject();
+            {
+                gen.writeFieldName("sum");
+                gen.writeStartObject();
+                {
+                    gen.writeStringField("field", value.getField());
+                }
+                gen.writeEndObject();
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregationBuilder.java
similarity index 57%
copy from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregationBuilder.java
index 2663856..b7a7f88 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/SumAggregationBuilder.java
@@ -15,20 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.requests.search.aggregation;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.google.common.base.Strings;
 
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+import static com.google.common.base.Preconditions.checkArgument;
 
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
+public final class SumAggregationBuilder implements AggregationBuilder {
+    private final String name;
+
+    private String field;
+
+    SumAggregationBuilder(String name) {
+        this.name = name;
     }
 
-    @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
+    public SumAggregationBuilder field(String field) {
+        checkArgument(!Strings.isNullOrEmpty(field), "field cannot be blank");
+        this.field = field;
         return this;
     }
+
+    @Override
+    public MaxAggregation build() {
+        return new MaxAggregation(name, field);
+    }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregation.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregation.java
new file mode 100644
index 0000000..0cb72f7
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregation.java
@@ -0,0 +1,65 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
+@JsonSerialize(using = TermsAggregation.Serializer.class)
+public final class TermsAggregation extends Aggregation {
+    private final String name;
+    private final String field;
+    private final BucketOrder order;
+    private final Integer size;
+    private final ImmutableMap<String, Aggregation> aggregations;
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    static final class Serializer extends JsonSerializer<TermsAggregation> {
+        @Override
+        public void serialize(final TermsAggregation value, final JsonGenerator gen,
+                              final SerializerProvider provider) throws IOException {
+            gen.writeStartObject();
+            {
+                gen.writeFieldName("terms");
+                gen.writeStartObject();
+                {
+                    gen.writeStringField("field", value.getField());
+                }
+                gen.writeEndObject();
+
+                if (value.getAggregations() != null && !value.getAggregations().isEmpty()) {
+                    gen.writeObjectField("aggregations", value.getAggregations());
+                }
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregationBuilder.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregationBuilder.java
new file mode 100644
index 0000000..3c3ccbc
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/requests/search/aggregation/TermsAggregationBuilder.java
@@ -0,0 +1,87 @@
+/*
+ * 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.skywalking.library.elasticsearch.requests.search.aggregation;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public final class TermsAggregationBuilder implements AggregationBuilder {
+    private final String name;
+
+    private String field;
+    private BucketOrder order;
+    private Integer size;
+    private ImmutableMap.Builder<String, Aggregation> subAggregations;
+
+    TermsAggregationBuilder(final String name) {
+        checkArgument(!Strings.isNullOrEmpty(name), "name cannot be blank");
+        this.name = name;
+    }
+
+    public TermsAggregationBuilder field(String field) {
+        checkArgument(!Strings.isNullOrEmpty(field), "field cannot be blank");
+        this.field = field;
+        return this;
+    }
+
+    public TermsAggregationBuilder order(BucketOrder order) {
+        requireNonNull(order, "order");
+        this.order = order;
+        return this;
+    }
+
+    public TermsAggregationBuilder size(int size) {
+        checkArgument(size >= 0, "size must be >= 0");
+        this.size = size;
+        return this;
+    }
+
+    public TermsAggregationBuilder subAggregation(Aggregation subAggregation) {
+        requireNonNull(subAggregation, "subAggregation");
+        subAggregations().put(subAggregation.name(), subAggregation);
+        return this;
+    }
+
+    public TermsAggregationBuilder subAggregation(AggregationBuilder subAggregationBuilder) {
+        requireNonNull(subAggregationBuilder, "subAggregationBuilder");
+        return subAggregation(subAggregationBuilder.build());
+    }
+
+    @Override
+    public TermsAggregation build() {
+        ImmutableMap<String, Aggregation> subAggregations;
+        if (this.subAggregations == null) {
+            subAggregations = null;
+        } else {
+            subAggregations = this.subAggregations.build();
+        }
+        return new TermsAggregation(
+            name, field, order, size, subAggregations
+        );
+    }
+
+    private ImmutableMap.Builder<String, Aggregation> subAggregations() {
+        if (subAggregations == null) {
+            subAggregations = ImmutableMap.builder();
+        }
+        return subAggregations;
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Document.java
similarity index 70%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Document.java
index 7960299..89e0565 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Document.java
@@ -13,14 +13,21 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+import lombok.Data;
+
+@Data
+public final class Document {
+    private boolean found;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+    @JsonProperty("_id")
+    private String id;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+    @JsonProperty("_source")
+    private Map<String, Object> source;
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Documents.java
similarity index 69%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Documents.java
index 7960299..6084cab 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Documents.java
@@ -13,14 +13,20 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response;
+
+import java.util.Iterator;
+import java.util.List;
+import lombok.Data;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+@Data
+public final class Documents implements Iterable<Document> {
+    private List<Document> docs;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
+    @Override
+    public Iterator<Document> iterator() {
+        return docs.stream().filter(Document::isFound).iterator();
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Config.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Index.java
similarity index 75%
rename from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Config.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Index.java
index 2b3ba51..10032b7 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Config.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Index.java
@@ -13,12 +13,16 @@
  * 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.skywalking.oap.server.storage.plugin.elasticsearch7;
+package org.apache.skywalking.library.elasticsearch.response;
 
-import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchConfig;
+import java.util.Map;
+import lombok.Data;
 
-public class StorageModuleElasticsearch7Config extends StorageModuleElasticsearchConfig {
+@Data
+public final class Index {
+    private Map<String, Object> settings;
+    private Mappings mappings;
+    private Map<String, Object> aliases;
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/IndexTemplate.java
similarity index 70%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/IndexTemplate.java
index 7960299..066fe2c 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/IndexTemplate.java
@@ -13,14 +13,19 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import java.util.List;
+import java.util.Map;
+import lombok.Data;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Data
+public final class IndexTemplate {
+    private int order;
+    private List<String> indexPatterns;
+    private Map<String, Object> settings;
+    private Mappings mappings;
+    private Map<String, Object> aliases;
 }
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Mappings.java
similarity index 58%
rename from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Mappings.java
index 2663856..642dd88 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ElasticSearchUpdateRequest.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/Mappings.java
@@ -15,20 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response;
 
-import org.elasticsearch.action.update.UpdateRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
 
-public class ElasticSearchUpdateRequest extends UpdateRequest implements org.apache.skywalking.oap.server.library.client.request.UpdateRequest {
+@Builder
+@ToString
+@NoArgsConstructor // For deserialization
+@AllArgsConstructor
+public final class Mappings {
+    @Getter
+    @Setter
+    @JsonIgnore
+    private String type;
 
-    public ElasticSearchUpdateRequest(String index, String type, String id) {
-        super(index, type, id);
-    }
-
-    @Override
-    public ElasticSearchUpdateRequest doc(XContentBuilder source) {
-        super.doc(source);
-        return this;
-    }
+    @Getter
+    @Setter
+    private Map<String, Object> properties = new HashMap<>();
 }
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/NodeInfo.java
similarity index 78%
copy from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
copy to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/NodeInfo.java
index 7960299..3e1ea2b 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/NodeInfo.java
@@ -13,14 +13,18 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import lombok.Data;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
+@Data
+public final class NodeInfo {
+    @Data
+    public static class Version {
+        private String number;
     }
+
+    private Version version;
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHit.java
similarity index 51%
rename from oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHit.java
index 0b2501d..5190e1a 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/base/IndexEs7Structures.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHit.java
@@ -13,28 +13,36 @@
  * 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.skywalking.oap.server.storage.plugin.elasticsearch7.base;
+package org.apache.skywalking.library.elasticsearch.response.search;
 
-import java.util.HashMap;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.Map;
-import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexStructures;
-
-public class IndexEs7Structures extends IndexStructures {
+import lombok.Getter;
+import lombok.Setter;
 
-    @Override
-    protected PropertiesExtractor doGetPropertiesExtractor() {
-        return mapping -> (Map<String, Object>) mapping.get("properties");
-    }
+@Getter
+@Setter
+public final class SearchHit implements Iterable<Map.Entry<String, Object>> {
+    @JsonProperty("_index")
+    private String index;
+    @JsonProperty("_type")
+    private String type;
+    @JsonProperty("_id")
+    private String id;
+    @JsonProperty("_score")
+    private double score;
+    @JsonProperty("_source")
+    private Map<String, Object> source;
 
     @Override
-    protected PropertiesWrapper doGetPropertiesWrapper() {
-        return properties -> {
-            HashMap<String, Object> mappings = new HashMap<>();
-            mappings.put("properties", properties);
-            return mappings;
-        };
+    public Iterator<Map.Entry<String, Object>> iterator() {
+        if (source == null) {
+            return Collections.emptyIterator();
+        }
+        return source.entrySet().iterator();
     }
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHits.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHits.java
new file mode 100644
index 0000000..27cc3a2
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchHits.java
@@ -0,0 +1,66 @@
+/*
+ * 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.skywalking.library.elasticsearch.response.search;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public final class SearchHits implements Iterable<SearchHit> {
+    @JsonDeserialize(using = TotalDeserializer.class)
+    private int total;
+    private List<SearchHit> hits;
+
+    public List<SearchHit> getHits() {
+        if (hits != null) {
+            return hits;
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Iterator<SearchHit> iterator() {
+        return getHits().iterator();
+    }
+
+    static final class TotalDeserializer extends JsonDeserializer<Integer> {
+        @Override
+        public Integer deserialize(final JsonParser p, final DeserializationContext ctxt)
+            throws IOException {
+            final JsonNode node = p.getCodec().readTree(p);
+            if (node.isInt()) {
+                return node.asInt();
+            }
+            final JsonNode value = node.get("value");
+            if (value.isInt()) {
+                return value.asInt();
+            }
+            throw new UnsupportedOperationException("Search response total field is not integer");
+        }
+    }
+}
diff --git a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchResponse.java
similarity index 74%
rename from oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
rename to oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchResponse.java
index 7960299..270ac22 100644
--- a/oap-server/server-library/library-client/src/test/java/org/apache/skywalking/oap/server/library/client/elasticsearch/ITElasticSearchClientOfNamespace.java
+++ b/oap-server/server-library/library-elasticsearch-client/src/main/java/org/apache/skywalking/library/elasticsearch/response/search/SearchResponse.java
@@ -13,14 +13,17 @@
  * 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.skywalking.oap.server.library.client.elasticsearch;
+package org.apache.skywalking.library.elasticsearch.response.search;
 
-public class ITElasticSearchClientOfNamespace extends ITElasticSearchClient {
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
 
-    public ITElasticSearchClientOfNamespace() {
-        super("test");
-    }
+@Getter
+@Setter
+public final class SearchResponse {
+    private SearchHits hits = new SearchHits();
+    private Map<String, Object> aggregations;
 }
diff --git a/oap-server/server-library/library-elasticsearch-client/src/test/java/org/apache/skywalking/library/elasticsearch/ITElasticSearchClientTest.java b/oap-server/server-library/library-elasticsearch-client/src/test/java/org/apache/skywalking/library/elasticsearch/ITElasticSearchClientTest.java
new file mode 100644
index 0000000..c51b4fb
--- /dev/null
+++ b/oap-server/server-library/library-elasticsearch-client/src/test/java/org/apache/skywalking/library/elasticsearch/ITElasticSearchClientTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.skywalking.library.elasticsearch;
+
+import java.util.Arrays;
+import java.util.Collection;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.library.elasticsearch.requests.IndexRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RequiredArgsConstructor
+@RunWith(Parameterized.class)
+public class ITElasticSearchClientTest {
+
+    @Parameterized.Parameters(name = "version: {0}")
+    public static Collection<Object[]> versions() {
+        return Arrays.asList(new Object[][] {
+            {"6.3.2"}, {"7.8.0"}
+        });
+    }
+
+    private final String version;
+
+    private ElasticsearchContainer server;
+    private ElasticSearchClient client;
+
+    @Before
+    public void setup() {
+        server = new ElasticsearchContainer(
+            DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch-oss")
+                           .withTag(version)
+        );
+        server.start();
+
+        client = ElasticSearchClient.builder()
+                                    .endpoints(server.getHttpHostAddress())
+                                    .build();
+        client.connect();
+    }
+
+    @After
+    public void tearDown() {
+        server.stop();
+    }
+
+    @Test
+    public void testIndex() {
+        final String index = "test-index";
+        assertFalse(client.index().exists(index));
+        assertFalse(client.index().get(index).isPresent());
+        assertTrue(client.index().create(index, null, null));
+        assertTrue(client.index().exists(index));
+        assertNotNull(client.index().get(index));
+        assertTrue(client.index().delete(index));
+        assertFalse(client.index().get(index).isPresent());
+    }
+
+    @Test
+    public void testDoc() {
+        final String index = "test-index";
+        assertTrue(client.index().create(index, null, null));
+
+        final ImmutableMap<String, Object> doc = ImmutableMap.of("key", "val");
+        final String idWithSpace = "an id"; // UI management templates' IDs contains spaces
+        final String type = "type";
+
+        client.documents().index(
+            IndexRequest.builder()
+                        .index(index)
+                        .type(type)
+                        .id(idWithSpace)
+                        .doc(doc)
+                        .build(), null);
+
+        assertTrue(client.documents().get(index, type, idWithSpace).isPresent());
+        assertEquals(client.documents().get(index, type, idWithSpace).get().getId(), idWithSpace);
+        assertEquals(client.documents().get(index, type, idWithSpace).get().getSource(), doc);
+    }
+}
diff --git a/oap-server/server-library/pom.xml b/oap-server/server-library/pom.xml
index acfcd44..fa37d28 100644
--- a/oap-server/server-library/pom.xml
+++ b/oap-server/server-library/pom.xml
@@ -32,6 +32,7 @@
         <module>library-server</module>
         <module>library-util</module>
         <module>library-client</module>
+        <module>library-elasticsearch-client</module>
     </modules>
 
     <dependencies>
@@ -40,4 +41,4 @@
             <artifactId>apm-util</artifactId>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/pom.xml b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/pom.xml
index f1042c3..d134a4f 100644
--- a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/pom.xml
+++ b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/pom.xml
@@ -33,4 +33,4 @@
             <version>${project.version}</version>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsReader.java b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsReader.java
index b9ebd2b..69d44ca 100644
--- a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsReader.java
+++ b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsReader.java
@@ -18,13 +18,14 @@
 
 package org.apache.skywalking.oap.server.recevier.configuration.discovery;
 
+import com.google.common.hash.Hashing;
 import java.io.InputStream;
 import java.io.Reader;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.codec.digest.DigestUtils;
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.SafeConstructor;
 
@@ -58,10 +59,15 @@ public class AgentConfigurationsReader {
                         map.forEach((key, value) -> {
                             config.put(key.toString(), value.toString());
 
-                            serviceConfigStr.append(key.toString()).append(":").append(value.toString());
+                            serviceConfigStr.append(key).append(":").append(value);
                         });
+
+                        // noinspection UnstableApiUsage
                         AgentConfigurations agentConfigurations = new AgentConfigurations(
-                            k.toString(), config, DigestUtils.sha512Hex(serviceConfigStr.toString()));
+                            k.toString(), config,
+                            Hashing.sha512().hashString(
+                                serviceConfigStr.toString(), StandardCharsets.UTF_8).toString()
+                        );
                         agentConfigurationsTable.getAgentConfigurationsCache()
                                                 .put(agentConfigurations.getService(), agentConfigurations);
                     });
diff --git a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsWatcher.java b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsWatcher.java
index e5ebe39..9c4594a 100644
--- a/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsWatcher.java
+++ b/oap-server/server-receiver-plugin/configuration-discovery-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/recevier/configuration/discovery/AgentConfigurationsWatcher.java
@@ -18,12 +18,12 @@
 
 package org.apache.skywalking.oap.server.recevier.configuration.discovery;
 
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher;
-import org.apache.skywalking.oap.server.library.module.ModuleProvider;
-
+import com.google.common.hash.Hashing;
 import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
+import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
 
 /**
  * AgentConfigurationsWatcher used to handle dynamic configuration changes.
@@ -37,8 +37,10 @@ public class AgentConfigurationsWatcher extends ConfigChangeWatcher {
         super(ConfigurationDiscoveryModule.NAME, provider, "agentConfigurations");
         this.settingsString = null;
         this.agentConfigurationsTable = new AgentConfigurationsTable();
+        // noinspection UnstableApiUsage
         this.emptyAgentConfigurations = new AgentConfigurations(
-            null, new HashMap<>(), DigestUtils.sha512Hex("EMPTY")
+            null, new HashMap<>(),
+            Hashing.sha512().hashString("EMPTY", StandardCharsets.UTF_8).toString()
         );
     }
 
diff --git a/oap-server/server-starter-es7/pom.xml b/oap-server/server-starter-es7/pom.xml
deleted file mode 100644
index 77b0faa..0000000
--- a/oap-server/server-starter-es7/pom.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>oap-server</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>8.8.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>server-starter-es7</artifactId>
-    <description>A backend starter specially for ElasticSearch 7 storage</description>
-    <packaging>jar</packaging>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>server-bootstrap</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-elasticsearch7-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>zipkin-receiver-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <!-- profile exporter -->
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>tool-profile-snapshot-exporter-es7</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.apache.skywalking</groupId>
-                <artifactId>oap-server-bom-es7</artifactId>
-                <version>${project.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-    <build>
-        <finalName>skywalking-oap</finalName>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>assembly</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <configuration>
-                            <descriptors>
-                                <descriptor>src/main/assembly/assembly.xml</descriptor>
-                            </descriptors>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/oap-server/server-starter-es7/src/main/assembly/assembly.xml b/oap-server/server-starter-es7/src/main/assembly/assembly.xml
deleted file mode 100644
index bc3202b..0000000
--- a/oap-server/server-starter-es7/src/main/assembly/assembly.xml
+++ /dev/null
@@ -1,33 +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.
-  ~
-  -->
-
-<assembly
-    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
-    <id>assembly</id>
-    <formats>
-        <format>dir</format>
-    </formats>
-    <dependencySets>
-        <dependencySet>
-            <outputDirectory>/libs</outputDirectory>
-            <scope>runtime</scope>
-        </dependencySet>
-    </dependencySets>
-</assembly>
diff --git a/oap-server/server-storage-plugin/pom.xml b/oap-server/server-storage-plugin/pom.xml
index 7a5215e..60ebd90 100644
--- a/oap-server/server-storage-plugin/pom.xml
+++ b/oap-server/server-storage-plugin/pom.xml
@@ -30,10 +30,9 @@
     <modules>
         <module>storage-jdbc-hikaricp-plugin</module>
         <module>storage-elasticsearch-plugin</module>
-        <module>storage-elasticsearch7-plugin</module>
         <module>storage-zipkin-elasticsearch7-plugin</module>
         <module>storage-influxdb-plugin</module>
         <module>storage-tidb-plugin</module>
     </modules>
 
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/pom.xml b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/pom.xml
index 62a3b7b..affa33f 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/pom.xml
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/pom.xml
@@ -39,11 +39,5 @@
             <artifactId>library-client</artifactId>
             <version>${project.version}</version>
         </dependency>
-        <dependency>
-            <groupId>fr.pilato.elasticsearch.testcontainers</groupId>
-            <artifactId>testcontainers-elasticsearch</artifactId>
-            <version>0.1</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
index ce76619..a95fe1b 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
@@ -19,11 +19,6 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch;
 
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
@@ -34,7 +29,6 @@ import org.apache.skywalking.oap.server.core.storage.IBatchDAO;
 import org.apache.skywalking.oap.server.core.storage.IHistoryDeleteDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageBuilderFactory;
 import org.apache.skywalking.oap.server.core.storage.StorageDAO;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
 import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
@@ -154,7 +148,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
                     elasticSearchClient.connect();
                 }
             }, config.getSecretsManagementFile(), config.getTrustStorePass());
-            /**
+            /*
              * By leveraging the sync update check feature when startup.
              */
             monitor.start();
@@ -215,7 +209,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
             StorageEsInstaller installer = new StorageEsInstaller(elasticSearchClient, getManager(), config);
 
             getManager().find(CoreModule.NAME).provider().getService(ModelCreator.class).addModelListener(installer);
-        } catch (StorageException | IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | CertificateException e) {
+        } catch (Exception e) {
             throw new ModuleStartException(e.getMessage(), e);
         }
     }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/BatchProcessEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/BatchProcessEsDAO.java
index fb8df02..0cc371d 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/BatchProcessEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/BatchProcessEsDAO.java
@@ -20,14 +20,14 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.util.List;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.bulk.BulkProcessor;
 import org.apache.skywalking.oap.server.core.storage.IBatchDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
+import org.apache.skywalking.oap.server.library.client.elasticsearch.IndexRequestWrapper;
+import org.apache.skywalking.oap.server.library.client.elasticsearch.UpdateRequestWrapper;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.PrepareRequest;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
-import org.elasticsearch.action.bulk.BulkProcessor;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.update.UpdateRequest;
 
 @Slf4j
 public class BatchProcessEsDAO extends EsDAO implements IBatchDAO {
@@ -52,7 +52,7 @@ public class BatchProcessEsDAO extends EsDAO implements IBatchDAO {
             this.bulkProcessor = getClient().createBulkProcessor(bulkActions, flushInterval, concurrentRequests);
         }
 
-        this.bulkProcessor.add((IndexRequest) insertRequest);
+        this.bulkProcessor.add(((IndexRequestWrapper) insertRequest).getRequest());
     }
 
     @Override
@@ -64,9 +64,9 @@ public class BatchProcessEsDAO extends EsDAO implements IBatchDAO {
         if (CollectionUtils.isNotEmpty(prepareRequests)) {
             for (PrepareRequest prepareRequest : prepareRequests) {
                 if (prepareRequest instanceof InsertRequest) {
-                    this.bulkProcessor.add((IndexRequest) prepareRequest);
+                    this.bulkProcessor.add(((IndexRequestWrapper) prepareRequest).getRequest());
                 } else {
-                    this.bulkProcessor.add((UpdateRequest) prepareRequest);
+                    this.bulkProcessor.add(((UpdateRequestWrapper) prepareRequest).getRequest());
                 }
             }
         }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java
index f586b6f..0c4562d 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java
@@ -18,34 +18,12 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
-import java.io.IOException;
-import java.util.Map;
-
 import org.apache.skywalking.oap.server.core.storage.AbstractDAO;
-import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentFactory;
 
 public abstract class EsDAO extends AbstractDAO<ElasticSearchClient> {
 
     public EsDAO(ElasticSearchClient client) {
         super(client);
     }
-
-    protected XContentBuilder map2builder(Map<String, Object> objectMap) throws IOException {
-        XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
-        for (Map.Entry<String, Object> entries: objectMap.entrySet()) {
-            Object value = entries.getValue();
-            String key = entries.getKey();
-            if (value instanceof StorageDataComplexObject) {
-                builder.field(key, ((StorageDataComplexObject) value).toStorageData());
-            } else {
-                builder.field(key, value);
-            }
-        }
-        builder.endObject();
-
-        return builder;
-    }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/HistoryDeleteEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/HistoryDeleteEsDAO.java
index af73fc9..5f687a1 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/HistoryDeleteEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/HistoryDeleteEsDAO.java
@@ -20,6 +20,7 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
@@ -53,7 +54,7 @@ public class HistoryDeleteEsDAO extends EsDAO implements IHistoryDeleteDAO {
         }
         deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMdd"));
         String tableName = IndexController.INSTANCE.getTableName(model);
-        List<String> indexes = client.retrievalIndexByAliases(tableName);
+        Collection<String> indexes = client.retrievalIndexByAliases(tableName);
 
         List<String> prepareDeleteIndexes = new ArrayList<>();
         List<String> leftIndices = new ArrayList<>();
@@ -95,7 +96,7 @@ public class HistoryDeleteEsDAO extends EsDAO implements IHistoryDeleteDAO {
                 }
             }
             String tableName = IndexController.INSTANCE.getTableName(model);
-            List<String> indexes;
+            Collection<String> indexes;
             try {
                 indexes = client.retrievalIndexByAliases(tableName);
             } catch (IOException e) {
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexStructures.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexStructures.java
index 74643ac..5c93e86 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexStructures.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexStructures.java
@@ -22,50 +22,37 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import lombok.Getter;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 
 public class IndexStructures {
     private final Map<String, Fields> structures;
-    @Getter
-    private final PropertiesExtractor extractor;
-    @Getter
-    private final PropertiesWrapper wrapper;
 
     public IndexStructures() {
         this.structures = new HashMap<>();
-        this.extractor = doGetPropertiesExtractor();
-        this.wrapper = doGetPropertiesWrapper();
     }
 
-    protected PropertiesExtractor doGetPropertiesExtractor() {
-        return mapping -> (Map<String, Object>) ((Map<String, Object>) mapping.get(
-            ElasticSearchClient.TYPE)).get("properties");
-    }
-
-    protected PropertiesWrapper doGetPropertiesWrapper() {
-        return properties -> {
-            HashMap<String, Object> mappings = new HashMap<>();
-            HashMap<String, Object> types = new HashMap<>();
-            mappings.put(ElasticSearchClient.TYPE, types);
-            types.put("properties", properties);
-            return mappings;
-        };
-    }
-
-    public Map<String, Object> getMapping(String tableName) {
-        return wrapper.wrapper(
-            structures.containsKey(tableName) ? structures.get(tableName).properties : new HashMap<>());
+    public Mappings getMapping(String tableName) {
+        Map<String, Object> properties =
+            structures.containsKey(tableName) ?
+                structures.get(tableName).properties : new HashMap<>();
+        return Mappings.builder()
+                       .type(ElasticSearchClient.TYPE)
+                       .properties(properties)
+                       .build();
     }
 
     /**
-     * Add or append field when the current structures don't contain the input structure or having new fields in it.
+     * Add or append field when the current structures don't contain the input structure or having
+     * new fields in it.
      */
-    public void putStructure(String tableName, Map<String, Object> mapping) {
-        if (Objects.isNull(mapping) || mapping.isEmpty()) {
+    public void putStructure(String tableName, Mappings mapping) {
+        if (Objects.isNull(mapping)
+            || Objects.isNull(mapping.getProperties())
+            || mapping.getProperties().isEmpty()) {
             return;
         }
-        Map<String, Object> properties = this.extractor.extract(mapping);
+        Map<String, Object> properties = mapping.getProperties();
         Fields fields = new Fields(properties);
         if (structures.containsKey(tableName)) {
             structures.get(tableName).appendNewFields(fields);
@@ -77,24 +64,32 @@ public class IndexStructures {
     /**
      * Returns mappings with fields that not exist in the input mappings.
      */
-    public Map<String, Object> diffStructure(String tableName, Map<String, Object> mappings) {
+    public Mappings diffStructure(String tableName, Mappings mappings) {
         if (!structures.containsKey(tableName)) {
-            return new HashMap<>();
+            return new Mappings();
         }
-        Map<String, Object> properties = this.extractor.extract(mappings);
-        Map<String, Object> diffProperties = structures.get(tableName).diffFields(new Fields(properties));
-        return this.wrapper.wrapper(diffProperties);
+        Map<String, Object> properties = mappings.getProperties();
+        Map<String, Object> diffProperties =
+            structures.get(tableName).diffFields(new Fields(properties));
+        return Mappings.builder()
+                       .type(ElasticSearchClient.TYPE)
+                       .properties(diffProperties)
+                       .build();
     }
 
     /**
-     * Returns true when the current structures already contains the properties of the input mappings.
+     * Returns true when the current structures already contains the properties of the input
+     * mappings.
      */
-    public boolean containsStructure(String tableName, Map<String, Object> mappings) {
-        if (Objects.isNull(mappings) || mappings.isEmpty()) {
+    public boolean containsStructure(String tableName, Mappings mappings) {
+        if (Objects.isNull(mappings) ||
+            Objects.isNull(mappings.getProperties()) ||
+            mappings.getProperties().isEmpty()) {
             return true;
         }
         return structures.containsKey(tableName)
-            && structures.get(tableName).containsAllFields(new Fields(this.extractor.extract(mappings)));
+            && structures.get(tableName)
+                         .containsAllFields(new Fields(mappings.getProperties()));
     }
 
     /**
@@ -111,20 +106,23 @@ public class IndexStructures {
          * Returns ture when the input fields have already been stored in the properties.
          */
         private boolean containsAllFields(Fields fields) {
-            return fields.properties.entrySet().stream().allMatch(item -> this.properties.containsKey(item.getKey()));
+            return fields.properties.entrySet().stream()
+                                    .allMatch(item -> this.properties.containsKey(item.getKey()));
         }
 
         /**
          * Append new fields to the properties when have new fields.
          */
         private void appendNewFields(Fields fields) {
-            Map<String, Object> newFields = fields.properties.entrySet()
-                                                             .stream()
-                                                             .filter(e -> !this.properties.containsKey(e.getKey()))
-                                                             .collect(Collectors.toMap(
-                                                                 Map.Entry::getKey, Map.Entry::getValue
-                                                             ));
-            newFields.forEach(properties::put);
+            Map<String, Object> newFields =
+                fields.properties.entrySet()
+                                 .stream()
+                                 .filter(e -> !this.properties.containsKey(e.getKey()))
+                                 .collect(Collectors.toMap(
+                                     Map.Entry::getKey,
+                                     Map.Entry::getValue
+                                 ));
+            properties.putAll(newFields);
         }
 
         /**
@@ -134,24 +132,9 @@ public class IndexStructures {
             return this.properties.entrySet().stream()
                                   .filter(e -> !fields.properties.containsKey(e.getKey()))
                                   .collect(Collectors.toMap(
-                                      Map.Entry::getKey, Map.Entry::getValue
+                                      Map.Entry::getKey,
+                                      Map.Entry::getValue
                                   ));
         }
     }
-
-    /**
-     * Extract properties form the mappings.
-     */
-    @FunctionalInterface
-    public interface PropertiesExtractor {
-        Map<String, Object> extract(Map<String, Object> mappings);
-    }
-
-    /**
-     * Wrapper properties to the mappings.
-     */
-    @FunctionalInterface
-    public interface PropertiesWrapper {
-        Map<String, Object> wrapper(Map<String, Object> properties);
-    }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
index 2c8676c..2925d0f 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java
@@ -19,13 +19,12 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.io.IOException;
+import java.util.Map;
 import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageHashMapBuilder;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
-import org.elasticsearch.action.get.GetResponse;
-import org.elasticsearch.common.xcontent.XContentBuilder;
 
 public class ManagementEsDAO extends EsDAO implements IManagementDAO {
     private final StorageHashMapBuilder<ManagementData> storageBuilder;
@@ -40,12 +39,13 @@ public class ManagementEsDAO extends EsDAO implements IManagementDAO {
     public void insert(Model model, ManagementData managementData) throws IOException {
         String tableName = IndexController.INSTANCE.getTableName(model);
         String docId = IndexController.INSTANCE.generateDocId(model, managementData.id());
-        final GetResponse response = getClient().get(tableName, docId);
-        if (response.isExists()) {
+        final boolean exist = getClient().existDoc(tableName, docId);
+        if (exist) {
             return;
         }
-        XContentBuilder builder = map2builder(
-            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(managementData)));
-        getClient().forceInsert(tableName, docId, builder);
+        Map<String, Object> source =
+            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(
+                managementData));
+        getClient().forceInsert(tableName, docId, source);
     }
-}
\ No newline at end of file
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/MetricsEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/MetricsEsDAO.java
index 38d379d..ce96138 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/MetricsEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/MetricsEsDAO.java
@@ -20,11 +20,11 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.response.Document;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
@@ -35,8 +35,6 @@ import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSear
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.IndicesMetadataCache;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.joda.time.DateTime;
 
 import static java.util.stream.Collectors.groupingBy;
@@ -90,15 +88,12 @@ public class MetricsEsDAO extends EsDAO implements IMetricsDAO {
             String[] ids = metricList.stream()
                                      .map(item -> IndexController.INSTANCE.generateDocId(model, item.id()))
                                      .toArray(String[]::new);
-            try {
-                SearchResponse response = getClient().ids(tableName, ids);
-                for (int i = 0; i < response.getHits().getHits().length; i++) {
-                    Metrics source = storageBuilder.storage2Entity(response.getHits().getAt(i).getSourceAsMap());
+            getClient().ids(tableName, ids).ifPresent(documents -> {
+                for (final Document doc : documents) {
+                    Metrics source = storageBuilder.storage2Entity(doc.getSource());
                     result.add(source);
                 }
-            } catch (IOException e) {
-                log.error("multiGet id=" + Arrays.toString(ids) + " from " + tableName + " fails.", e);
-            }
+            });
         });
 
         return result;
@@ -106,8 +101,8 @@ public class MetricsEsDAO extends EsDAO implements IMetricsDAO {
 
     @Override
     public InsertRequest prepareBatchInsert(Model model, Metrics metrics) throws IOException {
-        XContentBuilder builder = map2builder(
-            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(metrics)));
+        Map<String, Object> builder =
+            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(metrics));
         String modelName = TimeSeriesUtils.writeIndexName(model, metrics.getTimeBucket());
         String id = IndexController.INSTANCE.generateDocId(model, metrics.id());
         return getClient().prepareInsert(modelName, id, builder);
@@ -115,8 +110,8 @@ public class MetricsEsDAO extends EsDAO implements IMetricsDAO {
 
     @Override
     public UpdateRequest prepareBatchUpdate(Model model, Metrics metrics) throws IOException {
-        XContentBuilder builder = map2builder(
-            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(metrics)));
+        Map<String, Object> builder =
+            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(metrics));
         String modelName = TimeSeriesUtils.writeIndexName(model, metrics.getTimeBucket());
         String id = IndexController.INSTANCE.generateDocId(model, metrics.id());
         return getClient().prepareUpdate(modelName, id, builder);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/NoneStreamEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/NoneStreamEsDAO.java
index 3d89243..bb92956 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/NoneStreamEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/NoneStreamEsDAO.java
@@ -19,12 +19,12 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.io.IOException;
+import java.util.Map;
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageHashMapBuilder;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
-import org.elasticsearch.common.xcontent.XContentBuilder;
 
 /**
  * Synchronize storage Elasticsearch implements
@@ -40,8 +40,9 @@ public class NoneStreamEsDAO extends EsDAO implements INoneStreamDAO {
 
     @Override
     public void insert(Model model, NoneStream noneStream) throws IOException {
-        XContentBuilder builder = map2builder(
-            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(noneStream)));
+        Map<String, Object> builder =
+            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(
+                noneStream));
         String modelName = TimeSeriesUtils.writeIndexName(model, noneStream.getTimeBucket());
         String id = IndexController.INSTANCE.generateDocId(model, noneStream.id());
         getClient().forceInsert(modelName, id, builder);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/RecordEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/RecordEsDAO.java
index f23bc61..26f35c7 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/RecordEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/RecordEsDAO.java
@@ -19,13 +19,13 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
 import java.io.IOException;
+import java.util.Map;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageHashMapBuilder;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
-import org.elasticsearch.common.xcontent.XContentBuilder;
 
 public class RecordEsDAO extends EsDAO implements IRecordDAO {
     private final StorageHashMapBuilder<Record> storageBuilder;
@@ -38,8 +38,8 @@ public class RecordEsDAO extends EsDAO implements IRecordDAO {
 
     @Override
     public InsertRequest prepareBatchInsert(Model model, Record record) throws IOException {
-        XContentBuilder builder = map2builder(
-            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(record)));
+        Map<String, Object> builder =
+            IndexController.INSTANCE.appendMetricTableColumn(model, storageBuilder.entity2Storage(record));
         String modelName = TimeSeriesUtils.writeIndexName(model, record.getTimeBucket());
         String id = IndexController.INSTANCE.generateDocId(model, record.id());
         return getClient().prepareInsert(modelName, id, builder);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
index 442c075..1cc2de3 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
@@ -23,8 +23,12 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.library.elasticsearch.response.Index;
+import org.apache.skywalking.library.elasticsearch.response.IndexTemplate;
+import org.apache.skywalking.library.elasticsearch.response.Mappings;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
@@ -33,7 +37,6 @@ import org.apache.skywalking.oap.server.library.client.Client;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchConfig;
-import org.elasticsearch.common.unit.TimeValue;
 
 @Slf4j
 public class StorageEsInstaller extends ModelInstaller {
@@ -48,7 +51,7 @@ public class StorageEsInstaller extends ModelInstaller {
 
     public StorageEsInstaller(Client client,
                               ModuleManager moduleManager,
-                              StorageModuleElasticsearchConfig config) throws StorageException {
+                              StorageModuleElasticsearchConfig config) {
         super(client, moduleManager);
         this.columnTypeEsMapping = new ColumnTypeEsMapping();
         this.config = config;
@@ -70,9 +73,10 @@ public class StorageEsInstaller extends ModelInstaller {
             }
             boolean exist = esClient.isExistsTemplate(tableName)
                 && esClient.isExistsIndex(TimeSeriesUtils.latestWriteIndexName(model));
-            if (exist && IndexController.INSTANCE.isMetricModel(model)) {
+            final Optional<IndexTemplate> template = esClient.getTemplate(tableName);
+            if (exist && template.isPresent() && IndexController.INSTANCE.isMetricModel(model)) {
                 structures.putStructure(
-                    tableName, (Map<String, Object>) esClient.getTemplate(tableName).get("mappings")
+                    tableName, template.get().getMappings()
                 );
                 exist = structures.containsStructure(tableName, createMapping(model));
             }
@@ -111,7 +115,7 @@ public class StorageEsInstaller extends ModelInstaller {
         ElasticSearchClient esClient = (ElasticSearchClient) client;
         String tableName = IndexController.INSTANCE.getTableName(model);
         Map<String, Object> settings = createSetting(model);
-        Map<String, Object> mapping = createMapping(model);
+        Mappings mapping = createMapping(model);
         String indexName = TimeSeriesUtils.latestWriteIndexName(model);
         try {
             boolean shouldUpdateTemplate = !esClient.isExistsTemplate(tableName);
@@ -128,13 +132,14 @@ public class StorageEsInstaller extends ModelInstaller {
                 }
 
                 if (esClient.isExistsIndex(indexName)) {
-                    Map<String, Object> historyMapping = (Map<String, Object>) esClient.getIndex(indexName)
-                                                                                       .get("mappings");
-                    Map<String, Object> appendMapping = structures.diffStructure(tableName, historyMapping);
-                    if (!appendMapping.isEmpty()) {
+                    Mappings historyMapping = esClient.getIndex(indexName)
+                                                      .map(Index::getMappings)
+                                                      .orElseGet(Mappings::new);
+                    Mappings appendMapping = structures.diffStructure(tableName, historyMapping);
+                    if (appendMapping.getProperties() != null && !appendMapping.getProperties().isEmpty()) {
                         isAcknowledged = esClient.updateIndexMapping(indexName, appendMapping);
                         log.info("update {} index finished, isAcknowledged: {}, append mappings: {}", indexName,
-                                 isAcknowledged, appendMapping.toString()
+                                 isAcknowledged, appendMapping
                         );
                         if (!isAcknowledged) {
                             throw new StorageException("update " + indexName + " time series index failure");
@@ -174,11 +179,11 @@ public class StorageEsInstaller extends ModelInstaller {
             // even this value is set too small by end user manually.
             indexRefreshInterval = 5;
         }
-        setting.put("index.refresh_interval", TimeValue.timeValueSeconds(indexRefreshInterval).toString());
+        setting.put("index.refresh_interval", indexRefreshInterval + "s");
         setting.put("analysis", getAnalyzerSetting(model.getColumns()));
         if (!StringUtil.isEmpty(config.getAdvanced())) {
             Map<String, Object> advancedSettings = gson.fromJson(config.getAdvanced(), Map.class);
-            advancedSettings.forEach(setting::put);
+            setting.putAll(advancedSettings);
         }
         return setting;
     }
@@ -194,7 +199,7 @@ public class StorageEsInstaller extends ModelInstaller {
         return gson.fromJson(gson.toJson(analyzerSetting), Map.class);
     }
 
-    protected Map<String, Object> createMapping(Model model) {
+    protected Mappings createMapping(Model model) {
         Map<String, Object> properties = new HashMap<>();
         for (ModelColumn columnDefine : model.getColumns()) {
             if (columnDefine.isMatchQuery()) {
@@ -226,7 +231,10 @@ public class StorageEsInstaller extends ModelInstaller {
             column.put("type", "keyword");
             properties.put(IndexController.LogicIndicesRegister.METRIC_TABLE_NAME, column);
         }
-        Map<String, Object> mappings = this.structures.getWrapper().wrapper(properties);
+        Mappings mappings = Mappings.builder()
+                                    .type("type")
+                                    .properties(properties)
+                                    .build();
         log.debug("elasticsearch index template setting: {}", mappings.toString());
 
         return mappings;
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/cache/NetworkAddressAliasEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/cache/NetworkAddressAliasEsDAO.java
index 408839c..5f8d1da 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/cache/NetworkAddressAliasEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/cache/NetworkAddressAliasEsDAO.java
@@ -21,14 +21,14 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.cache;
 import java.util.ArrayList;
 import java.util.List;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.analysis.manual.networkalias.NetworkAddressAlias;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 
 @Slf4j
 public class NetworkAddressAliasEsDAO extends EsDAO implements INetworkAddressAliasDAO {
@@ -44,16 +44,19 @@ public class NetworkAddressAliasEsDAO extends EsDAO implements INetworkAddressAl
         List<NetworkAddressAlias> networkAddressAliases = new ArrayList<>();
 
         try {
-            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-            searchSourceBuilder.query(QueryBuilders.rangeQuery(NetworkAddressAlias.LAST_UPDATE_TIME_BUCKET)
-                                                   .gte(timeBucketInMinute));
-            searchSourceBuilder.size(resultWindowMaxSize);
+            final Search search =
+                Search.builder().query(
+                          Query.range(NetworkAddressAlias.LAST_UPDATE_TIME_BUCKET)
+                               .gte(timeBucketInMinute))
+                      .size(resultWindowMaxSize)
+                      .build();
 
-            SearchResponse response = getClient().search(NetworkAddressAlias.INDEX_NAME, searchSourceBuilder);
+            final SearchResponse results =
+                getClient().search(NetworkAddressAlias.INDEX_NAME, search);
 
             final NetworkAddressAlias.Builder builder = new NetworkAddressAlias.Builder();
-            for (SearchHit searchHit : response.getHits().getHits()) {
-                networkAddressAliases.add(builder.storage2Entity(searchHit.getSourceAsMap()));
+            for (SearchHit searchHit : results.getHits()) {
+                networkAddressAliases.add(builder.storage2Entity(searchHit.getSource()));
             }
         } catch (Throwable t) {
             log.error(t.getMessage(), t);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
index 65efcbd..a6779cb 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
@@ -21,6 +21,15 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.RangeQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.Aggregation;
+import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.BucketOrder;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
@@ -32,15 +41,6 @@ import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSear
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.index.query.RangeQueryBuilder;
-import org.elasticsearch.search.aggregations.AggregationBuilders;
-import org.elasticsearch.search.aggregations.BucketOrder;
-import org.elasticsearch.search.aggregations.bucket.terms.Terms;
-import org.elasticsearch.search.aggregations.metrics.avg.Avg;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 
 public class AggregationQueryEsDAO extends EsDAO implements IAggregationQueryDAO {
 
@@ -52,73 +52,78 @@ public class AggregationQueryEsDAO extends EsDAO implements IAggregationQueryDAO
     public List<SelectedRecord> sortMetrics(final TopNCondition condition,
                                             final String valueColumnName,
                                             final Duration duration,
-                                            final List<KeyValue> additionalConditions) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-        final RangeQueryBuilder queryBuilder = QueryBuilders.rangeQuery(Metrics.TIME_BUCKET)
-                                                            .lte(duration.getEndTimeBucket())
-                                                            .gte(duration.getStartTimeBucket());
+                                            final List<KeyValue> additionalConditions)
+        throws IOException {
+        final RangeQueryBuilder basicQuery = Query.range(Metrics.TIME_BUCKET)
+                                                  .lte(duration.getEndTimeBucket())
+                                                  .gte(duration.getStartTimeBucket());
+        final SearchBuilder search = Search.builder();
 
-        boolean asc = false;
-        if (condition.getOrder().equals(Order.ASC)) {
-            asc = true;
-        }
-        String tableName = IndexController.LogicIndicesRegister.getPhysicalTableName(condition.getName());
+        final boolean asc = condition.getOrder().equals(Order.ASC);
+        final String tableName =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(condition.getName());
 
         if (CollectionUtils.isEmpty(additionalConditions)
             && IndexController.LogicIndicesRegister.isMetricTable(condition.getName())) {
-            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
-            boolQuery.must()
-                     .add(QueryBuilders.termQuery(
+            final BoolQueryBuilder boolQuery =
+                Query.bool()
+                     .must(basicQuery)
+                     .must(Query.term(
                          IndexController.LogicIndicesRegister.METRIC_TABLE_NAME,
                          condition.getName()
                      ));
-            boolQuery.must().add(queryBuilder);
-            sourceBuilder.query(boolQuery);
+            search.query(boolQuery);
         } else if (CollectionUtils.isEmpty(additionalConditions)) {
-            sourceBuilder.query(queryBuilder);
+            search.query(basicQuery);
         } else if (CollectionUtils.isNotEmpty(additionalConditions)
             && IndexController.LogicIndicesRegister.isMetricTable(condition.getName())) {
-            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
-            boolQuery.must()
-                     .add(QueryBuilders.termQuery(
+            final BoolQueryBuilder boolQuery =
+                Query.bool()
+                     .must(Query.term(
                          IndexController.LogicIndicesRegister.METRIC_TABLE_NAME,
                          condition.getName()
                      ));
             additionalConditions.forEach(additionalCondition -> boolQuery
-                .must()
-                .add(QueryBuilders.termsQuery(additionalCondition.getKey(), additionalCondition.getValue())));
-            boolQuery.must().add(queryBuilder);
-            sourceBuilder.query(boolQuery);
+                .must(Query.term(
+                    additionalCondition.getKey(),
+                    additionalCondition.getValue()
+                )));
+            boolQuery.must(basicQuery);
+            search.query(boolQuery);
         } else {
-            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
+            final BoolQueryBuilder boolQuery = Query.bool();
             additionalConditions.forEach(additionalCondition -> boolQuery
-                .must()
-                .add(QueryBuilders.termsQuery(additionalCondition.getKey(), additionalCondition.getValue())));
-            boolQuery.must().add(queryBuilder);
-            sourceBuilder.query(boolQuery);
+                .must(Query.term(
+                    additionalCondition.getKey(),
+                    additionalCondition.getValue()
+                )));
+            boolQuery.must(basicQuery);
+            search.query(boolQuery);
         }
 
-        sourceBuilder.aggregation(
-            AggregationBuilders.terms(Metrics.ENTITY_ID)
-                               .field(Metrics.ENTITY_ID)
-                               .order(BucketOrder.aggregation(valueColumnName, asc))
-                               .size(condition.getTopN())
-                               .subAggregation(AggregationBuilders.avg(valueColumnName).field(valueColumnName))
-        );
+        search.aggregation(
+            Aggregation.terms(Metrics.ENTITY_ID)
+                       .field(Metrics.ENTITY_ID)
+                       .order(BucketOrder.aggregation(valueColumnName, asc))
+                       .size(condition.getTopN())
+                       .subAggregation(Aggregation.avg(valueColumnName).field(valueColumnName))
+                       .build());
 
-        SearchResponse response = getClient().search(tableName, sourceBuilder);
+        final SearchResponse response = getClient().search(tableName, search.build());
 
-        List<SelectedRecord> topNList = new ArrayList<>();
-        Terms idTerms = response.getAggregations().get(Metrics.ENTITY_ID);
-        for (Terms.Bucket termsBucket : idTerms.getBuckets()) {
+        final List<SelectedRecord> topNList = new ArrayList<>();
+        final Map<String, Object> idTerms =
+            (Map<String, Object>) response.getAggregations().get(Metrics.ENTITY_ID);
+        final List<Map<String, Object>> buckets =
+            (List<Map<String, Object>>) idTerms.get("buckets");
+        for (Map<String, Object> termsBucket : buckets) {
             SelectedRecord record = new SelectedRecord();
-            record.setId(termsBucket.getKeyAsString());
-            Avg value = termsBucket.getAggregations().get(valueColumnName);
-            record.setValue(String.valueOf((long) value.getValue()));
+            record.setId((String) termsBucket.get("key"));
+            Map<String, Object> value = (Map<String, Object>) termsBucket.get(valueColumnName);
+            record.setValue(String.valueOf(value.get("value")));
             topNList.add(record);
         }
 
         return topNList;
     }
-
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AlarmQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AlarmQueryEsDAO.java
index d1a0cf4..6748834 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AlarmQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AlarmQueryEsDAO.java
@@ -19,11 +19,16 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
 import com.google.common.base.Strings;
-
 import java.io.IOException;
 import java.util.List;
 import java.util.Objects;
-
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Sort;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.alarm.AlarmRecord;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
 import org.apache.skywalking.oap.server.core.query.enumeration.Scope;
@@ -35,13 +40,6 @@ import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
-import org.elasticsearch.search.sort.SortOrder;
 
 public class AlarmQueryEsDAO extends EsDAO implements IAlarmQueryDAO {
 
@@ -50,43 +48,44 @@ public class AlarmQueryEsDAO extends EsDAO implements IAlarmQueryDAO {
     }
 
     @Override
-    public Alarms getAlarm(final Integer scopeId, final String keyword, final int limit, final int from,
-                           final long startTB, final long endTB, final List<Tag> tags) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        List<QueryBuilder> mustQueryList = boolQueryBuilder.must();
+    public Alarms getAlarm(final Integer scopeId, final String keyword, final int limit,
+                           final int from,
+                           final long startTB, final long endTB, final List<Tag> tags)
+        throws IOException {
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(AlarmRecord.INDEX_NAME);
+        final BoolQueryBuilder query = Query.bool();
 
         if (startTB != 0 && endTB != 0) {
-            mustQueryList.add(QueryBuilders.rangeQuery(AlarmRecord.TIME_BUCKET).gte(startTB).lte(endTB));
+            query.must(Query.range(AlarmRecord.TIME_BUCKET).gte(startTB).lte(endTB));
         }
 
         if (Objects.nonNull(scopeId)) {
-            mustQueryList.add(QueryBuilders.termQuery(AlarmRecord.SCOPE, scopeId.intValue()));
+            query.must(Query.term(AlarmRecord.SCOPE, scopeId));
         }
 
         if (!Strings.isNullOrEmpty(keyword)) {
             String matchCName = MatchCNameBuilder.INSTANCE.build(AlarmRecord.ALARM_MESSAGE);
-            mustQueryList.add(QueryBuilders.matchPhraseQuery(matchCName, keyword));
+            query.must(Query.matchPhrase(matchCName, keyword));
         }
 
         if (CollectionUtils.isNotEmpty(tags)) {
-            tags.forEach(tag -> mustQueryList.add(QueryBuilders.termQuery(AlarmRecord.TAGS, tag.toString())));
+            tags.forEach(tag -> query.must(Query.term(AlarmRecord.TAGS, tag.toString())));
         }
 
-        sourceBuilder.query(boolQueryBuilder).sort(AlarmRecord.START_TIME, SortOrder.DESC);
-        sourceBuilder.size(limit);
-        sourceBuilder.from(from);
+        final SearchBuilder search =
+            Search.builder().query(query)
+                  .size(limit).from(from)
+                  .sort(AlarmRecord.START_TIME, Sort.Order.DESC);
 
-        SearchResponse response = getClient()
-                .search(IndexController.LogicIndicesRegister.getPhysicalTableName(AlarmRecord.INDEX_NAME), sourceBuilder);
+        SearchResponse response = getClient().search(index, search.build());
 
         Alarms alarms = new Alarms();
-        alarms.setTotal((int) response.getHits().totalHits);
+        alarms.setTotal(response.getHits().getTotal());
 
         for (SearchHit searchHit : response.getHits().getHits()) {
             AlarmRecord.Builder builder = new AlarmRecord.Builder();
-            AlarmRecord alarmRecord = builder.storage2Entity(searchHit.getSourceAsMap());
+            AlarmRecord alarmRecord = builder.storage2Entity(searchHit.getSource());
 
             AlarmMessage message = new AlarmMessage();
             message.setId(String.valueOf(alarmRecord.getId0()));
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java
index 8751c8d..8b8ad63 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java
@@ -19,6 +19,13 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
 import java.io.IOException;
 import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Sort;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
 import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
 import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
@@ -27,12 +34,6 @@ import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
-import org.elasticsearch.search.sort.SortOrder;
 
 import static java.util.Objects.nonNull;
 
@@ -50,43 +51,47 @@ public class BrowserLogQueryEsDAO extends EsDAO implements IBrowserLogQueryDAO {
                                                   final long endSecondTB,
                                                   final int limit,
                                                   final int from) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        sourceBuilder.query(boolQueryBuilder);
+        final BoolQueryBuilder boolQueryBuilder = Query.bool();
 
         if (startSecondTB != 0 && endSecondTB != 0) {
-            boolQueryBuilder.must().add(
-                QueryBuilders.rangeQuery(BrowserErrorLogRecord.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
+            boolQueryBuilder.must(
+                Query.range(BrowserErrorLogRecord.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
         }
         if (StringUtil.isNotEmpty(serviceId)) {
-            boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_ID, serviceId));
+            boolQueryBuilder.must(
+                Query.term(BrowserErrorLogRecord.SERVICE_ID, serviceId));
         }
         if (StringUtil.isNotEmpty(serviceVersionId)) {
-            boolQueryBuilder.must()
-                            .add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_VERSION_ID, serviceVersionId));
+            boolQueryBuilder.must(
+                Query.term(BrowserErrorLogRecord.SERVICE_VERSION_ID, serviceVersionId));
         }
         if (StringUtil.isNotEmpty(pagePathId)) {
-            boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.PAGE_PATH_ID, pagePathId));
+            boolQueryBuilder.must(
+                Query.term(BrowserErrorLogRecord.PAGE_PATH_ID, pagePathId));
         }
         if (nonNull(category)) {
-            boolQueryBuilder.must()
-                            .add(QueryBuilders.termQuery(BrowserErrorLogRecord.ERROR_CATEGORY, category.getValue()));
+            boolQueryBuilder.must(
+                Query.term(BrowserErrorLogRecord.ERROR_CATEGORY, category.getValue()));
         }
-        sourceBuilder.sort(BrowserErrorLogRecord.TIMESTAMP, SortOrder.DESC);
-        sourceBuilder.size(limit);
-        sourceBuilder.from(from);
-        SearchResponse response = getClient()
+
+        final SearchBuilder sourceBuilder =
+            Search.builder()
+                  .query(boolQueryBuilder)
+                  .sort(BrowserErrorLogRecord.TIMESTAMP, Sort.Order.DESC)
+                  .size(limit)
+                  .from(from);
+        final SearchResponse response = getClient()
             .search(
                 IndexController.LogicIndicesRegister.getPhysicalTableName(BrowserErrorLogRecord.INDEX_NAME),
-                sourceBuilder
+                sourceBuilder.build()
             );
 
         BrowserErrorLogs logs = new BrowserErrorLogs();
-        logs.setTotal((int) response.getHits().totalHits);
+        logs.setTotal(response.getHits().getTotal());
 
         for (SearchHit searchHit : response.getHits().getHits()) {
-            String dataBinaryBase64 = (String) searchHit.getSourceAsMap().get(BrowserErrorLogRecord.DATA_BINARY);
+            final String dataBinaryBase64 =
+                (String) searchHit.getSource().get(BrowserErrorLogRecord.DATA_BINARY);
             if (nonNull(dataBinaryBase64)) {
                 BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
                 logs.getLogs().add(log);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
index fb7c865..0701815 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
@@ -22,27 +22,26 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Sort;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.query.PaginationUtils;
-import org.apache.skywalking.oap.server.core.source.Event;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.type.event.EventQueryCondition;
 import org.apache.skywalking.oap.server.core.query.type.event.EventType;
 import org.apache.skywalking.oap.server.core.query.type.event.Events;
 import org.apache.skywalking.oap.server.core.query.type.event.Source;
+import org.apache.skywalking.oap.server.core.source.Event;
 import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
-import org.elasticsearch.search.sort.SortOrder;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static java.util.Objects.isNull;
@@ -54,124 +53,128 @@ public class ESEventQueryDAO extends EsDAO implements IEventQueryDAO {
 
     @Override
     public Events queryEvents(final EventQueryCondition condition) throws Exception {
-        final SearchSourceBuilder sourceBuilder = buildQuery(condition);
+        final SearchBuilder sourceBuilder = buildQuery(condition);
         return getEventsResultByCurrentBuilder(sourceBuilder);
     }
 
     @Override
     public Events queryEvents(List<EventQueryCondition> conditionList) throws Exception {
-        final SearchSourceBuilder sourceBuilder = buildQuery(conditionList);
+        final SearchBuilder sourceBuilder = buildQuery(conditionList);
         return getEventsResultByCurrentBuilder(sourceBuilder);
     }
 
-    private Events getEventsResultByCurrentBuilder(final SearchSourceBuilder sourceBuilder) throws IOException {
-        final SearchResponse response = getClient()
-                .search(IndexController.LogicIndicesRegister.getPhysicalTableName(Event.INDEX_NAME), sourceBuilder);
+    private Events getEventsResultByCurrentBuilder(final SearchBuilder searchBuilder)
+        throws IOException {
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(Event.INDEX_NAME);
+        final SearchResponse response = getClient().search(index, searchBuilder.build());
         final Events events = new Events();
-        events.setTotal((int) response.getHits().totalHits);
-        events.setEvents(Stream.of(response.getHits().getHits())
-                .map(this::parseSearchHit)
-                .collect(Collectors.toList()));
+        events.setTotal(response.getHits().getTotal());
+        events.setEvents(response.getHits().getHits().stream()
+                                 .map(this::parseSearchHit)
+                                 .collect(Collectors.toList()));
         return events;
     }
 
-    private void buildMustQueryListByCondition(final EventQueryCondition condition, final List<QueryBuilder> mustQueryList) {
+    private void buildMustQueryListByCondition(final EventQueryCondition condition,
+                                               final BoolQueryBuilder query) {
         if (!isNullOrEmpty(condition.getUuid())) {
-            mustQueryList.add(QueryBuilders.termQuery(Event.UUID, condition.getUuid()));
+            query.must(Query.term(Event.UUID, condition.getUuid()));
         }
 
         final Source source = condition.getSource();
         if (source != null) {
             if (!isNullOrEmpty(source.getService())) {
-                mustQueryList.add(QueryBuilders.termQuery(Event.SERVICE, source.getService()));
+                query.must(Query.term(Event.SERVICE, source.getService()));
             }
             if (!isNullOrEmpty(source.getServiceInstance())) {
-                mustQueryList.add(QueryBuilders.termQuery(Event.SERVICE_INSTANCE, source.getServiceInstance()));
+                query.must(Query.term(Event.SERVICE_INSTANCE, source.getServiceInstance()));
             }
             if (!isNullOrEmpty(source.getEndpoint())) {
-                mustQueryList.add(QueryBuilders.matchPhraseQuery(
-                        MatchCNameBuilder.INSTANCE.build(Event.ENDPOINT),
-                        source.getEndpoint()
+                query.must(Query.matchPhrase(
+                    MatchCNameBuilder.INSTANCE.build(Event.ENDPOINT),
+                    source.getEndpoint()
                 ));
             }
         }
 
         if (!isNullOrEmpty(condition.getName())) {
-            mustQueryList.add(QueryBuilders.termQuery(Event.NAME, condition.getName()));
+            query.must(Query.term(Event.NAME, condition.getName()));
         }
 
         if (condition.getType() != null) {
-            mustQueryList.add(QueryBuilders.termQuery(Event.TYPE, condition.getType().name()));
+            query.must(Query.term(Event.TYPE, condition.getType().name()));
         }
 
         final Duration startTime = condition.getTime();
         if (startTime != null) {
             if (startTime.getStartTimestamp() > 0) {
-                mustQueryList.add(QueryBuilders.rangeQuery(Event.START_TIME)
-                        .gt(startTime.getStartTimestamp()));
+                query.must(Query.range(Event.START_TIME).gt(startTime.getStartTimestamp()));
             }
             if (startTime.getEndTimestamp() > 0) {
-                mustQueryList.add(QueryBuilders.rangeQuery(Event.END_TIME)
-                        .lt(startTime.getEndTimestamp()));
+                query.must(Query.range(Event.END_TIME).lt(startTime.getEndTimestamp()));
             }
         }
     }
 
-    protected SearchSourceBuilder buildQuery(final List<EventQueryCondition> conditionList) {
-        final SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-        BoolQueryBuilder linkShouldBuilder = QueryBuilders.boolQuery();
-        sourceBuilder.query(linkShouldBuilder);
+    protected SearchBuilder buildQuery(final List<EventQueryCondition> conditionList) {
+        final BoolQueryBuilder query = Query.bool();
+
         conditionList.forEach(condition -> {
-            final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-            final List<QueryBuilder> mustQueryList = boolQueryBuilder.must();
-            linkShouldBuilder.should(boolQueryBuilder);
-            buildMustQueryListByCondition(condition, mustQueryList);
+            final BoolQueryBuilder bool = Query.bool();
+            query.should(bool);
+            buildMustQueryListByCondition(condition, bool);
         });
         EventQueryCondition condition = conditionList.get(0);
         final Order queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
-        sourceBuilder.sort(Event.START_TIME, Order.DES.equals(queryOrder) ? SortOrder.DESC : SortOrder.ASC);
-
         final PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
-        sourceBuilder.from(page.getFrom());
-        sourceBuilder.size(page.getLimit());
-        return sourceBuilder;
-    }
 
-    protected SearchSourceBuilder buildQuery(final EventQueryCondition condition) {
-        final SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-        final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        sourceBuilder.query(boolQueryBuilder);
+        return Search.builder().query(query)
+                     .sort(
+                         Event.START_TIME,
+                         Order.DES.equals(queryOrder) ? Sort.Order.DESC : Sort.Order.ASC
+                     )
+                     .from(page.getFrom())
+                     .size(page.getLimit());
+    }
 
-        final List<QueryBuilder> mustQueryList = boolQueryBuilder.must();
+    protected SearchBuilder buildQuery(final EventQueryCondition condition) {
+        final BoolQueryBuilder query = Query.bool();
 
-        buildMustQueryListByCondition(condition, mustQueryList);
+        buildMustQueryListByCondition(condition, query);
 
         final Order queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
-        sourceBuilder.sort(Event.START_TIME, Order.DES.equals(queryOrder) ? SortOrder.DESC : SortOrder.ASC);
-
         final PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
-        sourceBuilder.from(page.getFrom());
-        sourceBuilder.size(page.getLimit());
 
-        return sourceBuilder;
+        return Search.builder()
+                     .query(query)
+                     .sort(
+                         Event.START_TIME,
+                         Order.DES.equals(queryOrder) ? Sort.Order.DESC : Sort.Order.ASC
+                     )
+                     .from(page.getFrom())
+                     .size(page.getLimit());
     }
 
-    protected org.apache.skywalking.oap.server.core.query.type.event.Event parseSearchHit(final SearchHit searchHit) {
-        final org.apache.skywalking.oap.server.core.query.type.event.Event event = new org.apache.skywalking.oap.server.core.query.type.event.Event();
+    protected org.apache.skywalking.oap.server.core.query.type.event.Event parseSearchHit(
+        final SearchHit searchHit) {
+        final org.apache.skywalking.oap.server.core.query.type.event.Event event =
+            new org.apache.skywalking.oap.server.core.query.type.event.Event();
 
-        event.setUuid((String) searchHit.getSourceAsMap().get(Event.UUID));
+        event.setUuid((String) searchHit.getSource().get(Event.UUID));
 
-        String service = searchHit.getSourceAsMap().getOrDefault(Event.SERVICE, "").toString();
-        String serviceInstance = searchHit.getSourceAsMap().getOrDefault(Event.SERVICE_INSTANCE, "").toString();
-        String endpoint = searchHit.getSourceAsMap().getOrDefault(Event.ENDPOINT, "").toString();
+        String service = searchHit.getSource().getOrDefault(Event.SERVICE, "").toString();
+        String serviceInstance =
+            searchHit.getSource().getOrDefault(Event.SERVICE_INSTANCE, "").toString();
+        String endpoint = searchHit.getSource().getOrDefault(Event.ENDPOINT, "").toString();
         event.setSource(new Source(service, serviceInstance, endpoint));
 
-        event.setName((String) searchHit.getSourceAsMap().get(Event.NAME));
-        event.setType(EventType.parse(searchHit.getSourceAsMap().get(Event.TYPE).toString()));
-        event.setMessage((String) searchHit.getSourceAsMap().get(Event.MESSAGE));
-        event.setParameters((String) searchHit.getSourceAsMap().get(Event.PARAMETERS));
-        event.setStartTime(Long.parseLong(searchHit.getSourceAsMap().get(Event.START_TIME).toString()));
-        String endTimeStr = searchHit.getSourceAsMap().getOrDefault(Event.END_TIME, "0").toString();
+        event.setName((String) searchHit.getSource().get(Event.NAME));
+        event.setType(EventType.parse(searchHit.getSource().get(Event.TYPE).toString()));
+        event.setMessage((String) searchHit.getSource().get(Event.MESSAGE));
+        event.setParameters((String) searchHit.getSource().get(Event.PARAMETERS));
+        event.setStartTime(Long.parseLong(searchHit.getSource().get(Event.START_TIME).toString()));
+        String endTimeStr = searchHit.getSource().getOrDefault(Event.END_TIME, "0").toString();
         if (!endTimeStr.isEmpty() && !Objects.equals(endTimeStr, "0")) {
             event.setEndTime(Long.parseLong(endTimeStr));
         }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/LogQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/LogQueryEsDAO.java
index a60b6f4..eb0ca05 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/LogQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/LogQueryEsDAO.java
@@ -18,8 +18,16 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
+import com.google.common.base.Strings;
 import java.io.IOException;
 import java.util.List;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Sort;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord;
 import org.apache.skywalking.oap.server.core.analysis.manual.log.LogRecord;
@@ -36,14 +44,6 @@ import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
-import org.elasticsearch.search.sort.SortOrder;
 
 import static java.util.Objects.nonNull;
 import static org.apache.skywalking.apm.util.StringUtil.isNotEmpty;
@@ -71,46 +71,44 @@ public class LogQueryEsDAO extends EsDAO implements ILogQueryDAO {
                           final List<Tag> tags,
                           final List<String> keywordsOfContent,
                           final List<String> excludingKeywordsOfContent) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        sourceBuilder.query(boolQueryBuilder);
-        List<QueryBuilder> mustQueryList = boolQueryBuilder.must();
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(LogRecord.INDEX_NAME);
 
+        final BoolQueryBuilder query = Query.bool();
         if (startSecondTB != 0 && endSecondTB != 0) {
-            mustQueryList.add(QueryBuilders.rangeQuery(Record.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
+            query.must(Query.range(Record.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
         }
         if (isNotEmpty(serviceId)) {
-            mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.SERVICE_ID, serviceId));
+            query.must(Query.term(AbstractLogRecord.SERVICE_ID, serviceId));
         }
         if (isNotEmpty(serviceInstanceId)) {
-            mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.SERVICE_INSTANCE_ID, serviceInstanceId));
+            query.must(Query.term(AbstractLogRecord.SERVICE_INSTANCE_ID, serviceInstanceId));
         }
         if (isNotEmpty(endpointId)) {
-            mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.ENDPOINT_ID, endpointId));
+            query.must(Query.term(AbstractLogRecord.ENDPOINT_ID, endpointId));
         }
         if (nonNull(relatedTrace)) {
             if (isNotEmpty(relatedTrace.getTraceId())) {
-                mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.TRACE_ID, relatedTrace.getTraceId()));
+                query.must(Query.term(AbstractLogRecord.TRACE_ID, relatedTrace.getTraceId()));
             }
             if (isNotEmpty(relatedTrace.getSegmentId())) {
-                mustQueryList.add(
-                    QueryBuilders.termQuery(AbstractLogRecord.TRACE_SEGMENT_ID, relatedTrace.getSegmentId()));
+                query.must(
+                    Query.term(AbstractLogRecord.TRACE_SEGMENT_ID, relatedTrace.getSegmentId()));
             }
             if (nonNull(relatedTrace.getSpanId())) {
-                mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.SPAN_ID, relatedTrace.getSpanId()));
+                query.must(Query.term(AbstractLogRecord.SPAN_ID, relatedTrace.getSpanId()));
             }
         }
 
         if (CollectionUtils.isNotEmpty(tags)) {
-            tags.forEach(tag -> mustQueryList.add(QueryBuilders.termQuery(AbstractLogRecord.TAGS, tag.toString())));
+            tags.forEach(tag -> query.must(Query.term(AbstractLogRecord.TAGS, tag.toString())));
         }
 
         if (CollectionUtils.isNotEmpty(keywordsOfContent)) {
             keywordsOfContent.forEach(
                 content ->
-                    mustQueryList.add(
-                        QueryBuilders.matchPhraseQuery(
+                    query.must(
+                        Query.matchPhrase(
                             MatchCNameBuilder.INSTANCE.build(AbstractLogRecord.CONTENT),
                             content
                         )
@@ -121,8 +119,8 @@ public class LogQueryEsDAO extends EsDAO implements ILogQueryDAO {
         if (CollectionUtils.isNotEmpty(excludingKeywordsOfContent)) {
             excludingKeywordsOfContent.forEach(
                 content ->
-                    boolQueryBuilder.mustNot(
-                        QueryBuilders.matchPhraseQuery(
+                    query.mustNot(
+                        Query.matchPhrase(
                             MatchCNameBuilder.INSTANCE.build(AbstractLogRecord.CONTENT),
                             content
                         )
@@ -130,31 +128,41 @@ public class LogQueryEsDAO extends EsDAO implements ILogQueryDAO {
             );
         }
 
-        sourceBuilder.sort(LogRecord.TIMESTAMP, Order.DES.equals(queryOrder) ? SortOrder.DESC : SortOrder.ASC);
-        sourceBuilder.size(limit);
-        sourceBuilder.from(from);
+        final SearchBuilder search =
+            Search.builder().query(query)
+                  .sort(
+                      LogRecord.TIMESTAMP,
+                      Order.DES.equals(queryOrder) ?
+                          Sort.Order.DESC : Sort.Order.ASC
+                  )
+                  .size(limit)
+                  .from(from);
 
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(LogRecord.INDEX_NAME), sourceBuilder);
+        SearchResponse response = getClient().search(index, search.build());
 
         Logs logs = new Logs();
-        logs.setTotal((int) response.getHits().totalHits);
+        logs.setTotal(response.getHits().getTotal());
 
         for (SearchHit searchHit : response.getHits().getHits()) {
             Log log = new Log();
-            log.setServiceId((String) searchHit.getSourceAsMap().get(AbstractLogRecord.SERVICE_ID));
-            log.setServiceInstanceId((String) searchHit.getSourceAsMap()
+            log.setServiceId((String) searchHit.getSource().get(AbstractLogRecord.SERVICE_ID));
+            log.setServiceInstanceId((String) searchHit.getSource()
                                                        .get(AbstractLogRecord.SERVICE_INSTANCE_ID));
-            log.setEndpointId((String) searchHit.getSourceAsMap().get(AbstractLogRecord.ENDPOINT_ID));
+            log.setEndpointId(
+                (String) searchHit.getSource().get(AbstractLogRecord.ENDPOINT_ID));
             if (log.getEndpointId() != null) {
-                log.setEndpointName(IDManager.EndpointID.analysisId(log.getEndpointId()).getEndpointName());
+                log.setEndpointName(
+                    IDManager.EndpointID.analysisId(log.getEndpointId()).getEndpointName());
             }
-            log.setTraceId((String) searchHit.getSourceAsMap().get(AbstractLogRecord.TRACE_ID));
-            log.setTimestamp(((Number) searchHit.getSourceAsMap().get(AbstractLogRecord.TIMESTAMP)).longValue());
+            log.setTraceId((String) searchHit.getSource().get(AbstractLogRecord.TRACE_ID));
+            log.setTimestamp(
+                ((Number) searchHit.getSource().get(AbstractLogRecord.TIMESTAMP)).longValue());
             log.setContentType(ContentType.instanceOf(
-                ((Number) searchHit.getSourceAsMap().get(AbstractLogRecord.CONTENT_TYPE)).intValue()));
-            log.setContent((String) searchHit.getSourceAsMap().get(AbstractLogRecord.CONTENT));
-            String dataBinaryBase64 = (String) searchHit.getSourceAsMap().get(AbstractLogRecord.TAGS_RAW_DATA);
+                ((Number) searchHit.getSource()
+                                   .get(AbstractLogRecord.CONTENT_TYPE)).intValue()));
+            log.setContent((String) searchHit.getSource().get(AbstractLogRecord.CONTENT));
+            String dataBinaryBase64 =
+                (String) searchHit.getSource().get(AbstractLogRecord.TAGS_RAW_DATA);
             if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
                 parserDataBinary(dataBinaryBase64, log.getTags());
             }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetadataQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetadataQueryEsDAO.java
index 8464d3b..b34e971 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetadataQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetadataQueryEsDAO.java
@@ -25,7 +25,14 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
+import org.apache.skywalking.library.elasticsearch.requests.search.Query;
+import org.apache.skywalking.library.elasticsearch.requests.search.Search;
+import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.analysis.NodeType;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.analysis.manual.endpoint.EndpointTraffic;
@@ -42,11 +49,6 @@ import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSear
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.builder.SearchSourceBuilder;
 
 import static org.apache.skywalking.oap.server.core.analysis.manual.instance.InstanceTraffic.PropertyUtil.LANGUAGE;
 
@@ -60,120 +62,111 @@ public class MetadataQueryEsDAO extends EsDAO implements IMetadataQueryDAO {
 
     @Override
     public List<Service> getAllServices(final String group) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME);
 
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()));
+        final BoolQueryBuilder query =
+            Query.bool()
+                 .must(Query.term(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()));
+        final SearchBuilder search = Search.builder().query(query).size(queryMaxSize);
         if (StringUtil.isNotEmpty(group)) {
-            boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.GROUP, group));
+            query.must(Query.term(ServiceTraffic.GROUP, group));
         }
+        final SearchResponse results = getClient().search(index, search.build());
 
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(queryMaxSize);
-
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME), sourceBuilder);
-
-        return buildServices(response);
+        return buildServices(results);
     }
 
     @Override
     public List<Service> getAllBrowserServices() throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NODE_TYPE, NodeType.Browser.value()));
-
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(queryMaxSize);
-
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME), sourceBuilder);
-
-        return buildServices(response);
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME);
+        final BoolQueryBuilder query = Query.bool().must(
+            Query.term(ServiceTraffic.NODE_TYPE, NodeType.Browser.value()));
+        final SearchBuilder search = Search.builder().query(query).size(queryMaxSize);
+        final SearchResponse result = getClient().search(index, search.build());
+
+        return buildServices(result);
     }
 
     @Override
     public List<Database> getAllDatabases() throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NODE_TYPE, NodeType.Database.value()));
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME);
 
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(queryMaxSize);
+        final BoolQueryBuilder query = Query.bool().must(
+            Query.term(ServiceTraffic.NODE_TYPE, NodeType.Database.value()));
+        final SearchBuilder search = Search.builder().query(query).size(queryMaxSize);
+        final SearchResponse results = getClient().search(index, search.build());
 
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME), sourceBuilder);
-
-        final List<Service> serviceList = buildServices(response);
-        List<Database> databases = new ArrayList<>();
-        for (Service service : serviceList) {
+        final List<Service> serviceList = buildServices(results);
+        return serviceList.stream().map(service -> {
             Database database = new Database();
             database.setId(service.getId());
             database.setName(service.getName());
-            databases.add(database);
-        }
-        return databases;
+            return database;
+        }).collect(Collectors.toList());
     }
 
     @Override
     public List<Service> searchServices(String keyword) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME);
 
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+        final BoolQueryBuilder query =
+            Query.bool()
+                 .must(Query.term(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()));
+        final SearchBuilder search = Search.builder().query(query).size(queryMaxSize);
 
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()));
         if (!Strings.isNullOrEmpty(keyword)) {
             String matchCName = MatchCNameBuilder.INSTANCE.build(ServiceTraffic.NAME);
-            boolQueryBuilder.must().add(QueryBuilders.matchQuery(matchCName, keyword));
+            query.must(Query.match(matchCName, keyword));
         }
 
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(queryMaxSize);
-
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME), sourceBuilder);
+        SearchResponse response = getClient().search(index, search.build());
         return buildServices(response);
     }
 
     @Override
     public Service searchService(String serviceCode) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()));
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(ServiceTraffic.NAME, serviceCode));
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(1);
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME), sourceBuilder);
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(ServiceTraffic.INDEX_NAME);
+        final BoolQueryBuilder query =
+            Query.bool()
+                 .must(Query.term(ServiceTraffic.NODE_TYPE, NodeType.Normal.value()))
+                 .must(Query.term(ServiceTraffic.NAME, serviceCode));
+        final SearchBuilder search = Search.builder().query(query).size(1);
+
+        final SearchResponse response = getClient().search(index, search.build());
         final List<Service> services = buildServices(response);
         return services.size() > 0 ? services.get(0) : null;
     }
 
     @Override
-    public List<Endpoint> searchEndpoint(String keyword, String serviceId, int limit) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+    public List<Endpoint> searchEndpoint(String keyword, String serviceId, int limit)
+        throws IOException {
+        final String index = IndexController.LogicIndicesRegister.getPhysicalTableName(
+            EndpointTraffic.INDEX_NAME);
 
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(EndpointTraffic.SERVICE_ID, serviceId));
+        final BoolQueryBuilder query =
+            Query.bool()
+                 .must(Query.term(EndpointTraffic.SERVICE_ID, serviceId));
 
         if (!Strings.isNullOrEmpty(keyword)) {
             String matchCName = MatchCNameBuilder.INSTANCE.build(EndpointTraffic.NAME);
-            boolQueryBuilder.must().add(QueryBuilders.matchQuery(matchCName, keyword));
+            query.must(Query.match(matchCName, keyword));
         }
 
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(limit);
+        final SearchBuilder search = Search.builder().query(query).size(limit);
 
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(EndpointTraffic.INDEX_NAME), sourceBuilder);
+        final SearchResponse response = getClient().search(index, search.build());
 
         List<Endpoint> endpoints = new ArrayList<>();
         for (SearchHit searchHit : response.getHits()) {
-            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
+            Map<String, Object> sourceAsMap = searchHit.getSource();
 
-            final EndpointTraffic endpointTraffic = new EndpointTraffic.Builder().storage2Entity(sourceAsMap);
+            final EndpointTraffic endpointTraffic =
+                new EndpointTraffic.Builder().storage2Entity(sourceAsMap);
 
             Endpoint endpoint = new Endpoint();
             endpoint.setId(endpointTraffic.id());
@@ -187,27 +180,24 @@ public class MetadataQueryEsDAO extends EsDAO implements IMetadataQueryDAO {
     @Override
     public List<ServiceInstance> getServiceInstances(long startTimestamp, long endTimestamp,
                                                      String serviceId) throws IOException {
-        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
-
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(InstanceTraffic.INDEX_NAME);
 
         final long minuteTimeBucket = TimeBucket.getMinuteTimeBucket(startTimestamp);
+        final BoolQueryBuilder query =
+            Query.bool()
+                 .must(Query.range(InstanceTraffic.LAST_PING_TIME_BUCKET).gte(minuteTimeBucket))
+                 .must(Query.term(InstanceTraffic.SERVICE_ID, serviceId));
+        final SearchBuilder search = Search.builder().query(query).size(queryMaxSize);
 
-        boolQueryBuilder.must()
-                        .add(QueryBuilders.rangeQuery(InstanceTraffic.LAST_PING_TIME_BUCKET).gte(minuteTimeBucket));
-        boolQueryBuilder.must().add(QueryBuilders.termQuery(InstanceTraffic.SERVICE_ID, serviceId));
-
-        sourceBuilder.query(boolQueryBuilder);
-        sourceBuilder.size(queryMaxSize);
-
-        SearchResponse response = getClient()
-            .search(IndexController.LogicIndicesRegister.getPhysicalTableName(InstanceTraffic.INDEX_NAME), sourceBuilder);
+        final SearchResponse response = getClient().search(index, search.build());
 
         List<ServiceInstance> serviceInstances = new ArrayList<>();
         for (SearchHit searchHit : response.getHits()) {
-            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
+            Map<String, Object> sourceAsMap = searchHit.getSource();
 
-            final InstanceTraffic instanceTraffic = new InstanceTraffic.Builder().storage2Entity(sourceAsMap);
+            final InstanceTraffic instanceTraffic =
+                new InstanceTraffic.Builder().storage2Entity(sourceAsMap);
 
             ServiceInstance serviceInstance = new ServiceInstance();
             serviceInstance.setId(instanceTraffic.id());
@@ -235,9 +225,8 @@ public class MetadataQueryEsDAO extends EsDAO implements IMetadataQueryDAO {
 
     private List<Service> buildServices(SearchResponse response) {
         List<Service> services = new ArrayList<>();
-        for (SearchHit searchHit : response.getHits()) {
-            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
-
+        for (SearchHit hit : response.getHits()) {
+            final Map<String, Object> sourceAsMap = hit.getSource();
... 4637 lines suppressed ...