Search in sources :

Example 1 with ADValidationException

use of org.opensearch.ad.common.exception.ADValidationException in project anomaly-detection by opensearch-project.

the class AbstractAnomalyDetectorActionHandler method onSearchSingleEntityAdResponse.

protected void onSearchSingleEntityAdResponse(SearchResponse response, boolean indexingDryRun) throws IOException {
    if (response.getHits().getTotalHits().value >= maxSingleEntityAnomalyDetectors) {
        String errorMsgSingleEntity = String.format(Locale.ROOT, EXCEEDED_MAX_SINGLE_ENTITY_DETECTORS_PREFIX_MSG, maxSingleEntityAnomalyDetectors);
        logger.error(errorMsgSingleEntity);
        if (indexingDryRun) {
            listener.onFailure(new ADValidationException(errorMsgSingleEntity, DetectorValidationIssueType.GENERAL_SETTINGS, ValidationAspect.DETECTOR));
            return;
        }
        listener.onFailure(new IllegalArgumentException(errorMsgSingleEntity));
    } else {
        searchAdInputIndices(null, indexingDryRun);
    }
}
Also used : ADValidationException(org.opensearch.ad.common.exception.ADValidationException)

Example 2 with ADValidationException

use of org.opensearch.ad.common.exception.ADValidationException in project anomaly-detection by opensearch-project.

the class AbstractAnomalyDetectorActionHandler method validateAnomalyDetectorFeatures.

/**
 * Validate config/syntax, and runtime error of detector features
 * @param detectorId detector id
 * @param indexingDryRun if false, then will eventually index detector; true, skip indexing detector
 * @throws IOException when fail to parse feature aggregation
 */
// TODO: move this method to util class so that it can be re-usable for more use cases
// https://github.com/opensearch-project/anomaly-detection/issues/39
protected void validateAnomalyDetectorFeatures(String detectorId, boolean indexingDryRun) throws IOException {
    if (anomalyDetector != null && (anomalyDetector.getFeatureAttributes() == null || anomalyDetector.getFeatureAttributes().isEmpty())) {
        checkADNameExists(detectorId, indexingDryRun);
        return;
    }
    // checking configuration/syntax error of detector features
    String error = RestHandlerUtils.checkAnomalyDetectorFeaturesSyntax(anomalyDetector, maxAnomalyFeatures);
    if (StringUtils.isNotBlank(error)) {
        if (indexingDryRun) {
            listener.onFailure(new ADValidationException(error, DetectorValidationIssueType.FEATURE_ATTRIBUTES, ValidationAspect.DETECTOR));
            return;
        }
        listener.onFailure(new OpenSearchStatusException(error, RestStatus.BAD_REQUEST));
        return;
    }
    // checking runtime error from feature query
    ActionListener<MergeableList<Optional<double[]>>> validateFeatureQueriesListener = ActionListener.wrap(response -> {
        checkADNameExists(detectorId, indexingDryRun);
    }, exception -> {
        listener.onFailure(new ADValidationException(exception.getMessage(), DetectorValidationIssueType.FEATURE_ATTRIBUTES, ValidationAspect.DETECTOR));
    });
    MultiResponsesDelegateActionListener<MergeableList<Optional<double[]>>> multiFeatureQueriesResponseListener = new MultiResponsesDelegateActionListener<MergeableList<Optional<double[]>>>(validateFeatureQueriesListener, anomalyDetector.getFeatureAttributes().size(), String.format(Locale.ROOT, CommonErrorMessages.VALIDATION_FEATURE_FAILURE, anomalyDetector.getName()), false);
    for (Feature feature : anomalyDetector.getFeatureAttributes()) {
        SearchSourceBuilder ssb = new SearchSourceBuilder().size(1).query(QueryBuilders.matchAllQuery());
        AggregatorFactories.Builder internalAgg = parseAggregators(feature.getAggregation().toString(), xContentRegistry, feature.getId());
        ssb.aggregation(internalAgg.getAggregatorFactories().iterator().next());
        SearchRequest searchRequest = new SearchRequest().indices(anomalyDetector.getIndices().toArray(new String[0])).source(ssb);
        client.search(searchRequest, ActionListener.wrap(response -> {
            Optional<double[]> aggFeatureResult = searchFeatureDao.parseResponse(response, Arrays.asList(feature.getId()));
            if (aggFeatureResult.isPresent()) {
                multiFeatureQueriesResponseListener.onResponse(new MergeableList<Optional<double[]>>(new ArrayList<Optional<double[]>>(Arrays.asList(aggFeatureResult))));
            } else {
                String errorMessage = CommonErrorMessages.FEATURE_WITH_EMPTY_DATA_MSG + feature.getName();
                logger.error(errorMessage);
                multiFeatureQueriesResponseListener.onFailure(new OpenSearchStatusException(errorMessage, RestStatus.BAD_REQUEST));
            }
        }, e -> {
            String errorMessage;
            if (isExceptionCausedByInvalidQuery(e)) {
                errorMessage = CommonErrorMessages.FEATURE_WITH_INVALID_QUERY_MSG + feature.getName();
            } else {
                errorMessage = CommonErrorMessages.UNKNOWN_SEARCH_QUERY_EXCEPTION_MSG + feature.getName();
            }
            logger.error(errorMessage, e);
            multiFeatureQueriesResponseListener.onFailure(new OpenSearchStatusException(errorMessage, RestStatus.BAD_REQUEST, e));
        }));
    }
}
Also used : Arrays(java.util.Arrays) StringUtils(org.apache.commons.lang.StringUtils) ParseUtils.listEqualsWithoutConsideringOrder(org.opensearch.ad.util.ParseUtils.listEqualsWithoutConsideringOrder) IndexResponse(org.opensearch.action.index.IndexResponse) OpenSearchStatusException(org.opensearch.OpenSearchStatusException) FAIL_TO_FIND_DETECTOR_MSG(org.opensearch.ad.constant.CommonErrorMessages.FAIL_TO_FIND_DETECTOR_MSG) ThreadContext(org.opensearch.common.util.concurrent.ThreadContext) XContentParser(org.opensearch.common.xcontent.XContentParser) WriteRequest(org.opensearch.action.support.WriteRequest) Locale(java.util.Locale) Map(java.util.Map) ParseUtils.parseAggregators(org.opensearch.ad.util.ParseUtils.parseAggregators) XContentFactory(org.opensearch.common.xcontent.XContentFactory) ActionListener(org.opensearch.action.ActionListener) ActionResponse(org.opensearch.action.ActionResponse) GetResponse(org.opensearch.action.get.GetResponse) Client(org.opensearch.client.Client) NumericSetting(org.opensearch.ad.settings.NumericSetting) TimeValue(org.opensearch.common.unit.TimeValue) Feature(org.opensearch.ad.model.Feature) Set(java.util.Set) XContentParserUtils.ensureExpectedToken(org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken) GetFieldMappingsRequest(org.opensearch.action.admin.indices.mapping.get.GetFieldMappingsRequest) ADTaskManager(org.opensearch.ad.task.ADTaskManager) Instant(java.time.Instant) RestStatus(org.opensearch.rest.RestStatus) Collectors(java.util.stream.Collectors) TransportService(org.opensearch.transport.TransportService) Sets(com.google.common.collect.Sets) Objects(java.util.Objects) GetFieldMappingsAction(org.opensearch.action.admin.indices.mapping.get.GetFieldMappingsAction) MultiResponsesDelegateActionListener(org.opensearch.ad.util.MultiResponsesDelegateActionListener) List(java.util.List) Logger(org.apache.logging.log4j.Logger) QueryBuilder(org.opensearch.index.query.QueryBuilder) GetFieldMappingsResponse(org.opensearch.action.admin.indices.mapping.get.GetFieldMappingsResponse) SearchSourceBuilder(org.opensearch.search.builder.SearchSourceBuilder) SearchFeatureDao(org.opensearch.ad.feature.SearchFeatureDao) Optional(java.util.Optional) ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse) RestHandlerUtils(org.opensearch.ad.util.RestHandlerUtils) BoolQueryBuilder(org.opensearch.index.query.BoolQueryBuilder) AggregatorFactories(org.opensearch.search.aggregations.AggregatorFactories) IndicesOptions(org.opensearch.action.support.IndicesOptions) ArrayList(java.util.ArrayList) XCONTENT_WITH_TYPE(org.opensearch.ad.util.RestHandlerUtils.XCONTENT_WITH_TYPE) HashSet(java.util.HashSet) IndexAnomalyDetectorResponse(org.opensearch.ad.transport.IndexAnomalyDetectorResponse) AnomalyDetector(org.opensearch.ad.model.AnomalyDetector) SearchRequest(org.opensearch.action.search.SearchRequest) SearchResponse(org.opensearch.action.search.SearchResponse) MergeableList(org.opensearch.ad.model.MergeableList) RestHandlerUtils.isExceptionCausedByInvalidQuery(org.opensearch.ad.util.RestHandlerUtils.isExceptionCausedByInvalidQuery) ValidationAspect(org.opensearch.ad.model.ValidationAspect) ValidateAnomalyDetectorResponse(org.opensearch.ad.transport.ValidateAnomalyDetectorResponse) HISTORICAL_DETECTOR_TASK_TYPES(org.opensearch.ad.model.ADTaskType.HISTORICAL_DETECTOR_TASK_TYPES) QueryBuilders(org.opensearch.index.query.QueryBuilders) RestValidateAnomalyDetectorAction(org.opensearch.ad.rest.RestValidateAnomalyDetectorAction) CommonName(org.opensearch.ad.constant.CommonName) ADValidationException(org.opensearch.ad.common.exception.ADValidationException) RestRequest(org.opensearch.rest.RestRequest) ANOMALY_DETECTORS_INDEX(org.opensearch.ad.model.AnomalyDetector.ANOMALY_DETECTORS_INDEX) GetRequest(org.opensearch.action.get.GetRequest) IOException(java.io.IOException) AnomalyDetectionIndices(org.opensearch.ad.indices.AnomalyDetectionIndices) CreateIndexResponse(org.opensearch.action.admin.indices.create.CreateIndexResponse) CommonErrorMessages(org.opensearch.ad.constant.CommonErrorMessages) User(org.opensearch.commons.authuser.User) DetectorValidationIssueType(org.opensearch.ad.model.DetectorValidationIssueType) NamedXContentRegistry(org.opensearch.common.xcontent.NamedXContentRegistry) ClusterService(org.opensearch.cluster.service.ClusterService) Clock(java.time.Clock) IndexRequest(org.opensearch.action.index.IndexRequest) LogManager(org.apache.logging.log4j.LogManager) SearchRequest(org.opensearch.action.search.SearchRequest) Optional(java.util.Optional) MergeableList(org.opensearch.ad.model.MergeableList) MultiResponsesDelegateActionListener(org.opensearch.ad.util.MultiResponsesDelegateActionListener) Feature(org.opensearch.ad.model.Feature) SearchSourceBuilder(org.opensearch.search.builder.SearchSourceBuilder) AggregatorFactories(org.opensearch.search.aggregations.AggregatorFactories) ADValidationException(org.opensearch.ad.common.exception.ADValidationException) OpenSearchStatusException(org.opensearch.OpenSearchStatusException)

Example 3 with ADValidationException

use of org.opensearch.ad.common.exception.ADValidationException in project anomaly-detection by opensearch-project.

the class ModelValidationActionHandler method processTopEntityResults.

private void processTopEntityResults(SearchResponse response, long latestTime) {
    Histogram aggregate = checkBucketResultErrors(response);
    if (aggregate == null) {
        return;
    }
    double fullBucketRate = processBucketAggregationResults(aggregate);
    if (fullBucketRate < CONFIG_BUCKET_MINIMUM_SUCCESS_RATE) {
        listener.onFailure(new ADValidationException(CommonErrorMessages.CATEGORY_FIELD_TOO_SPARSE, DetectorValidationIssueType.CATEGORY, ValidationAspect.MODEL));
    } else {
        try {
            checkFeatureQueryDelegate(latestTime);
        } catch (Exception ex) {
            logger.error(ex);
            listener.onFailure(ex);
        }
    }
}
Also used : Histogram(org.opensearch.search.aggregations.bucket.histogram.Histogram) ADValidationException(org.opensearch.ad.common.exception.ADValidationException) OpenSearchStatusException(org.opensearch.OpenSearchStatusException) EndRunException(org.opensearch.ad.common.exception.EndRunException) ADValidationException(org.opensearch.ad.common.exception.ADValidationException) IOException(java.io.IOException)

Example 4 with ADValidationException

use of org.opensearch.ad.common.exception.ADValidationException in project anomaly-detection by opensearch-project.

the class AbstractAnomalyDetectorActionHandler method onSearchAdInputIndicesResponse.

protected void onSearchAdInputIndicesResponse(SearchResponse response, String detectorId, boolean indexingDryRun) throws IOException {
    if (response.getHits().getTotalHits().value == 0) {
        String errorMsg = NO_DOCS_IN_USER_INDEX_MSG + Arrays.toString(anomalyDetector.getIndices().toArray(new String[0]));
        logger.error(errorMsg);
        if (indexingDryRun) {
            listener.onFailure(new ADValidationException(errorMsg, DetectorValidationIssueType.INDICES, ValidationAspect.DETECTOR));
            return;
        }
        listener.onFailure(new IllegalArgumentException(errorMsg));
    } else {
        validateAnomalyDetectorFeatures(detectorId, indexingDryRun);
    }
}
Also used : ADValidationException(org.opensearch.ad.common.exception.ADValidationException)

Example 5 with ADValidationException

use of org.opensearch.ad.common.exception.ADValidationException in project anomaly-detection by opensearch-project.

the class AbstractAnomalyDetectorActionHandler method validateCategoricalField.

@SuppressWarnings("unchecked")
protected void validateCategoricalField(String detectorId, boolean indexingDryRun) {
    List<String> categoryField = anomalyDetector.getCategoryField();
    if (categoryField == null) {
        searchAdInputIndices(detectorId, indexingDryRun);
        return;
    }
    // we only support a certain number of categorical field
    // If there is more fields than required, AnomalyDetector's constructor
    // throws ADValidationException before reaching this line
    int maxCategoryFields = NumericSetting.maxCategoricalFields();
    if (categoryField.size() > maxCategoryFields) {
        listener.onFailure(new ADValidationException(CommonErrorMessages.getTooManyCategoricalFieldErr(maxCategoryFields), DetectorValidationIssueType.CATEGORY, ValidationAspect.DETECTOR));
        return;
    }
    String categoryField0 = categoryField.get(0);
    GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest();
    getMappingsRequest.indices(anomalyDetector.getIndices().toArray(new String[0])).fields(categoryField.toArray(new String[0]));
    getMappingsRequest.indicesOptions(IndicesOptions.strictExpand());
    ActionListener<GetFieldMappingsResponse> mappingsListener = ActionListener.wrap(getMappingsResponse -> {
        // example getMappingsResponse:
        // GetFieldMappingsResponse{mappings={server-metrics={_doc={service=FieldMappingMetadata{fullName='service',
        // source=org.opensearch.common.bytes.BytesArray@7ba87dbd}}}}}
        // for nested field, it would be
        // GetFieldMappingsResponse{mappings={server-metrics={_doc={host_nest.host2=FieldMappingMetadata{fullName='host_nest.host2',
        // source=org.opensearch.common.bytes.BytesArray@8fb4de08}}}}}
        boolean foundField = false;
        // Review why the change from FieldMappingMetadata to GetFieldMappingsResponse.FieldMappingMetadata
        Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetadata>>> mappingsByIndex = getMappingsResponse.mappings();
        for (Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetadata>> mappingsByType : mappingsByIndex.values()) {
            for (Map<String, GetFieldMappingsResponse.FieldMappingMetadata> mappingsByField : mappingsByType.values()) {
                for (Map.Entry<String, GetFieldMappingsResponse.FieldMappingMetadata> field2Metadata : mappingsByField.entrySet()) {
                    // example output:
                    // host_nest.host2=FieldMappingMetadata{fullName='host_nest.host2',
                    // source=org.opensearch.common.bytes.BytesArray@8fb4de08}
                    // Review why the change from FieldMappingMetadata to GetFieldMappingsResponse.FieldMappingMetadata
                    GetFieldMappingsResponse.FieldMappingMetadata fieldMetadata = field2Metadata.getValue();
                    if (fieldMetadata != null) {
                        // sourceAsMap returns sth like {host2={type=keyword}} with host2 being a nested field
                        Map<String, Object> fieldMap = fieldMetadata.sourceAsMap();
                        if (fieldMap != null) {
                            for (Object type : fieldMap.values()) {
                                if (type != null && type instanceof Map) {
                                    foundField = true;
                                    Map<String, Object> metadataMap = (Map<String, Object>) type;
                                    String typeName = (String) metadataMap.get(CommonName.TYPE);
                                    if (!typeName.equals(CommonName.KEYWORD_TYPE) && !typeName.equals(CommonName.IP_TYPE)) {
                                        listener.onFailure(new ADValidationException(CATEGORICAL_FIELD_TYPE_ERR_MSG, DetectorValidationIssueType.CATEGORY, ValidationAspect.DETECTOR));
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (foundField == false) {
            listener.onFailure(new ADValidationException(String.format(Locale.ROOT, CATEGORY_NOT_FOUND_ERR_MSG, categoryField0), DetectorValidationIssueType.CATEGORY, ValidationAspect.DETECTOR));
            return;
        }
        searchAdInputIndices(detectorId, indexingDryRun);
    }, error -> {
        String message = String.format(Locale.ROOT, "Fail to get the index mapping of %s", anomalyDetector.getIndices());
        logger.error(message, error);
        listener.onFailure(new IllegalArgumentException(message));
    });
    client.execute(GetFieldMappingsAction.INSTANCE, getMappingsRequest, mappingsListener);
}
Also used : GetFieldMappingsRequest(org.opensearch.action.admin.indices.mapping.get.GetFieldMappingsRequest) GetFieldMappingsResponse(org.opensearch.action.admin.indices.mapping.get.GetFieldMappingsResponse) ADValidationException(org.opensearch.ad.common.exception.ADValidationException) Map(java.util.Map)

Aggregations

ADValidationException (org.opensearch.ad.common.exception.ADValidationException)22 IOException (java.io.IOException)8 AnomalyDetector (org.opensearch.ad.model.AnomalyDetector)7 Map (java.util.Map)6 List (java.util.List)4 Locale (java.util.Locale)4 OpenSearchStatusException (org.opensearch.OpenSearchStatusException)4 SearchRequest (org.opensearch.action.search.SearchRequest)4 SearchResponse (org.opensearch.action.search.SearchResponse)4 CommonErrorMessages (org.opensearch.ad.constant.CommonErrorMessages)4 ValidationAspect (org.opensearch.ad.model.ValidationAspect)4 ValidateAnomalyDetectorActionHandler (org.opensearch.ad.rest.handler.ValidateAnomalyDetectorActionHandler)4 ClusterService (org.opensearch.cluster.service.ClusterService)4 Histogram (org.opensearch.search.aggregations.bucket.histogram.Histogram)4 SearchSourceBuilder (org.opensearch.search.builder.SearchSourceBuilder)4 Clock (java.time.Clock)3 Instant (java.time.Instant)3 ArrayList (java.util.ArrayList)3 Collectors (java.util.stream.Collectors)3 LogManager (org.apache.logging.log4j.LogManager)3