embulk-output-elasticsearch 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c0c560040a57c47a8ebb93d8fe09ea9c27d0877
4
- data.tar.gz: bb7e6b43e092b88266468f254c66923a53abaf71
3
+ metadata.gz: 17a82e00d22fd47a3f0921903a8b2210c0ef938c
4
+ data.tar.gz: accef942b8a09e8700477fc74883693702eaae0e
5
5
  SHA512:
6
- metadata.gz: 3dc3769243508bea8270ea41f99d7efaa26222feec9f34878bd234fee9a671bc084c2f62f4aff519ab7f5b3183a30183d81279ec7fdcc91bf0e2900849c8c8f9
7
- data.tar.gz: 86eabe54f80a8801add35089f29c643c2b6821b7032c116a43768d13d75ed88c85a83e404436942715448d4eb43023f7eae8bee55580bd05fdb2f162e1f013fa
6
+ metadata.gz: 7cee36d9a5099ce50c92fdf760777e1a9e6cc960a9d543486d8aad10b0244a97e87e1396e8e653759f16a44ae77a5d9cb66b8be1682221d2b1337b900156c8c9
7
+ data.tar.gz: 75288939178b00e2d612f640c07fee9f0b86b21d1b5d17e4b15c93b2be97cb32e616a042302bf653d5aef09ce94ad790a481d6a952240d3d7700f5c10a29c1d2
data/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ ## 0.2.0 - 2016-01-26
2
+
3
+ * [new feature] Support Elasticsearch 2.x [#12](https://github.com/muga/embulk-output-elasticsearch/pull/12)
4
+ * [new feature] Added replace mode [#15](https://github.com/muga/embulk-output-elasticsearch/pull/15)
5
+ * [maintenance] Fix id param's behavior [#14](https://github.com/muga/embulk-output-elasticsearch/pull/14)
6
+ * [maintenance] Added unit tests [#17](https://github.com/muga/embulk-output-elasticsearch/pull/17)
7
+ * [maintenance] Upgraded Embulk to v0.7.7
8
+
9
+ ## 0.1.8 - 2015-08-19
10
+
11
+ * [maintenance] Upgraded Embulk to v0.7.0
12
+ * [maintenance] Upgraded Elasticsearch to v1.5.2
13
+
14
+ ## 0.1.7 - 2015-05-09
15
+
16
+ * [maintenance] Fixed handling null value [#10](https://github.com/muga/embulk-output-elasticsearch/pull/10)
17
+
18
+ ## 0.1.6 - 2015-04-14
19
+
20
+ * [new feature] Added bulk_size parameter [#8](https://github.com/muga/embulk-output-elasticsearch/pull/8)
21
+
22
+ ## 0.1.5 - 2015-03-26
23
+
24
+ * [new feature] Added cluster_name parameter [#7](https://github.com/muga/embulk-output-elasticsearch/pull/7)
25
+
26
+ ## 0.1.4 - 2015-03-19
27
+
28
+ * [maintenance] Fixed parameter names index_name to index, doc_id_column to id. [#5](https://github.com/muga/embulk-output-elasticsearch/pull/5)
29
+ * [maintenance] Fixed typo at parameter [#6](https://github.com/muga/embulk-output-elasticsearch/pull/6)
30
+
31
+ ## 0.1.3 - 2015-02-25
32
+
33
+ * [new feature] Supported timestamp column [#4](https://github.com/muga/embulk-output-elasticsearch/pull/4)
34
+
35
+ ## 0.1.2 - 2015-02-24
36
+
37
+ ## 0.1.1 - 2015-02-16
38
+
39
+ ## 0.1.0 - 2015-02-16
data/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
 
10
10
  ## Configuration
11
11
 
12
+ - **mode**: "insert" or "replace". See below(string, optional, default is insert)
12
13
  - **nodes**: list of nodes. nodes are pairs of host and port (list, required)
13
14
  - **cluster_name**: name of the cluster (string, default is "elasticsearch")
14
15
  - **index**: index name (string, required)
@@ -18,11 +19,38 @@
18
19
  - **bulk_size**: Sets when to flush a new bulk request based on the size of actions currently added. (long, default is 5242880)
19
20
  - **concurrent_requests**: concurrent_requests (int, default is 5)
20
21
 
22
+ ### Modes
23
+
24
+ #### insert:
25
+
26
+ default.
27
+ This mode writes data to existing index.
28
+
29
+ #### replace:
30
+
31
+ 1. Create new temporary index
32
+ 2. Insert data into the new index
33
+ 3. replace the alias with the new index. If alias doesn't exists, plugin will create new alias.
34
+ 4. Delete existing (old) index if exists
35
+
36
+ Index should not exists with the same name as the alias
37
+
38
+ ```yaml
39
+ out:
40
+ type: elasticsearch
41
+ mode: replace
42
+ nodes:
43
+ - {host: localhost, port: 9300}
44
+ index: <alias name> # plugin generates index name like <index>_%Y%m%d-%H%M%S
45
+ index_type: <index type>
46
+ ```
47
+
21
48
  ## Example
22
49
 
23
50
  ```yaml
24
51
  out:
25
52
  type: elasticsearch
53
+ mode: insert
26
54
  nodes:
27
55
  - {host: localhost, port: 9300}
28
56
  index: <index name>
@@ -32,5 +60,53 @@ out:
32
60
  ## Build
33
61
 
34
62
  ```
35
- $ ./gradlew gem
63
+ $ ./gradlew gem # -t to watch change of files and rebuild continuously
36
64
  ```
65
+
66
+ ## Test
67
+
68
+ ```
69
+ $ ./gradlew test # -t to watch change of files and rebuild continuously
70
+ ```
71
+
72
+ To run unit tests, we need to configure the following environment variables.
73
+
74
+ When environment variables are not set, skip almost test cases.
75
+
76
+ ```
77
+ ES_HOST
78
+ ES_PORT(optional, if needed, default: 9300)
79
+ ES_INDEX
80
+ ES_INDEX_TYPE
81
+ ```
82
+
83
+ If you're using Mac OS X El Capitan and GUI Applications(IDE), like as follows.
84
+ ```
85
+ $ vi ~/Library/LaunchAgents/environment.plist
86
+ <?xml version="1.0" encoding="UTF-8"?>
87
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
88
+ <plist version="1.0">
89
+ <dict>
90
+ <key>Label</key>
91
+ <string>my.startup</string>
92
+ <key>ProgramArguments</key>
93
+ <array>
94
+ <string>sh</string>
95
+ <string>-c</string>
96
+ <string>
97
+ launchctl setenv ES_HOST example.com
98
+ launchctl setenv ES_PORT 9300
99
+ launchctl setenv ES_INDEX embulk
100
+ launchctl setenv ES_INDEX_TYPE embulk
101
+ </string>
102
+ </array>
103
+ <key>RunAtLoad</key>
104
+ <true/>
105
+ </dict>
106
+ </plist>
107
+
108
+ $ launchctl load ~/Library/LaunchAgents/environment.plist
109
+ $ launchctl getenv ES_INDEX //try to get value.
110
+
111
+ Then start your applications.
112
+ ```
data/build.gradle CHANGED
@@ -2,6 +2,7 @@ plugins {
2
2
  id "com.jfrog.bintray" version "1.1"
3
3
  id "com.github.jruby-gradle.base" version "0.1.5"
4
4
  id "java"
5
+ id "jacoco"
5
6
  }
6
7
  import com.github.jrubygradle.JRubyExec
7
8
  repositories {
@@ -13,18 +14,20 @@ configurations {
13
14
  provided
14
15
  }
15
16
 
16
- version = "0.1.8"
17
+ version = "0.2.0"
17
18
 
18
19
  compileJava.options.encoding = 'UTF-8' // source encoding
19
20
  sourceCompatibility = 1.7
20
21
  targetCompatibility = 1.7
21
22
 
22
23
  dependencies {
23
- compile "org.embulk:embulk-core:0.7.0"
24
- provided "org.embulk:embulk-core:0.7.0"
25
- compile 'org.elasticsearch:elasticsearch:1.5.2'
24
+ compile "org.embulk:embulk-core:0.7.7"
25
+ provided "org.embulk:embulk-core:0.7.7"
26
+ compile 'org.elasticsearch:elasticsearch:2.0.0'
27
+
26
28
  testCompile "junit:junit:4.+"
27
- testCompile "org.mockito:mockito-core:1.+"
29
+ testCompile "org.embulk:embulk-core:0.7.7:tests"
30
+ testCompile "org.embulk:embulk-standards:0.7.7"
28
31
  }
29
32
 
30
33
  task classpath(type: Copy, dependsOn: ["jar"]) {
@@ -67,4 +70,12 @@ Gem::Specification.new do |spec|
67
70
  spec.add_development_dependency "test-unit", ["~> 3.0.2"]
68
71
  end
69
72
  /$)
70
- }
73
+ }
74
+
75
+ jacocoTestReport {
76
+ afterEvaluate {
77
+ classDirectories = files(classDirectories.files.collect {
78
+ fileTree(dir: it, exclude: 'org/embulk/output/elasticsearch/ElasticsearchOutputPlugin$1.class')
79
+ })
80
+ }
81
+ }
@@ -1,9 +1,18 @@
1
1
  package org.embulk.output.elasticsearch;
2
2
 
3
- import com.google.common.base.Optional;
4
- import com.google.common.base.Throwables;
5
- import com.google.common.collect.ImmutableList;
6
- import com.google.inject.Inject;
3
+ import java.io.IOException;
4
+ import java.text.SimpleDateFormat;
5
+ import java.util.ArrayList;
6
+ import java.util.Date;
7
+ import java.util.List;
8
+ import java.util.Locale;
9
+ import java.util.concurrent.TimeUnit;
10
+ import java.net.InetAddress;
11
+ import java.net.UnknownHostException;
12
+
13
+ import com.fasterxml.jackson.annotation.JsonCreator;
14
+ import com.fasterxml.jackson.annotation.JsonValue;
15
+
7
16
  import org.elasticsearch.action.bulk.BulkItemResponse;
8
17
  import org.elasticsearch.action.bulk.BulkProcessor;
9
18
  import org.elasticsearch.action.bulk.BulkRequest;
@@ -12,38 +21,44 @@ import org.elasticsearch.action.index.IndexRequest;
12
21
  import org.elasticsearch.client.Client;
13
22
  import org.elasticsearch.client.Requests;
14
23
  import org.elasticsearch.client.transport.TransportClient;
15
- import org.elasticsearch.common.unit.ByteSizeValue;
16
- import org.elasticsearch.common.unit.ByteSizeUnit;
17
- import org.elasticsearch.common.settings.ImmutableSettings;
24
+ import org.elasticsearch.cluster.metadata.AliasMetaData;
25
+ import org.elasticsearch.cluster.metadata.AliasOrIndex;
26
+ import org.elasticsearch.common.collect.ImmutableOpenMap;
18
27
  import org.elasticsearch.common.settings.Settings;
19
28
  import org.elasticsearch.common.transport.InetSocketTransportAddress;
29
+ import org.elasticsearch.common.unit.ByteSizeValue;
20
30
  import org.elasticsearch.common.xcontent.XContentBuilder;
21
31
  import org.elasticsearch.common.xcontent.XContentFactory;
22
- import org.elasticsearch.node.Node;
23
- import org.elasticsearch.node.NodeBuilder;
24
- import org.embulk.config.TaskReport;
32
+ import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
33
+ import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
34
+ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
35
+ import org.elasticsearch.index.IndexNotFoundException;
36
+ import org.elasticsearch.indices.InvalidAliasNameException;
37
+
25
38
  import org.embulk.config.Config;
26
39
  import org.embulk.config.ConfigDefault;
27
40
  import org.embulk.config.ConfigDiff;
41
+ import org.embulk.config.ConfigException;
28
42
  import org.embulk.config.ConfigSource;
29
43
  import org.embulk.config.Task;
44
+ import org.embulk.config.TaskReport;
30
45
  import org.embulk.config.TaskSource;
31
46
  import org.embulk.spi.Column;
47
+ import org.embulk.spi.ColumnVisitor;
32
48
  import org.embulk.spi.Exec;
33
49
  import org.embulk.spi.OutputPlugin;
34
50
  import org.embulk.spi.Page;
35
51
  import org.embulk.spi.PageReader;
36
52
  import org.embulk.spi.Schema;
37
- import org.embulk.spi.ColumnVisitor;
38
53
  import org.embulk.spi.TransactionalPageOutput;
54
+ import org.embulk.spi.time.Timestamp;
55
+ import org.embulk.spi.type.Types;
39
56
  import org.slf4j.Logger;
40
57
 
41
- import java.io.IOException;
42
- import java.util.Date;
43
- import java.util.List;
44
- import java.util.concurrent.TimeUnit;
45
-
46
- import static com.google.common.base.Preconditions.checkState;
58
+ import com.google.common.base.Optional;
59
+ import com.google.common.base.Throwables;
60
+ import com.google.inject.Inject;
61
+ import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
47
62
 
48
63
  public class ElasticsearchOutputPlugin
49
64
  implements OutputPlugin
@@ -62,6 +77,10 @@ public class ElasticsearchOutputPlugin
62
77
  public interface PluginTask
63
78
  extends Task
64
79
  {
80
+ @Config("mode")
81
+ @ConfigDefault("\"insert\"")
82
+ public Mode getMode();
83
+
65
84
  @Config("nodes")
66
85
  public List<NodeAddressTask> getNodes();
67
86
 
@@ -71,6 +90,12 @@ public class ElasticsearchOutputPlugin
71
90
 
72
91
  @Config("index")
73
92
  public String getIndex();
93
+ public void setIndex(String indexName);
94
+
95
+ @Config("alias")
96
+ @ConfigDefault("null")
97
+ public Optional<String> getAlias();
98
+ public void setAlias(Optional<String> aliasName);
74
99
 
75
100
  @Config("index_type")
76
101
  public String getType();
@@ -108,21 +133,15 @@ public class ElasticsearchOutputPlugin
108
133
 
109
134
  // confirm that a client can be initialized
110
135
  try (Client client = createClient(task)) {
111
- }
112
-
113
- // check that id is included in the schema or not if the id is not null.
114
- if (task.getId().isPresent()) {
115
- String id = task.getId().get();
116
- boolean found = false;
117
- for (Column column : schema.getColumns()) {
118
- if (column.equals(id)) {
119
- found = true;
136
+ log.info(String.format("Executing plugin with '%s' mode.", task.getMode()));
137
+ if (task.getMode().equals(Mode.REPLACE)) {
138
+ task.setAlias(Optional.of(task.getIndex()));
139
+ task.setIndex(generateNewIndexName(task.getIndex()));
140
+ if (isExistsIndex(task.getAlias().orNull(), client) && !isAlias(task.getAlias().orNull(), client)) {
141
+ throw new ConfigException(String.format("Invalid alias name [%s], an index exists with the same name as the alias", task.getAlias().orNull()));
120
142
  }
121
143
  }
122
- checkState(found, "id is not included in column names of the Schema.");
123
- }
124
-
125
- try {
144
+ log.info(String.format("Inserting data into index[%s]", task.getIndex()));
126
145
  control.run(task.dump());
127
146
  } catch (Exception e) {
128
147
  throw Throwables.propagate(e);
@@ -145,19 +164,31 @@ public class ElasticsearchOutputPlugin
145
164
  public void cleanup(TaskSource taskSource,
146
165
  Schema schema, int processorCount,
147
166
  List<TaskReport> successTaskReports)
148
- { }
167
+ {
168
+ final PluginTask task = taskSource.loadTask(PluginTask.class);
169
+ if (task.getMode().equals(Mode.REPLACE)) {
170
+ try (Client client = createClient(task)) {
171
+ reAssignAlias(task.getAlias().orNull(), task.getIndex(), client);
172
+ } catch (IndexNotFoundException | InvalidAliasNameException e) {
173
+ throw new ConfigException(e);
174
+ }
175
+ }
176
+ }
149
177
 
150
178
  private Client createClient(final PluginTask task)
151
179
  {
152
180
  // @see http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/client.html
153
- Settings settings = ImmutableSettings.settingsBuilder()
154
- .classLoader(Settings.class.getClassLoader())
181
+ Settings settings = Settings.settingsBuilder()
155
182
  .put("cluster.name", task.getClusterName())
156
183
  .build();
157
- TransportClient client = new TransportClient(settings);
184
+ TransportClient client = TransportClient.builder().settings(settings).build();
158
185
  List<NodeAddressTask> nodes = task.getNodes();
159
186
  for (NodeAddressTask node : nodes) {
160
- client.addTransportAddress(new InetSocketTransportAddress(node.getHost(), node.getPort()));
187
+ try {
188
+ client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(node.getHost()), node.getPort()));
189
+ } catch (UnknownHostException e) {
190
+ Throwables.propagate(e);
191
+ }
161
192
  }
162
193
  return client;
163
194
  }
@@ -208,7 +239,6 @@ public class ElasticsearchOutputPlugin
208
239
  int processorIndex)
209
240
  {
210
241
  final PluginTask task = taskSource.loadTask(PluginTask.class);
211
-
212
242
  Client client = createClient(task);
213
243
  BulkProcessor bulkProcessor = newBulkProcessor(task, client);
214
244
  ElasticsearchPageOutput pageOutput = new ElasticsearchPageOutput(task, client, bulkProcessor);
@@ -224,6 +254,7 @@ public class ElasticsearchOutputPlugin
224
254
  private BulkProcessor bulkProcessor;
225
255
 
226
256
  private PageReader pageReader;
257
+ private Column idColumn;
227
258
 
228
259
  private final String index;
229
260
  private final String type;
@@ -244,6 +275,7 @@ public class ElasticsearchOutputPlugin
244
275
  void open(final Schema schema)
245
276
  {
246
277
  pageReader = new PageReader(schema);
278
+ idColumn = (id == null) ? null : schema.lookupColumn(id);
247
279
  }
248
280
 
249
281
  @Override
@@ -342,7 +374,7 @@ public class ElasticsearchOutputPlugin
342
374
  });
343
375
 
344
376
  contextBuilder.endObject();
345
- bulkProcessor.add(newIndexRequest().source(contextBuilder));
377
+ bulkProcessor.add(newIndexRequest(getIdValue(idColumn)).source(contextBuilder));
346
378
 
347
379
  } catch (IOException e) {
348
380
  Throwables.propagate(e); // TODO error handling
@@ -350,9 +382,33 @@ public class ElasticsearchOutputPlugin
350
382
  }
351
383
  }
352
384
 
353
- private IndexRequest newIndexRequest()
385
+ /**
386
+ * @param inputColumn
387
+ * @return
388
+ */
389
+ private String getIdValue(Column inputColumn) {
390
+ if (inputColumn == null) return null;
391
+ if (pageReader.isNull(inputColumn)) return null;
392
+ String idValue = null;
393
+ if (Types.STRING.equals(inputColumn.getType())) {
394
+ idValue = pageReader.getString(inputColumn);
395
+ } else if (Types.BOOLEAN.equals(inputColumn.getType())) {
396
+ idValue = pageReader.getBoolean(inputColumn) + "";
397
+ } else if (Types.DOUBLE.equals(inputColumn.getType())) {
398
+ idValue = pageReader.getDouble(inputColumn) + "";
399
+ } else if (Types.LONG.equals(inputColumn.getType())) {
400
+ idValue = pageReader.getLong(inputColumn) + "";
401
+ } else if (Types.TIMESTAMP.equals(inputColumn.getType())) {
402
+ idValue = pageReader.getTimestamp(inputColumn).toString();
403
+ } else {
404
+ idValue = null;
405
+ }
406
+ return idValue;
407
+ }
408
+
409
+ private IndexRequest newIndexRequest(String idValue)
354
410
  {
355
- return Requests.indexRequest(index).type(type).id(id);
411
+ return Requests.indexRequest(index).type(type).id(idValue);
356
412
  }
357
413
 
358
414
  @Override
@@ -400,4 +456,91 @@ public class ElasticsearchOutputPlugin
400
456
  }
401
457
 
402
458
  }
459
+
460
+ public enum Mode
461
+ {
462
+ INSERT,
463
+ REPLACE;
464
+
465
+ @JsonValue
466
+ @Override
467
+ public String toString()
468
+ {
469
+ return name().toLowerCase(Locale.ENGLISH);
470
+ }
471
+
472
+ @JsonCreator
473
+ public static Mode fromString(String value)
474
+ {
475
+ switch (value) {
476
+ case "insert":
477
+ return INSERT;
478
+ case "replace":
479
+ return REPLACE;
480
+ default:
481
+ throw new ConfigException(String.format("Unknown mode '%s'. Supported modes are insert, truncate_insert, replace", value));
482
+ }
483
+ }
484
+ }
485
+
486
+ private void reAssignAlias(String aliasName, String newIndexName, Client client)
487
+ throws IndexNotFoundException, InvalidAliasNameException
488
+ {
489
+ if (!isExistsAlias(aliasName, client)) {
490
+ client.admin().indices().prepareAliases()
491
+ .addAlias(newIndexName, aliasName)
492
+ .execute().actionGet();
493
+ log.info(String.format("Assigned alias[%s] to index[%s]", aliasName, newIndexName));
494
+ } else {
495
+ List<String> oldIndices = getIndexByAlias(aliasName, client);
496
+ client.admin().indices().prepareAliases()
497
+ .removeAlias(oldIndices.toArray(new String[oldIndices.size()]), aliasName)
498
+ .addAlias(newIndexName, aliasName)
499
+ .execute().actionGet();
500
+ log.info(String.format("Reassigned alias[%s] from index%s to index[%s]", aliasName, oldIndices, newIndexName));
501
+ for (String index : oldIndices) {
502
+ deleteIndex(index, client);
503
+ }
504
+ }
505
+ }
506
+
507
+ private void deleteIndex(String indexName, Client client)
508
+ {
509
+ client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet();
510
+ log.info(String.format("Deleted Index [%s]", indexName));
511
+ }
512
+
513
+ private List<String> getIndexByAlias(String aliasName, Client client)
514
+ {
515
+ ImmutableOpenMap<String, List<AliasMetaData>> map = client.admin().indices().getAliases(new GetAliasesRequest(aliasName))
516
+ .actionGet().getAliases();
517
+ List<String> indices = new ArrayList<>();
518
+ for (ObjectObjectCursor<String, List<AliasMetaData>> c : map) {
519
+ indices.add(c.key);
520
+ }
521
+
522
+ return indices;
523
+ }
524
+
525
+ private boolean isExistsAlias(String aliasName, Client client)
526
+ {
527
+ return client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasAlias(aliasName);
528
+ }
529
+
530
+ private boolean isExistsIndex(String indexName, Client client)
531
+ {
532
+ return client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasIndex(indexName);
533
+ }
534
+
535
+ private boolean isAlias(String aliasName, Client client)
536
+ {
537
+ AliasOrIndex aliasOrIndex = client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().getAliasAndIndexLookup().get(aliasName);
538
+ return aliasOrIndex != null && aliasOrIndex.isAlias();
539
+ }
540
+
541
+ public String generateNewIndexName(String indexName)
542
+ {
543
+ Timestamp time = Exec.getTransactionTime();
544
+ return indexName + new SimpleDateFormat("_yyyyMMdd-HHmmss").format(time.toEpochMilli());
545
+ }
403
546
  }
@@ -1,5 +1,484 @@
1
1
  package org.embulk.output.elasticsearch;
2
2
 
3
+ import java.io.ByteArrayOutputStream;
4
+ import java.io.InputStream;
5
+ import java.io.IOException;
6
+ import java.lang.reflect.InvocationTargetException;
7
+ import java.lang.reflect.Method;
8
+ import java.net.UnknownHostException;
9
+ import java.text.ParseException;
10
+ import java.text.SimpleDateFormat;
11
+ import java.util.Arrays;
12
+ import java.util.List;
13
+ import java.util.Map;
14
+ import java.security.GeneralSecurityException;
15
+
16
+ import com.google.common.collect.Lists;
17
+ import com.google.common.collect.ImmutableList;
18
+ import com.google.common.collect.ImmutableMap;
19
+ import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
20
+ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
21
+ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
22
+ import org.elasticsearch.action.get.GetResponse;
23
+ import org.elasticsearch.client.Client;
24
+ import org.embulk.EmbulkTestRuntime;
25
+ import org.embulk.config.ConfigException;
26
+ import org.embulk.config.TaskReport;
27
+ import org.embulk.config.TaskSource;
28
+ import org.embulk.config.ConfigSource;
29
+ import org.embulk.spi.Exec;
30
+ import org.embulk.spi.OutputPlugin;
31
+ import org.embulk.spi.Page;
32
+ import org.embulk.spi.PageTestUtils;
33
+ import org.embulk.spi.Schema;
34
+ import org.embulk.spi.time.Timestamp;
35
+ import org.embulk.spi.TransactionalPageOutput;
36
+ import org.embulk.spi.TestPageBuilderReader.MockPageOutput;
37
+ import org.embulk.standards.CsvParserPlugin;
38
+ import org.embulk.output.elasticsearch.ElasticsearchOutputPlugin.PluginTask;
39
+ import org.junit.Before;
40
+ import org.junit.BeforeClass;
41
+ import org.junit.Rule;
42
+ import org.junit.Test;
43
+ import static org.junit.Assert.assertEquals;
44
+ import static org.junit.Assert.assertTrue;
45
+ import static org.junit.Assume.assumeNotNull;
46
+
3
47
  public class TestElasticsearchOutputPlugin
4
48
  {
49
+ private static String ES_HOST;
50
+ private static int ES_PORT;
51
+ private static List ES_NODES;
52
+ private static String ES_CLUSTER_NAME;
53
+ private static String ES_INDEX;
54
+ private static String ES_INDEX_TYPE;
55
+ private static String ES_ID;
56
+ private static int ES_BULK_ACTIONS;
57
+ private static int ES_BULK_SIZE;
58
+ private static int ES_CONCURRENT_REQUESTS;
59
+ private static String PATH_PREFIX;
60
+
61
+ private MockPageOutput pageOutput;
62
+
63
+ final String ES_TEST_INDEX = "index_for_unittest";
64
+ final String ES_TEST_INDEX2 = "index_for_unittest2";
65
+ final String ES_TEST_ALIAS = "alias_for_unittest";
66
+
67
+ /*
68
+ * This test case requires environment variables
69
+ * ES_HOST
70
+ * ES_INDEX
71
+ * ES_INDEX_TYPE
72
+ */
73
+ @BeforeClass
74
+ public static void initializeConstant()
75
+ {
76
+ ES_HOST = System.getenv("ES_HOST") != null ? System.getenv("ES_HOST") : "";
77
+ ES_PORT = System.getenv("ES_PORT") != null ? Integer.valueOf(System.getenv("ES_PORT")) : 9300;
78
+
79
+ ES_CLUSTER_NAME = System.getenv("ES_CLUSTER_NAME") != null ? System.getenv("ES_CLUSTER_NAME") : "";
80
+ ES_INDEX = System.getenv("ES_INDEX");
81
+ ES_INDEX_TYPE = System.getenv("ES_INDEX_TYPE");
82
+ ES_ID = "id";
83
+ ES_BULK_ACTIONS = System.getenv("ES_BULK_ACTIONS") != null ? Integer.valueOf(System.getenv("ES_BULK_ACTIONS")) : 1000;
84
+ ES_BULK_SIZE = System.getenv("ES_BULK_SIZE") != null ? Integer.valueOf(System.getenv("ES_BULK_SIZE")) : 5242880;
85
+ ES_CONCURRENT_REQUESTS = System.getenv("ES_CONCURRENT_REQUESTS") != null ? Integer.valueOf(System.getenv("ES_CONCURRENT_REQUESTS")) : 5;
86
+
87
+ assumeNotNull(ES_HOST, ES_INDEX, ES_INDEX_TYPE);
88
+
89
+ ES_NODES = Arrays.asList(ImmutableMap.of("host", ES_HOST, "port", ES_PORT));
90
+
91
+ PATH_PREFIX = ElasticsearchOutputPlugin.class.getClassLoader().getResource("sample_01.csv").getPath();
92
+ }
93
+
94
+
95
+ @Rule
96
+ public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
97
+ private ElasticsearchOutputPlugin plugin;
98
+
99
+ @Before
100
+ public void createResources()
101
+ throws GeneralSecurityException, NoSuchMethodException,
102
+ IllegalAccessException, InvocationTargetException
103
+ {
104
+ ConfigSource config = config();
105
+ plugin = new ElasticsearchOutputPlugin();
106
+ PluginTask task = config.loadConfig(PluginTask.class);
107
+ pageOutput = new MockPageOutput();
108
+
109
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
110
+ createClient.setAccessible(true);
111
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
112
+ // Delete alias
113
+ if (client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasAlias(ES_TEST_ALIAS)) {
114
+ client.admin().indices().delete(new DeleteIndexRequest(ES_TEST_ALIAS)).actionGet();
115
+ }
116
+
117
+ // Delete index
118
+ if (client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasIndex(ES_TEST_INDEX)) {
119
+ client.admin().indices().delete(new DeleteIndexRequest(ES_TEST_INDEX)).actionGet();
120
+ }
121
+
122
+ if (client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasIndex(ES_TEST_INDEX2)) {
123
+ client.admin().indices().delete(new DeleteIndexRequest(ES_TEST_INDEX2)).actionGet();
124
+ }
125
+ }
126
+ }
127
+
128
+ @Test
129
+ public void testDefaultValues()
130
+ {
131
+ ConfigSource config = config();
132
+ ElasticsearchOutputPlugin.PluginTask task = config.loadConfig(PluginTask.class);
133
+ assertEquals(ES_INDEX, task.getIndex());
134
+ }
135
+
136
+ @Test
137
+ public void testDefaultValuesNull()
138
+ {
139
+ ConfigSource config = Exec.newConfigSource()
140
+ .set("in", inputConfig())
141
+ .set("parser", parserConfig(schemaConfig()))
142
+ .set("type", "elasticsearch")
143
+ .set("mode", "") // NULL
144
+ .set("nodes", ES_NODES)
145
+ .set("cluster_name", ES_CLUSTER_NAME)
146
+ .set("index", ES_INDEX)
147
+ .set("index_type", ES_INDEX_TYPE)
148
+ .set("id", ES_ID)
149
+ .set("bulk_actions", ES_BULK_ACTIONS)
150
+ .set("bulk_size", ES_BULK_SIZE)
151
+ .set("concurrent_requests", ES_CONCURRENT_REQUESTS
152
+ );
153
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
154
+ try {
155
+ plugin.transaction(config, schema, 0, new OutputPlugin.Control()
156
+ {
157
+ @Override
158
+ public List<TaskReport> run(TaskSource taskSource)
159
+ {
160
+ return Lists.newArrayList(Exec.newTaskReport());
161
+ }
162
+ });
163
+ } catch (Throwable t) {
164
+ if (t instanceof RuntimeException) {
165
+ assertTrue(t.getCause().getCause() instanceof ConfigException);
166
+ }
167
+ }
168
+ }
169
+
170
+ @Test
171
+ public void testResume()
172
+ {
173
+ ConfigSource config = config();
174
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
175
+ PluginTask task = config.loadConfig(PluginTask.class);
176
+ plugin.resume(task.dump(), schema, 0, new OutputPlugin.Control()
177
+ {
178
+ @Override
179
+ public List<TaskReport> run(TaskSource taskSource)
180
+ {
181
+ return Lists.newArrayList(Exec.newTaskReport());
182
+ }
183
+ });
184
+ }
185
+
186
+ @Test
187
+ public void testTransaction()
188
+ {
189
+ ConfigSource config = Exec.newConfigSource()
190
+ .set("in", inputConfig())
191
+ .set("parser", parserConfig(schemaConfig()))
192
+ .set("type", "elasticsearch")
193
+ .set("mode", "replace")
194
+ .set("nodes", ES_NODES)
195
+ .set("cluster_name", ES_CLUSTER_NAME)
196
+ .set("index", ES_INDEX)
197
+ .set("index_type", ES_INDEX_TYPE)
198
+ .set("id", ES_ID)
199
+ .set("bulk_actions", ES_BULK_ACTIONS)
200
+ .set("bulk_size", ES_BULK_SIZE)
201
+ .set("concurrent_requests", ES_CONCURRENT_REQUESTS
202
+ );
203
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
204
+ plugin.transaction(config, schema, 0, new OutputPlugin.Control()
205
+ {
206
+ @Override
207
+ public List<TaskReport> run(TaskSource taskSource)
208
+ {
209
+ return Lists.newArrayList(Exec.newTaskReport());
210
+ }
211
+ });
212
+ // no error happens
213
+ }
214
+
215
+ @Test
216
+ public void testOutputByOpen()
217
+ throws GeneralSecurityException, IOException, NoSuchMethodException,
218
+ IllegalAccessException, InvocationTargetException, ParseException
219
+ {
220
+ ConfigSource config = config();
221
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
222
+ PluginTask task = config.loadConfig(PluginTask.class);
223
+ plugin.transaction(config, schema, 0, new OutputPlugin.Control() {
224
+ @Override
225
+ public List<TaskReport> run(TaskSource taskSource) {
226
+ return Lists.newArrayList(Exec.newTaskReport());
227
+ }
228
+ });
229
+ TransactionalPageOutput output = plugin.open(task.dump(), schema, 0);
230
+
231
+ List<Page> pages = PageTestUtils.buildPage(runtime.getBufferAllocator(), schema, 1L, 32864L, Timestamp.ofEpochSecond(1422386629), Timestamp.ofEpochSecond(1422316800), true, 123.45, "embulk");
232
+ assertEquals(1, pages.size());
233
+ for (Page page : pages) {
234
+ output.add(page);
235
+ }
236
+
237
+ output.finish();
238
+ output.commit();
239
+
240
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
241
+ createClient.setAccessible(true);
242
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
243
+ GetResponse response = client.prepareGet(ES_INDEX, ES_INDEX_TYPE, "1").execute().actionGet();
244
+ assertTrue(response.isExists());
245
+ if (response.isExists()) {
246
+ Map<String, Object> map = response.getSourceAsMap();
247
+ assertEquals(1, map.get("id"));
248
+ assertEquals(32864, map.get("account"));
249
+ assertEquals("2015-01-27T19:23:49.000Z", map.get("time"));
250
+ assertEquals("2015-01-27T00:00:00.000Z", map.get("purchase"));
251
+ assertEquals(true, map.get("flg"));
252
+ assertEquals(123.45, map.get("score"));
253
+ assertEquals("embulk", map.get("comment"));
254
+ }
255
+ }
256
+ }
257
+
258
+ @Test
259
+ public void testOpenAbort()
260
+ {
261
+ ConfigSource config = config();
262
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
263
+ PluginTask task = config.loadConfig(PluginTask.class);
264
+ TransactionalPageOutput output = plugin.open(task.dump(), schema, 0);
265
+ output.abort();
266
+ // no error happens.
267
+ }
268
+
269
+ @Test
270
+ public void testCreateClientThrowsException()
271
+ throws GeneralSecurityException, IOException, NoSuchMethodException,
272
+ IllegalAccessException, InvocationTargetException
273
+ {
274
+ ConfigSource config = Exec.newConfigSource()
275
+ .set("in", inputConfig())
276
+ .set("parser", parserConfig(schemaConfig()))
277
+ .set("type", "elasticsearch")
278
+ .set("mode", "replace")
279
+ .set("nodes", Arrays.asList(ImmutableMap.of("host", "unknown-host", "port", 9300)))
280
+ .set("cluster_name", ES_CLUSTER_NAME)
281
+ .set("index", ES_INDEX)
282
+ .set("index_type", ES_INDEX_TYPE)
283
+ .set("id", ES_ID)
284
+ .set("bulk_actions", ES_BULK_ACTIONS)
285
+ .set("bulk_size", ES_BULK_SIZE)
286
+ .set("concurrent_requests", ES_CONCURRENT_REQUESTS
287
+ );
288
+ PluginTask task = config.loadConfig(PluginTask.class);
289
+
290
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
291
+ createClient.setAccessible(true);
292
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
293
+ } catch (Throwable t) {
294
+ if (t instanceof InvocationTargetException) {
295
+ assertTrue(t.getCause().getCause() instanceof UnknownHostException);
296
+ }
297
+ }
298
+ }
299
+
300
+ @Test
301
+ public void testMode()
302
+ {
303
+ assertEquals(2, ElasticsearchOutputPlugin.Mode.values().length);
304
+ assertEquals(ElasticsearchOutputPlugin.Mode.INSERT, ElasticsearchOutputPlugin.Mode.valueOf("INSERT"));
305
+ }
306
+
307
+ @Test(expected = ConfigException.class)
308
+ public void testModeThrowsConfigException()
309
+ {
310
+ ElasticsearchOutputPlugin.Mode.fromString("non-exists-mode");
311
+ }
312
+
313
+ @Test
314
+ public void testDeleteIndex()
315
+ throws GeneralSecurityException, IOException, NoSuchMethodException,
316
+ IllegalAccessException, InvocationTargetException
317
+ {
318
+ ConfigSource config = config();
319
+ PluginTask task = config.loadConfig(PluginTask.class);
320
+
321
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
322
+ createClient.setAccessible(true);
323
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
324
+ // Create Index
325
+ client.admin().indices().create(new CreateIndexRequest(ES_TEST_INDEX)).actionGet();
326
+
327
+ Method deleteIndex = ElasticsearchOutputPlugin.class.getDeclaredMethod("deleteIndex", String.class, Client.class);
328
+ deleteIndex.setAccessible(true);
329
+ deleteIndex.invoke(plugin, ES_TEST_INDEX, client);
330
+
331
+ assertEquals(false, client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasIndex(ES_TEST_INDEX));
332
+ }
333
+ }
334
+
335
+ @Test
336
+ public void testAlias()
337
+ throws GeneralSecurityException, IOException, NoSuchMethodException,
338
+ IllegalAccessException, InvocationTargetException
339
+ {
340
+ ConfigSource config = config();
341
+ PluginTask task = config.loadConfig(PluginTask.class);
342
+
343
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
344
+ createClient.setAccessible(true);
345
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
346
+
347
+ Method isAlias = ElasticsearchOutputPlugin.class.getDeclaredMethod("isAlias", String.class, Client.class);
348
+ isAlias.setAccessible(true);
349
+
350
+ Method isExistsAlias = ElasticsearchOutputPlugin.class.getDeclaredMethod("isExistsAlias", String.class, Client.class);
351
+ isExistsAlias.setAccessible(true);
352
+
353
+ Method getIndexByAlias = ElasticsearchOutputPlugin.class.getDeclaredMethod("getIndexByAlias", String.class, Client.class);
354
+ getIndexByAlias.setAccessible(true);
355
+
356
+ Method reAssignAlias = ElasticsearchOutputPlugin.class.getDeclaredMethod("reAssignAlias", String.class, String.class, Client.class);
357
+ reAssignAlias.setAccessible(true);
358
+
359
+ assertEquals(false, isAlias.invoke(plugin, ES_TEST_ALIAS, client));
360
+ assertEquals(false, isExistsAlias.invoke(plugin, ES_TEST_ALIAS, client));
361
+ List<String> indicesBefore = (List<String>) getIndexByAlias.invoke(plugin, ES_TEST_ALIAS, client);
362
+ assertEquals(0, indicesBefore.size());
363
+
364
+ // Create Index
365
+ client.admin().indices().create(new CreateIndexRequest(ES_TEST_INDEX)).actionGet();
366
+ client.admin().indices().create(new CreateIndexRequest(ES_TEST_INDEX2)).actionGet();
367
+ // Assign Alias
368
+ reAssignAlias.invoke(plugin, ES_TEST_ALIAS, ES_TEST_INDEX, client);
369
+
370
+ assertEquals(true, isAlias.invoke(plugin, ES_TEST_ALIAS, client));
371
+ assertEquals(true, isExistsAlias.invoke(plugin, ES_TEST_ALIAS, client));
372
+ List<String> indicesAfter = (List<String>) getIndexByAlias.invoke(plugin, ES_TEST_ALIAS, client);
373
+ assertEquals(1, indicesAfter.size());
374
+
375
+ // ReAssginAlias
376
+ reAssignAlias.invoke(plugin, ES_TEST_ALIAS, ES_TEST_INDEX2, client);
377
+ List<String> indicesReassign = (List<String>) getIndexByAlias.invoke(plugin, ES_TEST_ALIAS, client);
378
+ assertEquals(1, indicesReassign.size());
379
+ }
380
+ }
381
+
382
+ @Test
383
+ public void testIsExistsIndex()
384
+ throws GeneralSecurityException, IOException, NoSuchMethodException,
385
+ IllegalAccessException, InvocationTargetException
386
+ {
387
+ ConfigSource config = config();
388
+ PluginTask task = config.loadConfig(PluginTask.class);
389
+
390
+ Method createClient = ElasticsearchOutputPlugin.class.getDeclaredMethod("createClient", PluginTask.class);
391
+ createClient.setAccessible(true);
392
+ try (Client client = (Client) createClient.invoke(plugin, task)) {
393
+ Method isExistsIndex = ElasticsearchOutputPlugin.class.getDeclaredMethod("isExistsIndex", String.class, Client.class);
394
+ isExistsIndex.setAccessible(true);
395
+
396
+ // Delete index
397
+ if (client.admin().cluster().state(new ClusterStateRequest()).actionGet().getState().getMetaData().hasIndex(ES_TEST_INDEX)) {
398
+ client.admin().indices().delete(new DeleteIndexRequest(ES_TEST_INDEX)).actionGet();
399
+ }
400
+ assertEquals(false, isExistsIndex.invoke(plugin, ES_TEST_INDEX, client));
401
+
402
+ // Create Index
403
+ client.admin().indices().create(new CreateIndexRequest(ES_TEST_INDEX)).actionGet();
404
+ assertEquals(true, isExistsIndex.invoke(plugin, ES_TEST_INDEX, client));
405
+ }
406
+ }
407
+
408
+ @Test
409
+ public void testGenerateNewIndex()
410
+ {
411
+ String newIndexName = plugin.generateNewIndexName(ES_INDEX);
412
+ Timestamp time = Exec.getTransactionTime();
413
+ assertEquals(ES_INDEX + new SimpleDateFormat("_yyyyMMdd-HHmmss").format(time.toEpochMilli()), newIndexName);
414
+ }
415
+
416
+ private byte[] convertInputStreamToByte(InputStream is) throws IOException
417
+ {
418
+ ByteArrayOutputStream bo = new ByteArrayOutputStream();
419
+ byte [] buffer = new byte[1024];
420
+ while(true) {
421
+ int len = is.read(buffer);
422
+ if(len < 0) {
423
+ break;
424
+ }
425
+ bo.write(buffer, 0, len);
426
+ }
427
+ return bo.toByteArray();
428
+ }
429
+
430
+ private ConfigSource config()
431
+ {
432
+ return Exec.newConfigSource()
433
+ .set("in", inputConfig())
434
+ .set("parser", parserConfig(schemaConfig()))
435
+ .set("type", "elasticsearch")
436
+ .set("mode", "insert")
437
+ .set("nodes", ES_NODES)
438
+ .set("cluster_name", ES_CLUSTER_NAME)
439
+ .set("index", ES_INDEX)
440
+ .set("index_type", ES_INDEX_TYPE)
441
+ .set("id", ES_ID)
442
+ .set("bulk_actions", ES_BULK_ACTIONS)
443
+ .set("bulk_size", ES_BULK_SIZE)
444
+ .set("concurrent_requests", ES_CONCURRENT_REQUESTS);
445
+ }
446
+
447
+ private ImmutableMap<String, Object> inputConfig()
448
+ {
449
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
450
+ builder.put("type", "file");
451
+ builder.put("path_prefix", PATH_PREFIX);
452
+ builder.put("last_path", "");
453
+ return builder.build();
454
+ }
455
+
456
+ private ImmutableMap<String, Object> parserConfig(ImmutableList<Object> schemaConfig)
457
+ {
458
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
459
+ builder.put("type", "csv");
460
+ builder.put("newline", "CRLF");
461
+ builder.put("delimiter", ",");
462
+ builder.put("quote", "\"");
463
+ builder.put("escape", "\"");
464
+ builder.put("trim_if_not_quoted", false);
465
+ builder.put("skip_header_lines", 1);
466
+ builder.put("allow_extra_columns", false);
467
+ builder.put("allow_optional_columns", false);
468
+ builder.put("columns", schemaConfig);
469
+ return builder.build();
470
+ }
471
+
472
+ private ImmutableList<Object> schemaConfig()
473
+ {
474
+ ImmutableList.Builder<Object> builder = new ImmutableList.Builder<>();
475
+ builder.add(ImmutableMap.of("name", "id", "type", "long"));
476
+ builder.add(ImmutableMap.of("name", "account", "type", "long"));
477
+ builder.add(ImmutableMap.of("name", "time", "type", "timestamp", "format", "%Y-%m-%d %H:%M:%S"));
478
+ builder.add(ImmutableMap.of("name", "purchase", "type", "timestamp", "format", "%Y%m%d"));
479
+ builder.add(ImmutableMap.of("name", "flg", "type", "boolean"));
480
+ builder.add(ImmutableMap.of("name", "score", "type", "double"));
481
+ builder.add(ImmutableMap.of("name", "comment", "type", "string"));
482
+ return builder.build();
483
+ }
5
484
  }
@@ -0,0 +1,5 @@
1
+ id,account,time,purchase,flg,score,comment
2
+ 1,32864,2015-01-27 19:23:49,20150127,1,123.45,embulk
3
+ 2,14824,2015-01-27 19:01:23,20150127,0,234,56,embulk
4
+ 3,27559,2015-01-28 02:20:02,20150128,1,678.90,embulk
5
+ 4,11270,2015-01-29 11:54:36,20150129,0,100.00,embulk
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-output-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muga Nishizawa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-19 00:00:00.000000000 Z
11
+ date: 2016-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
- version_requirements: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '>='
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
14
  requirement: !ruby/object:Gem::Requirement
21
15
  requirements:
22
16
  - - '>='
23
17
  - !ruby/object:Gem::Version
24
18
  version: '1.0'
19
+ name: bundler
25
20
  prerelease: false
26
21
  type: :development
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
22
  version_requirements: !ruby/object:Gem::Requirement
30
23
  requirements:
31
24
  - - '>='
32
25
  - !ruby/object:Gem::Version
33
- version: '10.0'
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
34
28
  requirement: !ruby/object:Gem::Requirement
35
29
  requirements:
36
30
  - - '>='
37
31
  - !ruby/object:Gem::Version
38
32
  version: '10.0'
33
+ name: rake
39
34
  prerelease: false
40
35
  type: :development
41
- - !ruby/object:Gem::Dependency
42
- name: test-unit
43
36
  version_requirements: !ruby/object:Gem::Requirement
44
37
  requirements:
45
- - - ~>
38
+ - - '>='
46
39
  - !ruby/object:Gem::Version
47
- version: 3.0.2
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
48
42
  requirement: !ruby/object:Gem::Requirement
49
43
  requirements:
50
44
  - - ~>
51
45
  - !ruby/object:Gem::Version
52
46
  version: 3.0.2
47
+ name: test-unit
53
48
  prerelease: false
54
49
  type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.2
55
55
  description: Elasticsearch output plugin is an Embulk plugin that loads records to Elasticsearch read by any input plugins. Search the input plugins by "embulk-input" keyword.
56
56
  email:
57
57
  - muga.nishizawa@gmail.com
@@ -60,6 +60,7 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - .gitignore
63
+ - CHANGELOG.md
63
64
  - README.md
64
65
  - build.gradle
65
66
  - gradle/wrapper/gradle-wrapper.jar
@@ -70,24 +71,35 @@ files:
70
71
  - settings.gradle
71
72
  - src/main/java/org/embulk/output/elasticsearch/ElasticsearchOutputPlugin.java
72
73
  - src/test/java/org/embulk/output/elasticsearch/TestElasticsearchOutputPlugin.java
73
- - classpath/antlr-runtime-3.5.jar
74
- - classpath/asm-4.1.jar
75
- - classpath/asm-commons-4.1.jar
76
- - classpath/elasticsearch-1.5.2.jar
77
- - classpath/embulk-output-elasticsearch-0.1.8.jar
78
- - classpath/lucene-analyzers-common-4.10.4.jar
79
- - classpath/lucene-core-4.10.4.jar
80
- - classpath/lucene-grouping-4.10.4.jar
81
- - classpath/lucene-highlighter-4.10.4.jar
82
- - classpath/lucene-join-4.10.4.jar
83
- - classpath/lucene-memory-4.10.4.jar
84
- - classpath/lucene-misc-4.10.4.jar
85
- - classpath/lucene-queries-4.10.4.jar
86
- - classpath/lucene-queryparser-4.10.4.jar
87
- - classpath/lucene-sandbox-4.10.4.jar
88
- - classpath/lucene-spatial-4.10.4.jar
89
- - classpath/lucene-suggest-4.10.4.jar
74
+ - src/test/resources/sample_01.csv
75
+ - classpath/commons-cli-1.3.1.jar
76
+ - classpath/compress-lzf-1.0.2.jar
77
+ - classpath/elasticsearch-2.0.0.jar
78
+ - classpath/embulk-output-elasticsearch-0.2.0.jar
79
+ - classpath/HdrHistogram-2.1.6.jar
80
+ - classpath/hppc-0.7.1.jar
81
+ - classpath/jackson-dataformat-cbor-2.5.3.jar
82
+ - classpath/jackson-dataformat-smile-2.5.3.jar
83
+ - classpath/jackson-dataformat-yaml-2.5.3.jar
84
+ - classpath/joda-convert-1.2.jar
85
+ - classpath/joda-time-2.8.2.jar
86
+ - classpath/jsr166e-1.1.0.jar
87
+ - classpath/lucene-analyzers-common-5.2.1.jar
88
+ - classpath/lucene-backward-codecs-5.2.1.jar
89
+ - classpath/lucene-core-5.2.1.jar
90
+ - classpath/lucene-grouping-5.2.1.jar
91
+ - classpath/lucene-highlighter-5.2.1.jar
92
+ - classpath/lucene-join-5.2.1.jar
93
+ - classpath/lucene-memory-5.2.1.jar
94
+ - classpath/lucene-misc-5.2.1.jar
95
+ - classpath/lucene-queries-5.2.1.jar
96
+ - classpath/lucene-queryparser-5.2.1.jar
97
+ - classpath/lucene-sandbox-5.2.1.jar
98
+ - classpath/lucene-spatial-5.2.1.jar
99
+ - classpath/lucene-suggest-5.2.1.jar
100
+ - classpath/netty-3.10.5.Final.jar
90
101
  - classpath/spatial4j-0.4.1.jar
102
+ - classpath/t-digest-3.0.jar
91
103
  homepage: https://github.com/muga/embulk-output-elasticsearch
92
104
  licenses:
93
105
  - Apache 2.0