use of org.opensearch.ad.model.ADTask.IS_LATEST_FIELD in project anomaly-detection by opensearch-project.
the class ADDataMigrator method checkIfRealtimeTaskExistsAndBackfill.
private void checkIfRealtimeTaskExistsAndBackfill(AnomalyDetectorJob job, AnomalyDetectorFunction createRealtimeTaskFunction, ConcurrentLinkedQueue<AnomalyDetectorJob> detectorJobs, boolean migrateAll) {
String jobId = job.getName();
BoolQueryBuilder query = new BoolQueryBuilder();
query.filter(new TermQueryBuilder(DETECTOR_ID_FIELD, jobId));
if (job.isEnabled()) {
query.filter(new TermQueryBuilder(IS_LATEST_FIELD, true));
}
query.filter(new TermsQueryBuilder(TASK_TYPE_FIELD, taskTypeToString(ADTaskType.REALTIME_TASK_TYPES)));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(query).size(1);
SearchRequest searchRequest = new SearchRequest(DETECTION_STATE_INDEX).source(searchSourceBuilder);
client.search(searchRequest, ActionListener.wrap(r -> {
if (r != null && r.getHits().getTotalHits().value > 0) {
// Backfill next realtime job
backfillRealtimeTask(detectorJobs, migrateAll);
return;
}
createRealtimeTaskFunction.execute();
}, e -> {
if (e instanceof ResourceNotFoundException) {
createRealtimeTaskFunction.execute();
}
logger.error("Failed to search tasks of detector " + jobId);
}));
}
use of org.opensearch.ad.model.ADTask.IS_LATEST_FIELD in project anomaly-detection by opensearch-project.
the class ADTaskManager method getAndExecuteOnLatestADTasks.
/**
* Get latest AD tasks and execute consumer function.
* If resetTaskState is true, will collect latest task's profile data from all data nodes. If no data
* node running the latest task, will reset the task state as STOPPED; otherwise, check if there is
* any stale running entities(entity exists in coordinating node cache but no task running on worker
* node) and clean up.
* [Important!] Make sure listener returns in function
*
* @param detectorId detector id
* @param parentTaskId parent task id
* @param entity entity value
* @param adTaskTypes AD task types
* @param function consumer function
* @param transportService transport service
* @param resetTaskState reset task state or not
* @param size return how many AD tasks
* @param listener action listener
* @param <T> response type of action listener
*/
public <T> void getAndExecuteOnLatestADTasks(String detectorId, String parentTaskId, Entity entity, List<ADTaskType> adTaskTypes, Consumer<List<ADTask>> function, TransportService transportService, boolean resetTaskState, int size, ActionListener<T> listener) {
BoolQueryBuilder query = new BoolQueryBuilder();
query.filter(new TermQueryBuilder(DETECTOR_ID_FIELD, detectorId));
query.filter(new TermQueryBuilder(IS_LATEST_FIELD, true));
if (parentTaskId != null) {
query.filter(new TermQueryBuilder(PARENT_TASK_ID_FIELD, parentTaskId));
}
if (adTaskTypes != null && adTaskTypes.size() > 0) {
query.filter(new TermsQueryBuilder(TASK_TYPE_FIELD, taskTypeToString(adTaskTypes)));
}
if (entity != null && !isNullOrEmpty(entity.getAttributes())) {
String path = "entity";
String entityKeyFieldName = path + ".name";
String entityValueFieldName = path + ".value";
for (Map.Entry<String, String> attribute : entity.getAttributes().entrySet()) {
BoolQueryBuilder entityBoolQuery = new BoolQueryBuilder();
TermQueryBuilder entityKeyFilterQuery = QueryBuilders.termQuery(entityKeyFieldName, attribute.getKey());
TermQueryBuilder entityValueFilterQuery = QueryBuilders.termQuery(entityValueFieldName, attribute.getValue());
entityBoolQuery.filter(entityKeyFilterQuery).filter(entityValueFilterQuery);
NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder(path, entityBoolQuery, ScoreMode.None);
query.filter(nestedQueryBuilder);
}
}
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(query).sort(EXECUTION_START_TIME_FIELD, SortOrder.DESC).size(size);
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(sourceBuilder);
searchRequest.indices(DETECTION_STATE_INDEX);
client.search(searchRequest, ActionListener.wrap(r -> {
// https://github.com/opendistro-for-elasticsearch/anomaly-detection/pull/359#discussion_r558653132
// getTotalHits will be null when we track_total_hits is false in the query request.
// Add more checking here to cover some unknown cases.
List<ADTask> adTasks = new ArrayList<>();
if (r == null || r.getHits().getTotalHits() == null || r.getHits().getTotalHits().value == 0) {
// don't throw exception here as consumer functions need to handle missing task
// in different way.
function.accept(adTasks);
return;
}
Iterator<SearchHit> iterator = r.getHits().iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
try (XContentParser parser = createXContentParserFromRegistry(xContentRegistry, searchHit.getSourceRef())) {
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
ADTask adTask = ADTask.parse(parser, searchHit.getId());
adTasks.add(adTask);
} catch (Exception e) {
String message = "Failed to parse AD task for detector " + detectorId + ", task id " + searchHit.getId();
logger.error(message, e);
listener.onFailure(new OpenSearchStatusException(message, RestStatus.INTERNAL_SERVER_ERROR));
}
}
if (resetTaskState) {
resetLatestDetectorTaskState(adTasks, function, transportService, listener);
} else {
function.accept(adTasks);
}
}, e -> {
if (e instanceof IndexNotFoundException) {
function.accept(new ArrayList<>());
} else {
logger.error("Failed to search AD task for detector " + detectorId, e);
listener.onFailure(e);
}
}));
}
use of org.opensearch.ad.model.ADTask.IS_LATEST_FIELD in project anomaly-detection by opensearch-project.
the class ADTaskManager method maintainRunningHistoricalTasks.
// =========================================================
// Methods below are maintenance code triggered by hourly cron
// =========================================================
/**
* Maintain running historical tasks.
* Search current running latest tasks, then maintain tasks one by one.
* Get task profile to check if task is really running on worker node.
* 1. If not running, reset task state as STOPPED.
* 2. If task is running and task for HC detector, check if there is any stale running entities and
* clean up.
*
* @param transportService transport service
* @param size return how many tasks
*/
public void maintainRunningHistoricalTasks(TransportService transportService, int size) {
// Clean expired HC batch task run state cache.
adTaskCacheManager.cleanExpiredHCBatchTaskRunStates();
// Find owning node with highest AD version to make sure we only have 1 node maintain running historical tasks
// and we use the latest logic.
Optional<DiscoveryNode> owningNode = hashRing.getOwningNodeWithHighestAdVersion(AD_TASK_MAINTAINENCE_NODE_MODEL_ID);
if (!owningNode.isPresent() || !clusterService.localNode().getId().equals(owningNode.get().getId())) {
return;
}
logger.info("Start to maintain running historical tasks");
BoolQueryBuilder query = new BoolQueryBuilder();
query.filter(new TermQueryBuilder(IS_LATEST_FIELD, true));
query.filter(new TermsQueryBuilder(TASK_TYPE_FIELD, taskTypeToString(HISTORICAL_DETECTOR_TASK_TYPES)));
query.filter(new TermsQueryBuilder(STATE_FIELD, NOT_ENDED_STATES));
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// default maintain interval is 5 seconds, so maintain 10 tasks will take at least 50 seconds.
sourceBuilder.query(query).sort(LAST_UPDATE_TIME_FIELD, SortOrder.DESC).size(size);
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(sourceBuilder);
searchRequest.indices(DETECTION_STATE_INDEX);
client.search(searchRequest, ActionListener.wrap(r -> {
if (r == null || r.getHits().getTotalHits() == null || r.getHits().getTotalHits().value == 0) {
return;
}
ConcurrentLinkedQueue<ADTask> taskQueue = new ConcurrentLinkedQueue<>();
Iterator<SearchHit> iterator = r.getHits().iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
try (XContentParser parser = createXContentParserFromRegistry(xContentRegistry, searchHit.getSourceRef())) {
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
taskQueue.add(ADTask.parse(parser, searchHit.getId()));
} catch (Exception e) {
logger.error("Maintaining running historical task: failed to parse AD task " + searchHit.getId(), e);
}
}
maintainRunningHistoricalTask(taskQueue, transportService);
}, e -> {
if (e instanceof IndexNotFoundException) {
// the method will be called hourly
// don't log stack trace as most of OpenSearch domains have no AD installed
logger.debug(STATE_INDEX_NOT_EXIST_MSG);
} else {
logger.error("Failed to search historical tasks in maintaining job", e);
}
}));
}
use of org.opensearch.ad.model.ADTask.IS_LATEST_FIELD in project anomaly-detection by opensearch-project.
the class ADTaskManager method updateLatestFlagOfOldTasksAndCreateNewTask.
private void updateLatestFlagOfOldTasksAndCreateNewTask(AnomalyDetector detector, DetectionDateRange detectionDateRange, User user, ActionListener<AnomalyDetectorJobResponse> listener) {
UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest();
updateByQueryRequest.indices(DETECTION_STATE_INDEX);
BoolQueryBuilder query = new BoolQueryBuilder();
query.filter(new TermQueryBuilder(DETECTOR_ID_FIELD, detector.getDetectorId()));
query.filter(new TermQueryBuilder(IS_LATEST_FIELD, true));
// make sure we reset all latest task as false when user switch from single entity to HC, vice versa.
query.filter(new TermsQueryBuilder(TASK_TYPE_FIELD, taskTypeToString(getADTaskTypes(detectionDateRange, true))));
updateByQueryRequest.setQuery(query);
updateByQueryRequest.setRefresh(true);
String script = String.format(Locale.ROOT, "ctx._source.%s=%s;", IS_LATEST_FIELD, false);
updateByQueryRequest.setScript(new Script(script));
client.execute(UpdateByQueryAction.INSTANCE, updateByQueryRequest, ActionListener.wrap(r -> {
List<BulkItemResponse.Failure> bulkFailures = r.getBulkFailures();
if (bulkFailures.isEmpty()) {
// Realtime AD coordinating node is chosen by job scheduler, we won't know it until realtime AD job
// runs. Just set realtime AD coordinating node as null here, and AD job runner will reset correct
// coordinating node once realtime job starts.
// For historical analysis, this method will be called on coordinating node, so we can set coordinating
// node as local node.
String coordinatingNode = detectionDateRange == null ? null : clusterService.localNode().getId();
createNewADTask(detector, detectionDateRange, user, coordinatingNode, listener);
} else {
logger.error("Failed to update old task's state for detector: {}, response: {} ", detector.getDetectorId(), r.toString());
listener.onFailure(bulkFailures.get(0).getCause());
}
}, e -> {
logger.error("Failed to reset old tasks as not latest for detector " + detector.getDetectorId(), e);
listener.onFailure(e);
}));
}
Aggregations