From 37725f640c9563f606995db9f862ff599df781ad Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Mon, 4 Jul 2016 09:25:46 +0200 Subject: [PATCH] Add missing field type in the FieldStats response. This change adds the type of the field in the fieldstats response. It can be one of the following: * "integer" for byte, short, integer and long * "float" for float, half-float and double * "date" for date * "ip" for ip * "text" for string, keyword and text. Closes #17750 --- .../action/fieldstats/FieldStats.java | 86 +++++++++---------- .../fieldstats/TransportFieldStatsAction.java | 4 +- .../fieldstats/FieldStatsIntegrationIT.java | 19 +++- .../fieldstats/FieldStatsTests.java | 26 +++++- .../test/field_stats/10_basics.yaml | 12 ++- 5 files changed, 98 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/fieldstats/FieldStats.java b/core/src/main/java/org/elasticsearch/action/fieldstats/FieldStats.java index 2c6f2539b97..4a4f106b085 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldstats/FieldStats.java +++ b/core/src/main/java/org/elasticsearch/action/fieldstats/FieldStats.java @@ -68,6 +68,23 @@ public abstract class FieldStats implements Writeable, ToXContent { return this.type; } + public String getDisplayType() { + switch (type) { + case 0: + return "integer"; + case 1: + return "float"; + case 2: + return "date"; + case 3: + return "string"; + case 4: + return "ip"; + default: + throw new IllegalArgumentException("Unknown type."); + } + } + /** * @return the total number of documents. * @@ -220,23 +237,24 @@ public abstract class FieldStats implements Writeable, ToXContent { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(Fields.MAX_DOC, maxDoc); - builder.field(Fields.DOC_COUNT, docCount); - builder.field(Fields.DENSITY, getDensity()); - builder.field(Fields.SUM_DOC_FREQ, sumDocFreq); - builder.field(Fields.SUM_TOTAL_TERM_FREQ, sumTotalTermFreq); - builder.field(Fields.SEARCHABLE, isSearchable); - builder.field(Fields.AGGREGATABLE, isAggregatable); + builder.field(TYPE_FIELD, getDisplayType()); + builder.field(MAX_DOC_FIELD, maxDoc); + builder.field(DOC_COUNT_FIELD, docCount); + builder.field(DENSITY_FIELD, getDensity()); + builder.field(SUM_DOC_FREQ_FIELD, sumDocFreq); + builder.field(SUM_TOTAL_TERM_FREQ_FIELD, sumTotalTermFreq); + builder.field(SEARCHABLE_FIELD, isSearchable); + builder.field(AGGREGATABLE_FIELD, isAggregatable); toInnerXContent(builder); builder.endObject(); return builder; } protected void toInnerXContent(XContentBuilder builder) throws IOException { - builder.field(Fields.MIN_VALUE, getMinValue()); - builder.field(Fields.MIN_VALUE_AS_STRING, getMinValueAsString()); - builder.field(Fields.MAX_VALUE, getMaxValue()); - builder.field(Fields.MAX_VALUE_AS_STRING, getMaxValueAsString()); + builder.field(MIN_VALUE_FIELD, getMinValue()); + builder.field(MIN_VALUE_AS_STRING_FIELD, getMinValueAsString()); + builder.field(MAX_VALUE_FIELD, getMaxValue()); + builder.field(MAX_VALUE_AS_STRING_FIELD, getMaxValueAsString()); } @Override @@ -484,8 +502,8 @@ public abstract class FieldStats implements Writeable, ToXContent { @Override protected void toInnerXContent(XContentBuilder builder) throws IOException { - builder.field(Fields.MIN_VALUE, getMinValueAsString()); - builder.field(Fields.MAX_VALUE, getMaxValueAsString()); + builder.field(MIN_VALUE_FIELD, getMinValueAsString()); + builder.field(MAX_VALUE_FIELD, getMaxValueAsString()); } } @@ -598,34 +616,16 @@ public abstract class FieldStats implements Writeable, ToXContent { } } - public static String typeName(byte type) { - switch (type) { - case 0: - return "whole-number"; - case 1: - return "floating-point"; - case 2: - return "date"; - case 3: - return "text"; - case 4: - return "ip"; - default: - throw new IllegalArgumentException("Unknown type."); - } - } - - private static final class Fields { - static final String MAX_DOC = new String("max_doc"); - static final String DOC_COUNT = new String("doc_count"); - static final String DENSITY = new String("density"); - static final String SUM_DOC_FREQ = new String("sum_doc_freq"); - static final String SUM_TOTAL_TERM_FREQ = new String("sum_total_term_freq"); - static final String SEARCHABLE = new String("searchable"); - static final String AGGREGATABLE = new String("aggregatable"); - static final String MIN_VALUE = new String("min_value"); - static final String MIN_VALUE_AS_STRING = new String("min_value_as_string"); - static final String MAX_VALUE = new String("max_value"); - static final String MAX_VALUE_AS_STRING = new String("max_value_as_string"); - } + static final String TYPE_FIELD = new String("type"); + static final String MAX_DOC_FIELD = new String("max_doc"); + static final String DOC_COUNT_FIELD = new String("doc_count"); + static final String DENSITY_FIELD = new String("density"); + static final String SUM_DOC_FREQ_FIELD = new String("sum_doc_freq"); + static final String SUM_TOTAL_TERM_FREQ_FIELD = new String("sum_total_term_freq"); + static final String SEARCHABLE_FIELD = new String("searchable"); + static final String AGGREGATABLE_FIELD = new String("aggregatable"); + static final String MIN_VALUE_FIELD = new String("min_value"); + static final String MIN_VALUE_AS_STRING_FIELD = new String("min_value_as_string"); + static final String MAX_VALUE_FIELD = new String("max_value"); + static final String MAX_VALUE_AS_STRING_FIELD = new String("max_value_as_string"); } diff --git a/core/src/main/java/org/elasticsearch/action/fieldstats/TransportFieldStatsAction.java b/core/src/main/java/org/elasticsearch/action/fieldstats/TransportFieldStatsAction.java index f70e5dda114..e65f6951432 100644 --- a/core/src/main/java/org/elasticsearch/action/fieldstats/TransportFieldStatsAction.java +++ b/core/src/main/java/org/elasticsearch/action/fieldstats/TransportFieldStatsAction.java @@ -116,9 +116,9 @@ public class TransportFieldStatsAction extends Arrays.sort(fields, (o1, o2) -> Byte.compare(o1.getType(), o2.getType())); conflicts.put(entry.getKey(), "Field [" + entry.getKey() + "] of type [" + - FieldStats.typeName(fields[0].getType()) + + fields[0].getDisplayType() + "] conflicts with existing field of type [" + - FieldStats.typeName(fields[1].getType()) + + fields[1].getDisplayType() + "] in other index."); } } else { diff --git a/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsIntegrationIT.java b/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsIntegrationIT.java index e87cc5f6571..6240a13a0bd 100644 --- a/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsIntegrationIT.java +++ b/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsIntegrationIT.java @@ -169,18 +169,25 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getAllFieldStats().get("byte").getMinValue(), equalTo(minByte)); assertThat(response.getAllFieldStats().get("byte").getMaxValue(), equalTo(maxByte)); + assertThat(response.getAllFieldStats().get("byte").getDisplayType(), equalTo("integer")); assertThat(response.getAllFieldStats().get("short").getMinValue(), equalTo(minShort)); assertThat(response.getAllFieldStats().get("short").getMaxValue(), equalTo(maxShort)); + assertThat(response.getAllFieldStats().get("short").getDisplayType(), equalTo("integer")); assertThat(response.getAllFieldStats().get("integer").getMinValue(), equalTo(minInt)); assertThat(response.getAllFieldStats().get("integer").getMaxValue(), equalTo(maxInt)); + assertThat(response.getAllFieldStats().get("integer").getDisplayType(), equalTo("integer")); assertThat(response.getAllFieldStats().get("long").getMinValue(), equalTo(minLong)); assertThat(response.getAllFieldStats().get("long").getMaxValue(), equalTo(maxLong)); + assertThat(response.getAllFieldStats().get("long").getDisplayType(), equalTo("integer")); assertThat(response.getAllFieldStats().get("half_float").getMinValue(), equalTo(minHalfFloat)); assertThat(response.getAllFieldStats().get("half_float").getMaxValue(), equalTo(maxHalfFloat)); + assertThat(response.getAllFieldStats().get("half_float").getDisplayType(), equalTo("float")); assertThat(response.getAllFieldStats().get("float").getMinValue(), equalTo(minFloat)); assertThat(response.getAllFieldStats().get("float").getMaxValue(), equalTo(maxFloat)); + assertThat(response.getAllFieldStats().get("float").getDisplayType(), equalTo("float")); assertThat(response.getAllFieldStats().get("double").getMinValue(), equalTo(minDouble)); assertThat(response.getAllFieldStats().get("double").getMaxValue(), equalTo(maxDouble)); + assertThat(response.getAllFieldStats().get("double").getDisplayType(), equalTo("float")); } public void testFieldStatsIndexLevel() throws Exception { @@ -207,6 +214,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1)); assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(-10L)); assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(300L)); + assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getDisplayType(), + equalTo("integer")); // Level: cluster response = client().prepareFieldStats().setFields("value").setLevel("cluster").get(); @@ -216,6 +225,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1)); assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(-10L)); assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(300L)); + assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getDisplayType(), + equalTo("integer")); // Level: indices response = client().prepareFieldStats().setFields("value").setLevel("indices").get(); @@ -228,6 +239,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(200L)); assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(201L)); assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(300L)); + assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getDisplayType(), + equalTo("integer")); // Illegal level option: try { @@ -259,7 +272,7 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getIndicesMergedFieldStats().get("_all").size(), equalTo(0)); assertThat(response.getConflicts().size(), equalTo(1)); assertThat(response.getConflicts().get("value"), - equalTo("Field [value] of type [whole-number] conflicts with existing field of type [text] " + + equalTo("Field [value] of type [integer] conflicts with existing field of type [string] " + "in other index.")); response = client().prepareFieldStats().setFields("value").setLevel("indices").get(); @@ -296,7 +309,7 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { assertThat(response.getIndicesMergedFieldStats().get("_all").get("value2").getMaxValue(), equalTo(1L)); assertThat(response.getConflicts().size(), equalTo(1)); assertThat(response.getConflicts().get("value"), - equalTo("Field [value] of type [whole-number] conflicts with existing field of type [text] " + + equalTo("Field [value] of type [integer] conflicts with existing field of type [string] " + "in other index.")); response = client().prepareFieldStats().setFields("value", "value2").setLevel("indices").get(); @@ -310,6 +323,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase { equalTo(new BytesRef("a"))); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(new BytesRef("b"))); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("string")); } public void testFieldStatsFiltering() throws Exception { diff --git a/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsTests.java b/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsTests.java index 20db1bf20c4..bfee11f7f0e 100644 --- a/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsTests.java +++ b/core/src/test/java/org/elasticsearch/fieldstats/FieldStatsTests.java @@ -89,6 +89,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(String.format(Locale.ENGLISH, "%03d", 0))); assertThat(result.getAllFieldStats().get("field").getMaxValueAsString(), equalTo(String.format(Locale.ENGLISH, "%03d", 10))); + assertThat(result.getAllFieldStats().get("field").getDisplayType(), + equalTo("string")); } public void testDouble() { @@ -106,6 +108,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(-1d)); assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(9d)); assertThat(result.getAllFieldStats().get(fieldName).getMinValueAsString(), equalTo(Double.toString(-1))); + assertThat(result.getAllFieldStats().get(fieldName).getDisplayType(), equalTo("float")); } public void testHalfFloat() { @@ -124,6 +127,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(9d)); assertThat(result.getAllFieldStats().get(fieldName).getMinValueAsString(), equalTo(Float.toString(-1))); assertThat(result.getAllFieldStats().get(fieldName).getMaxValueAsString(), equalTo(Float.toString(9))); + assertThat(result.getAllFieldStats().get(fieldName).getDisplayType(), equalTo("float")); } public void testFloat() { @@ -169,6 +173,11 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(java.lang.Long.toString(max))); assertThat(result.getAllFieldStats().get(fieldName).isSearchable(), equalTo(true)); assertThat(result.getAllFieldStats().get(fieldName).isAggregatable(), equalTo(true)); + if (fieldType.equals("float") || fieldType.equals("double") || fieldType.equals("half-float")) { + assertThat(result.getAllFieldStats().get(fieldName).getDisplayType(), equalTo("float")); + } else { + assertThat(result.getAllFieldStats().get(fieldName).getDisplayType(), equalTo("integer")); + } client().admin().indices().prepareDelete("test").get(); client().admin().indices().prepareDelete("test1").get(); @@ -191,6 +200,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(stat.getSumTotalTermFreq(), equalTo(4L)); assertThat(stat.isSearchable(), equalTo(true)); assertThat(stat.isAggregatable(), equalTo(false)); + assertThat(stat.getDisplayType(), equalTo("integer")); } public void testMerge_notAvailable() { @@ -209,6 +219,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(stat.getSumTotalTermFreq(), equalTo(-1L)); assertThat(stat.isSearchable(), equalTo(true)); assertThat(stat.isAggregatable(), equalTo(true)); + assertThat(stat.getDisplayType(), equalTo("integer")); stats.add(new FieldStats.Long(1, -1L, -1L, -1L, true, true, 1L, 1L)); stat = stats.remove(0); @@ -221,6 +232,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(stat.getSumTotalTermFreq(), equalTo(-1L)); assertThat(stat.isSearchable(), equalTo(true)); assertThat(stat.isAggregatable(), equalTo(true)); + assertThat(stat.getDisplayType(), equalTo("integer")); } public void testNumberFiltering() { @@ -350,6 +362,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(dateTime1Str)); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str)); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("date")); response = client().prepareFieldStats() .setFields("value") @@ -370,6 +384,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(dateTime1.getMillis())); assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValueAsString(), equalTo(dateTime1Str)); + assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getDisplayType(), + equalTo("date")); response = client().prepareFieldStats() .setFields("value") @@ -402,6 +418,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(dateTime2.getMillis())); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str)); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("date")); response = client().prepareFieldStats() .setFields("value") @@ -417,6 +435,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(dateTime1Str)); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str)); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("date")); response = client().prepareFieldStats() .setFields("value") @@ -432,6 +452,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { equalTo(dateTime1Str)); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str)); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("date")); } public void testDateFiltering_optionalFormat() { @@ -453,6 +475,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase { assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1)); assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo("2014-01-02T00:00:00.000Z")); + assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getDisplayType(), + equalTo("date")); try { client().prepareFieldStats() @@ -487,6 +511,6 @@ public class FieldStatsTests extends ESSingleNodeTestCase { .get(); assertThat(response.getAllFieldStats().size(), equalTo(1)); assertThat(response.getAllFieldStats().get("_type").isSearchable(), equalTo(true)); - // assertThat(response.getAllFieldStats().get("_type").isAggregatable(), equalTo(true)); + assertThat(response.getAllFieldStats().get("_type").isAggregatable(), equalTo(true)); } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/field_stats/10_basics.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/field_stats/10_basics.yaml index eb1d1c6f758..35cc19224ec 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/field_stats/10_basics.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/field_stats/10_basics.yaml @@ -54,6 +54,7 @@ setup: - match: { indices._all.fields.foo.doc_count: 2 } - match: { indices._all.fields.foo.min_value: "babar" } - match: { indices._all.fields.foo.max_value: "bar" } + - match: { indices._all.fields.foo.type: "string" } - is_false: indices._all.fields.foo.min_value_as_string - is_false: indices._all.fields.foo.max_value_as_string - match: { indices._all.fields.foo.searchable: true } @@ -66,6 +67,7 @@ setup: - match: { indices._all.fields.number.min_value_as_string: "123" } - match: { indices._all.fields.number.max_value: 456 } - match: { indices._all.fields.number.max_value_as_string: "456" } + - match: { indices._all.fields.number.type: "integer" } - is_false: conflicts --- @@ -83,6 +85,7 @@ setup: - is_false: indices.test_1.fields.foo.max_value_as_string - match: { indices.test_1.fields.foo.searchable: true } - match: { indices.test_1.fields.foo.aggregatable: false } + - match: { indices.test_1.fields.foo.type: "string" } - match: { indices.test_1.fields.number.max_doc: 1 } - match: { indices.test_1.fields.number.doc_count: 1 } - match: { indices.test_1.fields.number.searchable: true } @@ -91,14 +94,17 @@ setup: - match: { indices.test_1.fields.number.min_value_as_string: "123" } - match: { indices.test_1.fields.number.max_value: 123 } - match: { indices.test_1.fields.number.max_value_as_string: "123" } + - match: { indices.test_1.fields.number.type: "integer" } - match: { indices.test_2.fields.foo.max_doc: 1 } - match: { indices.test_2.fields.foo.doc_count: 1 } - match: { indices.test_2.fields.foo.min_value: "babar" } - match: { indices.test_2.fields.foo.max_value: "babar" } + - match: { indices.test_2.fields.foo.type: "string" } - is_false: indices.test_2.fields.foo.min_value_as_string - is_false: indices.test_2.fields.foo.max_value_as_string - match: { indices.test_2.fields.foo.searchable: true } - match: { indices.test_2.fields.foo.aggregatable: false } + - match: { indices.test_2.fields.foo.type: "string" } - match: { indices.test_2.fields.number.max_doc: 1 } - match: { indices.test_2.fields.number.doc_count: 1 } - match: { indices.test_2.fields.number.searchable: true } @@ -107,6 +113,7 @@ setup: - match: { indices.test_2.fields.number.min_value_as_string: "456" } - match: { indices.test_2.fields.number.max_value: 456 } - match: { indices.test_2.fields.number.max_value_as_string: "456" } + - match: { indices.test_2.fields.number.type: "integer" } - is_false: conflicts --- @@ -124,6 +131,7 @@ setup: - match: { indices.test_1.fields.foo.aggregatable: false } - match: { indices.test_1.fields.foo.min_value: "bar" } - match: { indices.test_1.fields.foo.max_value: "bar" } + - match: { indices.test_1.fields.foo.type: "string" } - is_false: indices.test_1.fields.number - is_false: conflicts @@ -156,6 +164,7 @@ setup: - match: { indices._all.fields.foo.max_value: "bar" } - match: { indices._all.fields.foo.searchable: true } - match: { indices._all.fields.foo.aggregatable: false } + - match: { indices._all.fields.foo.type: "string" } - match: { indices._all.fields.number.max_doc: 2 } - match: { indices._all.fields.number.doc_count: 2 } - match: { indices._all.fields.number.searchable: true } @@ -164,5 +173,6 @@ setup: - match: { indices._all.fields.number.min_value_as_string: "123" } - match: { indices._all.fields.number.max_value: 456 } - match: { indices._all.fields.number.max_value_as_string: "456" } - - match: { conflicts.bar: "Field [bar] of type [whole-number] conflicts with existing field of type [text] in other index." } + - match: { indices._all.fields.number.type: "integer" } + - match: { conflicts.bar: "Field [bar] of type [integer] conflicts with existing field of type [string] in other index." } - is_false: indices._all.fields.bar