From 6c1700c343b92556b46ffad2f827e236114c1025 Mon Sep 17 00:00:00 2001 From: Dimitris Athanasiou Date: Wed, 9 Sep 2020 12:41:26 +0300 Subject: [PATCH] [7.x][ML] Outlier detection mapping for nested feature influence (#62068) (#62150) Adds mappings for outlier detection results. Backport of #62068 --- .../dataframe/analyses/OutlierDetection.java | 23 ++++++++++++++++++- .../analyses/OutlierDetectionTests.java | 12 ++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java index 03451c23085ef..132914eb17102 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java @@ -13,6 +13,9 @@ import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.KeywordFieldMapper; +import org.elasticsearch.index.mapper.NumberFieldMapper; +import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.xpack.core.ml.inference.trainedmodel.InferenceConfig; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; @@ -56,6 +59,20 @@ public static OutlierDetection fromXContent(XContentParser parser, boolean ignor private static final List PROGRESS_PHASES = Collections.singletonList("computing_outliers"); + static final Map FEATURE_INFLUENCE_MAPPING; + static { + Map properties = new HashMap<>(); + properties.put("feature_name", Collections.singletonMap("type", KeywordFieldMapper.CONTENT_TYPE)); + properties.put("influence", Collections.singletonMap("type", NumberFieldMapper.NumberType.DOUBLE.typeName())); + + Map mapping = new HashMap<>(); + mapping.put("dynamic", false); + mapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + mapping.put("properties", properties); + + FEATURE_INFLUENCE_MAPPING = Collections.unmodifiableMap(mapping); + } + /** * The number of neighbors. Leave unspecified for dynamic detection. */ @@ -229,7 +246,11 @@ public List getFieldCardinalityConstraints() { @Override public Map getExplicitlyMappedFields(Map mappingsProperties, String resultsFieldName) { - return Collections.emptyMap(); + Map additionalProperties = new HashMap<>(); + additionalProperties.put(resultsFieldName + ".outlier_score", + Collections.singletonMap("type", NumberFieldMapper.NumberType.DOUBLE.typeName())); + additionalProperties.put(resultsFieldName + ".feature_influence", FEATURE_INFLUENCE_MAPPING); + return additionalProperties; } @Override diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetectionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetectionTests.java index 3ead1958fdfe5..469e8f17dcbc3 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetectionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetectionTests.java @@ -8,15 +8,17 @@ import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import java.io.IOException; +import java.util.Collections; import java.util.Map; -import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; @@ -106,7 +108,13 @@ public void testFieldCardinalityLimitsIsEmpty() { } public void testGetExplicitlyMappedFields() { - assertThat(createTestInstance().getExplicitlyMappedFields(null, null), is(anEmptyMap())); + Map mappedFields = createTestInstance().getExplicitlyMappedFields(null, "test"); + assertThat(mappedFields.size(), equalTo(2)); + assertThat(mappedFields, hasKey("test.outlier_score")); + assertThat(mappedFields.get("test.outlier_score"), + equalTo(Collections.singletonMap("type", NumberFieldMapper.NumberType.DOUBLE.typeName()))); + assertThat(mappedFields, hasKey("test.feature_influence")); + assertThat(mappedFields.get("test.feature_influence"), equalTo(OutlierDetection.FEATURE_INFLUENCE_MAPPING)); } public void testGetStateDocId() {