@@ -8,8 +8,10 @@ package org.opensearch.alerting
8
8
import org.apache.logging.log4j.LogManager
9
9
import org.opensearch.ExceptionsHelper
10
10
import org.opensearch.OpenSearchStatusException
11
+ import org.opensearch.action.DocWriteRequest
12
+ import org.opensearch.action.bulk.BulkRequest
13
+ import org.opensearch.action.bulk.BulkResponse
11
14
import org.opensearch.action.index.IndexRequest
12
- import org.opensearch.action.index.IndexResponse
13
15
import org.opensearch.action.search.SearchAction
14
16
import org.opensearch.action.search.SearchRequest
15
17
import org.opensearch.action.search.SearchResponse
@@ -273,10 +275,7 @@ object DocumentLevelMonitorRunner : MonitorRunner() {
273
275
// If there are no triggers defined, we still want to generate findings
274
276
if (monitor.triggers.isEmpty()) {
275
277
if (dryrun == false && monitor.id != Monitor .NO_ID ) {
276
- docsToQueries.forEach {
277
- val triggeredQueries = it.value.map { queryId -> idQueryMap[queryId]!! }
278
- createFindings(monitor, monitorCtx, triggeredQueries, it.key, true )
279
- }
278
+ createFindings(monitor, monitorCtx, docsToQueries, idQueryMap, true )
280
279
}
281
280
} else {
282
281
monitor.triggers.forEach {
@@ -365,7 +364,7 @@ object DocumentLevelMonitorRunner : MonitorRunner() {
365
364
trigger : DocumentLevelTrigger ,
366
365
monitor : Monitor ,
367
366
idQueryMap : Map <String , DocLevelQuery >,
368
- docsToQueries : Map <String , List <String >>,
367
+ docsToQueries : MutableMap <String , MutableList <String >>,
369
368
queryToDocIds : Map <DocLevelQuery , Set <String >>,
370
369
dryrun : Boolean ,
371
370
workflowRunContext : WorkflowRunContext ? ,
@@ -374,35 +373,34 @@ object DocumentLevelMonitorRunner : MonitorRunner() {
374
373
val triggerCtx = DocumentLevelTriggerExecutionContext (monitor, trigger)
375
374
val triggerResult = monitorCtx.triggerService!! .runDocLevelTrigger(monitor, trigger, queryToDocIds)
376
375
377
- val findings = mutableListOf<String >()
378
- val findingDocPairs = mutableListOf<Pair <String , String >>()
376
+ val triggerFindingDocPairs = mutableListOf<Pair <String , String >>()
379
377
380
378
// TODO: Implement throttling for findings
381
- docsToQueries.forEach {
382
- val triggeredQueries = it.value.map { queryId -> idQueryMap[queryId]!! }
383
- val findingId = createFindings(
384
- monitor,
385
- monitorCtx,
386
- triggeredQueries,
387
- it.key,
388
- ! dryrun && monitor.id != Monitor .NO_ID ,
389
- executionId
390
- )
391
- findings.add(findingId)
379
+ val findingToDocPairs = createFindings(
380
+ monitor,
381
+ monitorCtx,
382
+ docsToQueries,
383
+ idQueryMap,
384
+ ! dryrun && monitor.id != Monitor .NO_ID ,
385
+ executionId
386
+ )
392
387
393
- if (triggerResult.triggeredDocs.contains(it.key)) {
394
- findingDocPairs.add(Pair (findingId, it.key))
388
+ findingToDocPairs.forEach {
389
+ // Only pick those entries whose docs have triggers associated with them
390
+ if (triggerResult.triggeredDocs.contains(it.second)) {
391
+ triggerFindingDocPairs.add(Pair (it.first, it.second))
395
392
}
396
393
}
397
394
398
395
val actionCtx = triggerCtx.copy(
399
396
triggeredDocs = triggerResult.triggeredDocs,
400
- relatedFindings = findings,
397
+ // confirm if this is right or only trigger-able findings should be present in this list
398
+ relatedFindings = findingToDocPairs.map { it.first },
401
399
error = monitorResult.error ? : triggerResult.error
402
400
)
403
401
404
402
val alerts = mutableListOf<Alert >()
405
- findingDocPairs .forEach {
403
+ triggerFindingDocPairs .forEach {
406
404
val alert = monitorCtx.alertService!! .composeDocLevelAlert(
407
405
listOf (it.first),
408
406
listOf (it.second),
@@ -461,51 +459,82 @@ object DocumentLevelMonitorRunner : MonitorRunner() {
461
459
return triggerResult
462
460
}
463
461
462
+ /* *
463
+ * 1. Bulk index all findings based on shouldCreateFinding flag
464
+ * 2. invoke publishFinding() to kickstart auto-correlations
465
+ * 3. Returns a list of pairs for finding id to doc id
466
+ */
464
467
private suspend fun createFindings (
465
468
monitor : Monitor ,
466
469
monitorCtx : MonitorRunnerExecutionContext ,
467
- docLevelQueries : List < DocLevelQuery >,
468
- matchingDocId : String ,
470
+ docsToQueries : MutableMap < String , MutableList < String > >,
471
+ idQueryMap : Map < String , DocLevelQuery > ,
469
472
shouldCreateFinding : Boolean ,
470
473
workflowExecutionId : String? = null,
471
- ): String {
472
- // Before the "|" is the doc id and after the "|" is the index
473
- val docIndex = matchingDocId.split(" |" )
474
+ ): List <Pair <String , String >> {
474
475
475
- val finding = Finding (
476
- id = UUID .randomUUID().toString(),
477
- relatedDocIds = listOf (docIndex[0 ]),
478
- correlatedDocIds = listOf (docIndex[0 ]),
479
- monitorId = monitor.id,
480
- monitorName = monitor.name,
481
- index = docIndex[1 ],
482
- docLevelQueries = docLevelQueries,
483
- timestamp = Instant .now(),
484
- executionId = workflowExecutionId
485
- )
476
+ val findingDocPairs = mutableListOf<Pair <String , String >>()
477
+ val findings = mutableListOf<Finding >()
478
+ val indexRequests = mutableListOf<IndexRequest >()
486
479
487
- val findingStr = finding.toXContent(XContentBuilder .builder(XContentType .JSON .xContent()), ToXContent .EMPTY_PARAMS ).string()
488
- logger.debug(" Findings: $findingStr " )
480
+ docsToQueries.forEach {
481
+ val triggeredQueries = it.value.map { queryId -> idQueryMap[queryId]!! }
482
+
483
+ // Before the "|" is the doc id and after the "|" is the index
484
+ val docIndex = it.key.split(" |" )
489
485
490
- if (shouldCreateFinding) {
491
- val indexRequest = IndexRequest (monitor.dataSources.findingsIndex)
492
- .setRefreshPolicy(WriteRequest .RefreshPolicy .IMMEDIATE )
493
- .source(findingStr, XContentType .JSON )
494
- .id(finding.id)
495
- .routing(finding.id)
486
+ val finding = Finding (
487
+ id = UUID .randomUUID().toString(),
488
+ relatedDocIds = listOf (docIndex[0 ]),
489
+ correlatedDocIds = listOf (docIndex[0 ]),
490
+ monitorId = monitor.id,
491
+ monitorName = monitor.name,
492
+ index = docIndex[1 ],
493
+ docLevelQueries = triggeredQueries,
494
+ timestamp = Instant .now(),
495
+ executionId = workflowExecutionId
496
+ )
497
+ findingDocPairs.add(Pair (finding.id, it.key))
498
+ findings.add(finding)
499
+
500
+ val findingStr =
501
+ finding.toXContent(XContentBuilder .builder(XContentType .JSON .xContent()), ToXContent .EMPTY_PARAMS )
502
+ .string()
503
+ logger.debug(" Findings: $findingStr " )
504
+
505
+ if (shouldCreateFinding) {
506
+ indexRequests + = IndexRequest (monitor.dataSources.findingsIndex)
507
+ .source(findingStr, XContentType .JSON )
508
+ .id(finding.id)
509
+ .routing(finding.id)
510
+ .opType(DocWriteRequest .OpType .INDEX )
511
+ }
512
+ }
496
513
497
- monitorCtx.client!! .suspendUntil<Client , IndexResponse > {
498
- monitorCtx.client!! .index(indexRequest, it)
514
+ if (indexRequests.isNotEmpty()) {
515
+ val bulkResponse: BulkResponse = monitorCtx.client!! .suspendUntil {
516
+ bulk(BulkRequest ().add(indexRequests).setRefreshPolicy(WriteRequest .RefreshPolicy .IMMEDIATE ), it)
517
+ }
518
+ if (bulkResponse.hasFailures()) {
519
+ bulkResponse.items.forEach { item ->
520
+ if (item.isFailed) {
521
+ logger.debug(" Failed indexing the finding ${item.id} of monitor [${monitor.id} ]" )
522
+ }
523
+ }
524
+ } else {
525
+ logger.debug(" [${bulkResponse.items.size} ] All findings successfully indexed." )
499
526
}
500
527
}
501
528
502
529
try {
503
- publishFinding(monitor, monitorCtx, finding)
530
+ findings.forEach { finding ->
531
+ publishFinding(monitor, monitorCtx, finding)
532
+ }
504
533
} catch (e: Exception ) {
505
534
// suppress exception
506
535
logger.error(" Optional finding callback failed" , e)
507
536
}
508
- return finding.id
537
+ return findingDocPairs
509
538
}
510
539
511
540
private fun publishFinding (
0 commit comments