in src/main/java/org/opensearch/ad/transport/SearchTopAnomalyResultTransportAction.java [219:341]
protected void doExecute(Task task, SearchTopAnomalyResultRequest request, ActionListener<SearchTopAnomalyResultResponse> listener) {
GetAnomalyDetectorRequest getAdRequest = new GetAnomalyDetectorRequest(
request.getDetectorId(),
// The default version value used in org.opensearch.rest.action.RestActions.parseVersion()
-3L,
false,
true,
"",
"",
false,
null
);
client.execute(GetAnomalyDetectorAction.INSTANCE, getAdRequest, ActionListener.wrap(getAdResponse -> {
// Make sure detector exists
if (getAdResponse.getDetector() == null) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "No anomaly detector found with ID %s", request.getDetectorId())
);
}
// Make sure detector is HC
List<String> categoryFieldsFromResponse = getAdResponse.getDetector().getCategoryField();
if (categoryFieldsFromResponse == null || categoryFieldsFromResponse.isEmpty()) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "No category fields found for detector ID %s", request.getDetectorId())
);
}
// Validating the category fields. Setting the list to be all category fields,
// unless otherwise specified
if (request.getCategoryFields() == null || request.getCategoryFields().isEmpty()) {
request.setCategoryFields(categoryFieldsFromResponse);
} else {
for (String categoryField : request.getCategoryFields()) {
if (!categoryFieldsFromResponse.contains(categoryField)) {
throw new IllegalArgumentException(
String
.format(
Locale.ROOT,
"Category field %s doesn't exist for detector ID %s",
categoryField,
request.getDetectorId()
)
);
}
}
}
// Validating historical tasks if historical is true. Setting the ID to the latest historical task's
// ID, unless otherwise specified
if (request.getHistorical() == true) {
ADTask historicalTask = getAdResponse.getHistoricalAdTask();
if (historicalTask == null) {
throw new ResourceNotFoundException(
String.format(Locale.ROOT, "No historical tasks found for detector ID %s", request.getDetectorId())
);
}
if (Strings.isNullOrEmpty(request.getTaskId())) {
request.setTaskId(historicalTask.getTaskId());
}
}
// Validating the order. If nothing passed use default
OrderType orderType;
String orderString = request.getOrder();
if (Strings.isNullOrEmpty(orderString)) {
orderType = DEFAULT_ORDER_TYPE;
} else {
if (orderString.equals(OrderType.SEVERITY.getName())) {
orderType = OrderType.SEVERITY;
} else if (orderString.equals(OrderType.OCCURRENCE.getName())) {
orderType = OrderType.OCCURRENCE;
} else {
// No valid order type was passed, throw an error
throw new IllegalArgumentException(String.format(Locale.ROOT, "Ordering by %s is not a valid option", orderString));
}
}
request.setOrder(orderType.getName());
// Validating the size. If nothing passed use default
if (request.getSize() == null) {
request.setSize(DEFAULT_SIZE);
} else if (request.getSize() > MAX_SIZE) {
throw new IllegalArgumentException("Size cannot exceed " + MAX_SIZE);
} else if (request.getSize() <= 0) {
throw new IllegalArgumentException("Size must be a positive integer");
}
// Generating the search request which will contain the generated query
SearchRequest searchRequest = generateSearchRequest(request);
// Adding search over any custom result indices
String rawCustomResultIndex = getAdResponse.getDetector().getResultIndex();
String customResultIndex = rawCustomResultIndex == null ? null : rawCustomResultIndex.trim();
if (!Strings.isNullOrEmpty(customResultIndex)) {
searchRequest.indices(defaultIndex, customResultIndex);
}
// Utilizing the existing search() from SearchHandler to handle security permissions. Both user role
// and backend role filtering is handled in there, and any error will be propagated up and
// returned as a failure in this Listener.
// This same method is used for security handling for the search results action. Since this action
// is doing fundamentally the same thing, we can reuse the security logic here.
searchHandler
.search(
searchRequest,
new TopAnomalyResultListener(
listener,
searchRequest.source(),
clock.millis() + TOP_ANOMALY_RESULT_TIMEOUT_IN_MILLIS,
request.getSize(),
orderType,
customResultIndex
)
);
}, exception -> {
logger.error("Failed to get top anomaly results", exception);
listener.onFailure(exception);
}));
}