|
37 | 37 | import org.opensearch.dataprepper.model.configuration.PipelineDescription; |
38 | 38 | import org.opensearch.dataprepper.model.configuration.PluginSetting; |
39 | 39 | import org.opensearch.dataprepper.model.event.Event; |
| 40 | +import org.opensearch.dataprepper.model.event.EventHandle; |
40 | 41 | import org.opensearch.dataprepper.model.event.exceptions.EventKeyNotFoundException; |
41 | 42 | import org.opensearch.dataprepper.model.failures.DlqObject; |
42 | 43 | import org.opensearch.dataprepper.model.opensearch.OpenSearchBulkActions; |
|
77 | 78 | import org.opensearch.dataprepper.plugins.sink.opensearch.index.IndexTemplateAPIWrapper; |
78 | 79 | import org.opensearch.dataprepper.plugins.sink.opensearch.index.IndexTemplateAPIWrapperFactory; |
79 | 80 | import org.opensearch.dataprepper.plugins.sink.opensearch.index.IndexType; |
| 81 | +import org.opensearch.dataprepper.plugins.sink.opensearch.index.TSDBDocumentBuilder; |
80 | 82 | import org.opensearch.dataprepper.plugins.sink.opensearch.index.TemplateStrategy; |
81 | 83 | import org.opensearch.dataprepper.plugins.source.opensearch.configuration.ServerlessOptions; |
82 | 84 | import org.slf4j.Logger; |
@@ -171,6 +173,8 @@ public class OpenSearchSink extends AbstractSink<Record<Event>> { |
171 | 173 |
|
172 | 174 | private ExistingDocumentQueryManager existingDocumentQueryManager; |
173 | 175 |
|
| 176 | + private final TSDBDocumentBuilder tsdbDocumentBuilder; |
| 177 | + |
174 | 178 | private final ExecutorService queryExecutorService; |
175 | 179 |
|
176 | 180 | private final int processWorkerThreads; |
@@ -219,6 +223,7 @@ public OpenSearchSink(final PluginSetting pluginSetting, |
219 | 223 | this.lastFlushTimeMap = new ConcurrentHashMap<>(); |
220 | 224 | this.pluginConfigObservable = pluginConfigObservable; |
221 | 225 | this.objectMapper = new ObjectMapper(); |
| 226 | + this.tsdbDocumentBuilder = (this.indexType == IndexType.TSDB) ? new TSDBDocumentBuilder() : null; |
222 | 227 | this.queryExecutorService = openSearchSinkConfig.getIndexConfiguration().getQueryTerm() != null ? |
223 | 228 | Executors.newSingleThreadExecutor(BackgroundThreadFactory.defaultExecutorThreadFactory("existing-document-query-manager")) : null; |
224 | 229 |
|
@@ -470,6 +475,32 @@ public void doOutput(final Collection<Record<Event>> records) { |
470 | 475 | } |
471 | 476 |
|
472 | 477 | dataStreamIndex.ensureTimestamp(event, indexName); |
| 478 | + |
| 479 | + if (indexType == IndexType.TSDB) { |
| 480 | + try { |
| 481 | + final List<String> tsdbDocs = tsdbDocumentBuilder.build(event); |
| 482 | + final String tsdbAction = resolveEventAction(event); |
| 483 | + final List<BulkOperationWrapper> wrappers = new ArrayList<>(tsdbDocs.size()); |
| 484 | + for (int i = 0; i < tsdbDocs.size(); i++) { |
| 485 | + final SerializedJson doc = SerializedJson.fromStringAndOptionals(tsdbDocs.get(i), null, null, null); |
| 486 | + final BulkOperation op = getBulkOperationForAction(tsdbAction, doc, null, indexName, null); |
| 487 | + final BulkOperationWrapper wrapper = (i == 0) |
| 488 | + ? new BulkOperationWrapper(op, event.getEventHandle(), null, null) |
| 489 | + : new BulkOperationWrapper(op, (EventHandle) null, null, null); |
| 490 | + wrappers.add(wrapper); |
| 491 | + } |
| 492 | + for (final BulkOperationWrapper wrapper : wrappers) { |
| 493 | + bulkRequest = flushBatch(bulkRequest, wrapper, lastFlushTime); |
| 494 | + bulkRequest.addOperation(wrapper); |
| 495 | + } |
| 496 | + } catch (final Exception e) { |
| 497 | + LOG.error("Failed to build TSDB documents for event: {}", e.getMessage(), e); |
| 498 | + dynamicIndexDroppedEvents.increment(); |
| 499 | + logFailureForDlqObjects(List.of(createDlqObjectFromEvent(event, indexName, e.getMessage())), e); |
| 500 | + } |
| 501 | + continue; |
| 502 | + } |
| 503 | + |
473 | 504 | final SerializedJson document = getDocument(event); |
474 | 505 |
|
475 | 506 | Long version = null; |
@@ -502,20 +533,7 @@ public void doOutput(final Collection<Record<Event>> records) { |
502 | 533 | } |
503 | 534 | } |
504 | 535 |
|
505 | | - String eventAction = action; |
506 | | - if (actions != null) { |
507 | | - for (final ActionConfiguration actionEntry: actions) { |
508 | | - final String condition = actionEntry.getWhen(); |
509 | | - eventAction = actionEntry.getType(); |
510 | | - if (condition != null && |
511 | | - expressionEvaluator.evaluateConditional(condition, event)) { |
512 | | - break; |
513 | | - } |
514 | | - } |
515 | | - } |
516 | | - if (eventAction.contains("${")) { |
517 | | - eventAction = event.formatString(eventAction, expressionEvaluator); |
518 | | - } |
| 536 | + String eventAction = resolveEventAction(event); |
519 | 537 |
|
520 | 538 | if (dataStreamDetector.isDataStream(indexName)) { |
521 | 539 | eventAction = dataStreamIndex.determineAction(eventAction, indexName); |
@@ -623,7 +641,7 @@ void successfulOperationsHandler(final List<BulkOperationWrapper> successfulOper |
623 | 641 | if (bulkOperation.getEvent() != null) { |
624 | 642 | bulkOperation.getEvent().getEventHandle().release(true); |
625 | 643 | } else { |
626 | | - bulkOperation.getEventHandle().release(true); |
| 644 | + bulkOperation.releaseEventHandle(true); |
627 | 645 | } |
628 | 646 | } |
629 | 647 | return; |
@@ -776,6 +794,24 @@ private DlqObject createDlqObjectFromEvent(final Event event, |
776 | 794 | return builder.build(); |
777 | 795 | } |
778 | 796 |
|
| 797 | + private String resolveEventAction(final Event event) { |
| 798 | + String resolvedAction = action; |
| 799 | + if (actions != null) { |
| 800 | + for (final ActionConfiguration actionEntry : actions) { |
| 801 | + final String condition = actionEntry.getWhen(); |
| 802 | + resolvedAction = actionEntry.getType(); |
| 803 | + if (condition != null && |
| 804 | + expressionEvaluator.evaluateConditional(condition, event)) { |
| 805 | + break; |
| 806 | + } |
| 807 | + } |
| 808 | + } |
| 809 | + if (resolvedAction.contains("${")) { |
| 810 | + resolvedAction = event.formatString(resolvedAction, expressionEvaluator); |
| 811 | + } |
| 812 | + return resolvedAction; |
| 813 | + } |
| 814 | + |
779 | 815 | /** |
780 | 816 | * This function is used for update and upsert bulk actions to determine whether the original JsonNode needs to be filtered down |
781 | 817 | * based on the user's sink configuration. If a new parameter manipulates the document before sending to OpenSearch, it needs to be added to |
|
0 commit comments