├── .gitignore
├── README.md
├── config
└── connect-elasticsearch-schema-sink.properties
├── pom.xml
└── src
└── main
└── java
└── org
└── apache
└── kafka
└── connect
└── elasticsearchschema
├── ElasticsearchSinkConnector.java
└── ElasticsearchSinkTask.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kafka Connect Elastic Search Connector
2 |
3 | kafka-connect-elastic-search-sink is a [Kafka Connector](http://kafka.apache.org/090/documentation.html#connect)
4 | for loading data to Elasticsearch from Kafka with Avro and schema registry integration.
5 |
6 |
7 | # Development
8 |
9 | To build a development version you'll need a recent version of Kafka. You can build
10 | kafka-connect-elastic-search with Maven using the standard lifecycle phases.
11 |
12 |
13 | # Testing
14 |
--------------------------------------------------------------------------------
/config/connect-elasticsearch-schema-sink.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one or more
2 | # contributor license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright ownership.
4 | # The ASF licenses this file to You under the Apache License, Version 2.0
5 | # (the "License"); you may not use this file except in compliance with
6 | # the License. You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | name=elasticsearch-schema-sink
17 | connector.class=org.apache.kafka.connect.elasticsearchschema.ElasticsearchSinkConnector
18 | tasks.max=1
19 | # topics from which consume messages
20 | topics=topic1,topic2,topic3
21 | # indexes on which write the messages
22 | elasticsearch.indexes=index_for_topic1,index_for_topic2,index_for_topic3
23 | elasticsearch.cluster.name=test-cluster
24 | elasticsearch.hosts=localhost:9300
25 | # name to use for documents, optional, default value: avro schema name
26 | elasticsearch.document.name=document
27 | elasticsearch.bulk.size=10
28 | # format to use for the date to append at the end of the index name, optional
29 | # if empty or null, no suffix will be used
30 | date.format=yyyy.MM.dd
31 | # separator to use for separate the index name and the date suffix, optional
32 | # default value: "-"
33 | suffix.separator=-
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.apache.kafka
8 | connect-elasticsearch-schema-sink
9 | 1.0
10 |
11 |
12 |
13 | confluent
14 | http://packages.confluent.io/maven/
15 |
16 |
17 |
18 |
19 |
20 |
21 | org.apache.maven.plugins
22 | maven-compiler-plugin
23 | 3.3
24 | true
25 |
26 | 1.8
27 | 1.8
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-assembly-plugin
33 | 2.6
34 |
35 |
36 | jar-with-dependencies
37 |
38 |
39 |
40 |
41 | make-assembly
42 | package
43 |
44 | single
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.apache.kafka
55 | connect-api
56 | 0.10.0.0
57 | compile
58 |
59 |
60 | org.slf4j
61 | slf4j-api
62 | 1.7.6
63 | compile
64 |
65 |
66 | org.apache.avro
67 | avro
68 | 1.7.7
69 |
70 |
71 | org.elasticsearch
72 | elasticsearch
73 | 2.3.4
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/kafka/connect/elasticsearchschema/ElasticsearchSinkConnector.java:
--------------------------------------------------------------------------------
1 | package org.apache.kafka.connect.elasticsearchschema;
2 |
3 | import org.apache.kafka.common.config.ConfigDef;
4 | import org.apache.kafka.common.utils.AppInfoParser;
5 | import org.apache.kafka.connect.connector.Task;
6 | import org.apache.kafka.connect.errors.ConnectException;
7 | import org.apache.kafka.connect.sink.SinkConnector;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | /**
15 | * ElasticsearchSinkConnector implement the Connector interface to send Kafka
16 | * data to Elasticsearch.
17 | *
18 | * @author Andrea Patelli
19 | */
20 | public class ElasticsearchSinkConnector extends SinkConnector {
21 | public static final String CLUSTER_NAME = "elasticsearch.cluster.name";
22 | public static final String HOSTS = "elasticsearch.hosts";
23 | public static final String BULK_SIZE = "elasticsearch.bulk.size";
24 | public static final String INDEXES = "elasticsearch.indexes";
25 | public static final String DOCUMENT_NAME = "elasticsearch.document.name";
26 | public static final String TOPICS = "topics";
27 | public static final String DATE_FORMAT = "date.format";
28 | public static final String SUFFIX_SEPARATOR = "suffix.separator";
29 |
30 | private String clusterName;
31 | private String hosts;
32 | private String bulkSize;
33 | private String documentName;
34 | private String topics;
35 | private String indexes;
36 | private String dateFormat;
37 | private String suffixSeparator;
38 |
39 |
40 | /**
41 | * Get the version of this connector.
42 | *
43 | * @return the version, formatted as a String
44 | */
45 | @Override
46 | public String version() {
47 | return AppInfoParser.getVersion();
48 | }
49 |
50 | /**
51 | * Start this Connector. This method will only be called on a clean Connector, i.e. it has
52 | * either just been instantiated and initialized or {@link #stop()} has been invoked.
53 | *
54 | * @param props configuration settings
55 | */
56 | @Override
57 | public void start(Map props) {
58 | clusterName = props.get(CLUSTER_NAME);
59 | hosts = props.get(HOSTS);
60 | bulkSize = props.get(BULK_SIZE);
61 | documentName = props.get(DOCUMENT_NAME);
62 | suffixSeparator = props.get(SUFFIX_SEPARATOR);
63 | if (clusterName == null || clusterName.isEmpty()) {
64 | throw new ConnectException("ElasticsearchSinkConnector configuration must include 'elasticsearch.cluster.name' setting");
65 | }
66 | if (hosts == null || hosts.isEmpty()) {
67 | throw new ConnectException("ElasticsearchSinkConnector configuration must include 'elasticserch.hosts' setting");
68 | }
69 | if (bulkSize == null || bulkSize.isEmpty()) {
70 | throw new ConnectException("ElasticsearchSinkConnector configuration must include 'elasticsearch.bulk.size' setting");
71 | }
72 | if (documentName == null) {
73 | documentName = "";
74 | }
75 |
76 | topics = props.get(TOPICS);
77 | indexes = props.get(INDEXES);
78 | if (topics == null || topics.isEmpty()) {
79 | throw new ConnectException("ElasticsearchSinkConnector configuration must include 'topics' setting");
80 | }
81 | if (indexes == null || indexes.isEmpty()) {
82 | throw new ConnectException("ElasticsearchSinkConnector configuration must include 'elasticsearch.indexes' setting");
83 | }
84 |
85 | if (suffixSeparator == null) {
86 | suffixSeparator = "-";
87 | }
88 | dateFormat = props.get(DATE_FORMAT);
89 | }
90 |
91 | /**
92 | * Returns the Task implementation for this Connector.
93 | */
94 | @Override
95 | public Class extends Task> taskClass() {
96 | return ElasticsearchSinkTask.class;
97 | }
98 |
99 | /**
100 | * Returns a set of configurations for Tasks based on the current configuration,
101 | * producing at most count configurations.
102 | *
103 | * @param maxTasks maximum number of configurations to generate
104 | * @return configurations for Tasks
105 | */
106 | @Override
107 | public List