@@ -266,26 +266,25 @@ private void normalDeleteJob(ParentTaskAssigningClient parentTaskClient, DeleteJ
266
266
private void deleteJobDocuments (ParentTaskAssigningClient parentTaskClient , String jobId ,
267
267
CheckedConsumer <Boolean , Exception > finishedHandler , Consumer <Exception > failureHandler ) {
268
268
269
- AtomicReference <String > indexName = new AtomicReference <>();
269
+ AtomicReference <String []> indexNames = new AtomicReference <>();
270
270
271
271
final ActionListener <AcknowledgedResponse > completionHandler = ActionListener .wrap (
272
272
response -> finishedHandler .accept (response .isAcknowledged ()),
273
273
failureHandler );
274
274
275
- // Step 8. If we did not drop the index and after DBQ state done, we delete the aliases
275
+ // Step 8. If we did not drop the indices and after DBQ state done, we delete the aliases
276
276
ActionListener <BulkByScrollResponse > dbqHandler = ActionListener .wrap (
277
277
bulkByScrollResponse -> {
278
- if (bulkByScrollResponse == null ) { // no action was taken by DBQ, assume Index was deleted
278
+ if (bulkByScrollResponse == null ) { // no action was taken by DBQ, assume indices were deleted
279
279
completionHandler .onResponse (new AcknowledgedResponse (true ));
280
280
} else {
281
281
if (bulkByScrollResponse .isTimedOut ()) {
282
- logger .warn ("[{}] DeleteByQuery for indices [{}, {}] timed out." , jobId , indexName .get (),
283
- indexName .get () + "-*" );
282
+ logger .warn ("[{}] DeleteByQuery for indices [{}] timed out." , jobId , String .join (", " , indexNames .get ()));
284
283
}
285
284
if (!bulkByScrollResponse .getBulkFailures ().isEmpty ()) {
286
- logger .warn ("[{}] {} failures and {} conflicts encountered while running DeleteByQuery on indices [{}, {} ]." ,
285
+ logger .warn ("[{}] {} failures and {} conflicts encountered while running DeleteByQuery on indices [{}]." ,
287
286
jobId , bulkByScrollResponse .getBulkFailures ().size (), bulkByScrollResponse .getVersionConflicts (),
288
- indexName . get (), indexName .get () + "-*" );
287
+ String . join ( ", " , indexNames .get ()) );
289
288
for (BulkItemResponse .Failure failure : bulkByScrollResponse .getBulkFailures ()) {
290
289
logger .warn ("DBQ failure: " + failure );
291
290
}
@@ -295,13 +294,12 @@ private void deleteJobDocuments(ParentTaskAssigningClient parentTaskClient, Stri
295
294
},
296
295
failureHandler );
297
296
298
- // Step 7. If we did not delete the index , we run a delete by query
297
+ // Step 7. If we did not delete the indices , we run a delete by query
299
298
ActionListener <Boolean > deleteByQueryExecutor = ActionListener .wrap (
300
299
response -> {
301
- if (response ) {
302
- String indexPattern = indexName .get () + "-*" ;
303
- logger .info ("Running DBQ on [" + indexName .get () + "," + indexPattern + "] for job [" + jobId + "]" );
304
- DeleteByQueryRequest request = new DeleteByQueryRequest (indexName .get (), indexPattern );
300
+ if (response && indexNames .get ().length > 0 ) {
301
+ logger .info ("Running DBQ on [" + String .join (", " , indexNames .get ()) + "] for job [" + jobId + "]" );
302
+ DeleteByQueryRequest request = new DeleteByQueryRequest (indexNames .get ());
305
303
ConstantScoreQueryBuilder query =
306
304
new ConstantScoreQueryBuilder (new TermQueryBuilder (Job .ID .getPreferredName (), jobId ));
307
305
request .setQuery (query );
@@ -317,15 +315,15 @@ private void deleteJobDocuments(ParentTaskAssigningClient parentTaskClient, Stri
317
315
},
318
316
failureHandler );
319
317
320
- // Step 6. If we have any hits, that means we are NOT the only job on this index , and should not delete it
321
- // if we do not have any hits, we can drop the index and then skip the DBQ and alias deletion
318
+ // Step 6. If we have any hits, that means we are NOT the only job on these indices , and should not delete the indices.
319
+ // If we do not have any hits, we can drop the indices and then skip the DBQ and alias deletion.
322
320
ActionListener <SearchResponse > customIndexSearchHandler = ActionListener .wrap (
323
321
searchResponse -> {
324
322
if (searchResponse == null || searchResponse .getHits ().totalHits > 0 ) {
325
323
deleteByQueryExecutor .onResponse (true ); // We need to run DBQ and alias deletion
326
324
} else {
327
- logger .info ("Running DELETE Index on [" + indexName . get () + "] for job [" + jobId + "]" );
328
- DeleteIndexRequest request = new DeleteIndexRequest (indexName .get ());
325
+ logger .info ("Running DELETE Index on [" + String . join ( ", " , indexNames . get () ) + "] for job [" + jobId + "]" );
326
+ DeleteIndexRequest request = new DeleteIndexRequest (indexNames .get ());
329
327
request .indicesOptions (IndicesOptions .lenientExpandOpen ());
330
328
// If we have deleted the index, then we don't need to delete the aliases or run the DBQ
331
329
executeAsyncWithOrigin (
@@ -347,29 +345,43 @@ private void deleteJobDocuments(ParentTaskAssigningClient parentTaskClient, Stri
347
345
}
348
346
);
349
347
350
- // Step 5. Determine if we are on a shared index by looking at `.ml-anomalies-shared` or the custom index's aliases
348
+ // Step 5. Determine if we are on shared indices by looking at whether the initial index was ".ml-anomalies-shared"
349
+ // or whether the indices that the job's results alias points to contain any documents from other jobs.
350
+ // TODO: this check is currently assuming that a job's results indices are either ALL shared or ALL
351
+ // dedicated to the job. We have considered functionality like rolling jobs that generate large
352
+ // volumes of results from shared to dedicated indices. On deletion such a job would have a mix of
353
+ // shared indices requiring DBQ and dedicated indices that could be simply dropped. The current
354
+ // functionality would apply DBQ to all these indices, which is safe but suboptimal. So this functionality
355
+ // should be revisited when we add rolling results index functionality, especially if we add the ability
356
+ // to switch a job over to a dedicated index for future results.
351
357
ActionListener <Job > getJobHandler = ActionListener .wrap (
352
358
job -> {
353
- indexName .set (job .getResultsIndexName ());
354
- if (indexName .get ().equals (AnomalyDetectorsIndexFields .RESULTS_INDEX_PREFIX +
355
- AnomalyDetectorsIndexFields .RESULTS_INDEX_DEFAULT )) {
356
- //don't bother searching the index any further, we are on the default shared
359
+ indexNames .set (indexNameExpressionResolver .concreteIndexNames (clusterService .state (),
360
+ IndicesOptions .lenientExpandOpen (), AnomalyDetectorsIndex .jobResultsAliasedName (jobId )));
361
+ // The job may no longer be using the initial shared index, but if it started off on a
362
+ // shared index then it will still be on a shared index even if it's been reindexed
363
+ if (job .getInitialResultsIndexName ()
364
+ .equals (AnomalyDetectorsIndexFields .RESULTS_INDEX_PREFIX + AnomalyDetectorsIndexFields .RESULTS_INDEX_DEFAULT )) {
365
+ // don't bother searching the index any further, we are on the default shared
366
+ customIndexSearchHandler .onResponse (null );
367
+ } else if (indexNames .get ().length == 0 ) {
368
+ // don't bother searching the index any further - it's already been closed or deleted
357
369
customIndexSearchHandler .onResponse (null );
358
370
} else {
359
371
SearchSourceBuilder source = new SearchSourceBuilder ()
360
372
.size (1 )
361
373
.query (QueryBuilders .boolQuery ().filter (
362
374
QueryBuilders .boolQuery ().mustNot (QueryBuilders .termQuery (Job .ID .getPreferredName (), jobId ))));
363
375
364
- SearchRequest searchRequest = new SearchRequest (indexName .get ());
376
+ SearchRequest searchRequest = new SearchRequest (indexNames .get ());
365
377
searchRequest .source (source );
366
378
executeAsyncWithOrigin (parentTaskClient , ML_ORIGIN , SearchAction .INSTANCE , searchRequest , customIndexSearchHandler );
367
379
}
368
380
},
369
381
failureHandler
370
382
);
371
383
372
- // Step 4. Get the job as the result index name is required
384
+ // Step 4. Get the job as the initial result index name is required
373
385
ActionListener <Boolean > deleteCategorizerStateHandler = ActionListener .wrap (
374
386
response -> {
375
387
jobManager .getJob (jobId , getJobHandler );
0 commit comments