diff --git a/client-adapter/es8x/pom.xml b/client-adapter/es8x/pom.xml
new file mode 100644
index 00000000..47d40c20
--- /dev/null
+++ b/client-adapter/es8x/pom.xml
@@ -0,0 +1,94 @@
+
+
+
+ canal.client-adapter
+ com.alibaba.otter
+ 1.1.7-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+ com.alibaba.otter
+ client-adapter.es8x
+ jar
+ canal client adapter es v8x module for otter ${project.version}
+
+
+
+ com.alibaba.otter
+ client-adapter.common
+ ${project.version}
+ provided
+
+
+ com.alibaba.otter
+ client-adapter.escore
+ ${project.version}
+
+
+ co.elastic.clients
+ elasticsearch-java
+ 8.6.2
+
+
+
+ org.elasticsearch.client
+ elasticsearch-rest-high-level-client
+ 7.17.9
+
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.4
+
+
+ jar-with-dependencies
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/ES8xAdapter.java b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/ES8xAdapter.java
new file mode 100644
index 00000000..a972fd99
--- /dev/null
+++ b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/ES8xAdapter.java
@@ -0,0 +1,117 @@
+package com.alibaba.otter.canal.client.adapter.es8x;
+
+import com.alibaba.otter.canal.client.adapter.es.core.ESAdapter;
+import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;
+import com.alibaba.otter.canal.client.adapter.es8x.etl.ESEtlService;
+import com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;
+import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;
+import com.alibaba.otter.canal.client.adapter.support.DatasourceConfig;
+import com.alibaba.otter.canal.client.adapter.support.EtlResult;
+import com.alibaba.otter.canal.client.adapter.support.OuterAdapterConfig;
+import com.alibaba.otter.canal.client.adapter.support.SPI;
+import org.elasticsearch.action.search.SearchResponse;
+
+import javax.sql.DataSource;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * ES 8.x 外部适配器
+ *
+ * @author ymz 2013-02-23
+ * @version 1.0.0
+ */
+@SPI("es8")
+public class ES8xAdapter extends ESAdapter {
+
+ private ESConnection esConnection;
+
+ public ESConnection getEsConnection() {
+ return esConnection;
+ }
+
+ @Override
+ public void init(OuterAdapterConfig configuration, Properties envProperties) {
+ try {
+ Map properties = configuration.getProperties();
+
+ String[] hostArray = configuration.getHosts().split(",");
+ esConnection = new ESConnection(hostArray, properties);
+
+ this.esTemplate = new ES8xTemplate(esConnection);
+
+ envProperties.put("es.version", "es8");
+ super.init(configuration, envProperties);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Map count(String task) {
+ ESSyncConfig config = esSyncConfig.get(task);
+ ESSyncConfig.ESMapping mapping = config.getEsMapping();
+ SearchResponse response = this.esConnection.new ESSearchRequest(mapping.get_index()).size(0).getResponse();
+
+ long rowCount = response.getHits().getTotalHits().value;
+ Map res = new LinkedHashMap<>();
+ res.put("esIndex", mapping.get_index());
+ res.put("count", rowCount);
+ return res;
+ }
+
+ @Override
+ public EtlResult etl(String task, List params) {
+ EtlResult etlResult = new EtlResult();
+ ESSyncConfig config = esSyncConfig.get(task);
+ if (config != null) {
+ DataSource dataSource = DatasourceConfig.DATA_SOURCES.get(config.getDataSourceKey());
+ ESEtlService esEtlService = new ESEtlService(esConnection, config);
+ if (dataSource != null) {
+ return esEtlService.importData(params);
+ } else {
+ etlResult.setSucceeded(false);
+ etlResult.setErrorMessage("DataSource not found");
+ return etlResult;
+ }
+ } else {
+ StringBuilder resultMsg = new StringBuilder();
+ boolean resSuccess = true;
+ for (ESSyncConfig configTmp : esSyncConfig.values()) {
+ // 取所有的destination为task的配置
+ if (configTmp.getDestination().equals(task)) {
+ ESEtlService esEtlService = new ESEtlService(esConnection, configTmp);
+ EtlResult etlRes = esEtlService.importData(params);
+ if (!etlRes.getSucceeded()) {
+ resSuccess = false;
+ resultMsg.append(etlRes.getErrorMessage()).append("\n");
+ } else {
+ resultMsg.append(etlRes.getResultMessage()).append("\n");
+ }
+ }
+ }
+ if (resultMsg.length() > 0) {
+ etlResult.setSucceeded(resSuccess);
+ if (resSuccess) {
+ etlResult.setResultMessage(resultMsg.toString());
+ } else {
+ etlResult.setErrorMessage(resultMsg.toString());
+ }
+ return etlResult;
+ }
+ }
+ etlResult.setSucceeded(false);
+ etlResult.setErrorMessage("Task not found");
+ return etlResult;
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ if (esConnection != null) {
+ esConnection.close();
+ }
+ }
+}
diff --git a/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/etl/ESEtlService.java b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/etl/ESEtlService.java
new file mode 100644
index 00000000..705d3be2
--- /dev/null
+++ b/client-adapter/es8x/src/main/java/com/alibaba/otter/canal/client/adapter/es8x/etl/ESEtlService.java
@@ -0,0 +1,200 @@
+package com.alibaba.otter.canal.client.adapter.es8x.etl;
+
+import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig;
+import com.alibaba.otter.canal.client.adapter.es.core.config.ESSyncConfig.ESMapping;
+import com.alibaba.otter.canal.client.adapter.es.core.config.SchemaItem.FieldItem;
+import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;
+import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESBulkResponse;
+import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESIndexRequest;
+import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest.ESUpdateRequest;
+import com.alibaba.otter.canal.client.adapter.es.core.support.ESTemplate;
+import com.alibaba.otter.canal.client.adapter.es8x.support.ES8xTemplate;
+import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection;
+import com.alibaba.otter.canal.client.adapter.es8x.support.ESConnection.ESSearchRequest;
+import com.alibaba.otter.canal.client.adapter.support.AbstractEtlService;
+import com.alibaba.otter.canal.client.adapter.support.AdapterConfig;
+import com.alibaba.otter.canal.client.adapter.support.EtlResult;
+import com.alibaba.otter.canal.client.adapter.support.Util;
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * ES ETL Service
+ *
+ * @author rewerma 2018-11-01
+ * @version 1.0.0
+ */
+public class ESEtlService extends AbstractEtlService {
+
+ private ESConnection esConnection;
+ private ESTemplate esTemplate;
+ private ESSyncConfig config;
+
+ public ESEtlService(ESConnection esConnection, ESSyncConfig config) {
+ super("ES", config);
+ this.esConnection = esConnection;
+ this.esTemplate = new ES8xTemplate(esConnection);
+ this.config = config;
+ }
+
+ public EtlResult importData(List params) {
+ ESMapping mapping = config.getEsMapping();
+ logger.info("start etl to import data to index: {}", mapping.get_index());
+ String sql = mapping.getSql();
+ return importData(sql, params);
+ }
+
+ protected boolean executeSqlImport(DataSource ds, String sql, List