Browse Source

field stats: Added `min_value_as_string` and `max_value_as_string` response elements for all number based fields. The existing `min_value` and `max_value` will return the values as numbers instead.

Closes #14404
Martijn van Groningen 10 years ago
parent
commit
48771f1a76

+ 38 - 22
core/src/main/java/org/elasticsearch/action/fieldstats/FieldStats.java

@@ -106,19 +106,37 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         return sumTotalTermFreq;
     }
 
+    /**
+     * @return the lowest value in the field.
+     *
+     * Note that, documents marked as deleted that haven't yet been merged way aren't taken into account.
+     */
+    public T getMinValue() {
+        return minValue;
+    }
+
+    /**
+     * @return the highest value in the field.
+     *
+     * Note that, documents marked as deleted that haven't yet been merged way aren't taken into account.
+     */
+    public T getMaxValue() {
+        return maxValue;
+    }
+
     /**
      * @return the lowest value in the field represented as a string.
      *
      * Note that, documents marked as deleted that haven't yet been merged way aren't taken into account.
      */
-    public abstract String getMinValue();
+    public abstract String getMinValueAsString();
 
     /**
      * @return the highest value in the field represented as a string.
      *
      * Note that, documents marked as deleted that haven't yet been merged way aren't taken into account.
      */
-    public abstract String getMaxValue();
+    public abstract String getMaxValueAsString();
 
     /**
      * @param value The string to be parsed
@@ -192,8 +210,10 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
     }
 
     protected void toInnerXContent(XContentBuilder builder) throws IOException {
-        builder.field(Fields.MIN_VALUE, minValue);
-        builder.field(Fields.MAX_VALUE, maxValue);
+        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());
     }
 
     @Override
@@ -229,12 +249,12 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         }
 
         @Override
-        public String getMinValue() {
+        public String getMinValueAsString() {
             return String.valueOf(minValue.longValue());
         }
 
         @Override
-        public String getMaxValue() {
+        public String getMaxValueAsString() {
             return String.valueOf(maxValue.longValue());
         }
 
@@ -282,12 +302,12 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         }
 
         @Override
-        public String getMinValue() {
+        public String getMinValueAsString() {
             return String.valueOf(minValue.floatValue());
         }
 
         @Override
-        public String getMaxValue() {
+        public String getMaxValueAsString() {
             return String.valueOf(maxValue.floatValue());
         }
 
@@ -335,12 +355,12 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         }
 
         @Override
-        public String getMinValue() {
+        public String getMinValueAsString() {
             return String.valueOf(minValue.doubleValue());
         }
 
         @Override
-        public String getMaxValue() {
+        public String getMaxValueAsString() {
             return String.valueOf(maxValue.doubleValue());
         }
 
@@ -388,12 +408,12 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         }
 
         @Override
-        public String getMinValue() {
+        public String getMinValueAsString() {
             return minValue.utf8ToString();
         }
 
         @Override
-        public String getMaxValue() {
+        public String getMaxValueAsString() {
             return maxValue.utf8ToString();
         }
 
@@ -419,8 +439,8 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
 
         @Override
         protected void toInnerXContent(XContentBuilder builder) throws IOException {
-            builder.field(Fields.MIN_VALUE, getMinValue());
-            builder.field(Fields.MAX_VALUE, getMaxValue());
+            builder.field(Fields.MIN_VALUE, getMinValueAsString());
+            builder.field(Fields.MAX_VALUE, getMaxValueAsString());
         }
 
         @Override
@@ -452,12 +472,12 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         }
 
         @Override
-        public String getMinValue() {
+        public String getMinValueAsString() {
             return dateFormatter.printer().print(minValue);
         }
 
         @Override
-        public String getMaxValue() {
+        public String getMaxValueAsString() {
             return dateFormatter.printer().print(maxValue);
         }
 
@@ -470,12 +490,6 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
             return dateFormatter.parser().parseMillis(value);
         }
 
-        @Override
-        protected void toInnerXContent(XContentBuilder builder) throws IOException {
-            builder.field(Fields.MIN_VALUE, getMinValue());
-            builder.field(Fields.MAX_VALUE, getMaxValue());
-        }
-
         @Override
         public void readFrom(StreamInput in) throws IOException {
             super.readFrom(in);
@@ -525,7 +539,9 @@ public abstract class FieldStats<T extends Comparable<T>> implements Streamable,
         final static XContentBuilderString SUM_DOC_FREQ = new XContentBuilderString("sum_doc_freq");
         final static XContentBuilderString SUM_TOTAL_TERM_FREQ = new XContentBuilderString("sum_total_term_freq");
         final static XContentBuilderString MIN_VALUE = new XContentBuilderString("min_value");
+        final static XContentBuilderString MIN_VALUE_AS_STRING = new XContentBuilderString("min_value_as_string");
         final static XContentBuilderString MAX_VALUE = new XContentBuilderString("max_value");
+        final static XContentBuilderString MAX_VALUE_AS_STRING = new XContentBuilderString("max_value_as_string");
 
     }
 

+ 55 - 54
core/src/test/java/org/elasticsearch/fieldstats/FieldStatsIntegrationIT.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.fieldstats;
 
+import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.action.ActionRequestValidationException;
 import org.elasticsearch.action.fieldstats.FieldStats;
 import org.elasticsearch.action.fieldstats.FieldStatsResponse;
@@ -47,12 +48,12 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         ));
         ensureGreen("test");
 
-        byte minByte = Byte.MAX_VALUE;
-        byte maxByte = Byte.MIN_VALUE;
-        short minShort = Short.MAX_VALUE;
-        short maxShort = Short.MIN_VALUE;
-        int minInt = Integer.MAX_VALUE;
-        int maxInt = Integer.MIN_VALUE;
+        long minByte = Byte.MAX_VALUE;
+        long maxByte = Byte.MIN_VALUE;
+        long minShort = Short.MAX_VALUE;
+        long maxShort = Short.MIN_VALUE;
+        long minInt = Integer.MAX_VALUE;
+        long maxInt = Integer.MIN_VALUE;
         long minLong = Long.MAX_VALUE;
         long maxLong = Long.MIN_VALUE;
         float minFloat = Float.MAX_VALUE;
@@ -66,11 +67,11 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         List<IndexRequestBuilder> request = new ArrayList<>(numDocs);
         for (int doc = 0; doc < numDocs; doc++) {
             byte b = randomByte();
-            minByte = (byte) Math.min(minByte, b);
-            maxByte = (byte) Math.max(maxByte, b);
+            minByte = Math.min(minByte, b);
+            maxByte = Math.max(maxByte, b);
             short s = randomShort();
-            minShort = (short) Math.min(minShort, s);
-            maxShort = (short) Math.max(maxShort, s);
+            minShort = Math.min(minShort, s);
+            maxShort = Math.max(maxShort, s);
             int i = randomInt();
             minInt = Math.min(minInt, i);
             maxInt = Math.max(maxInt, i);
@@ -106,18 +107,18 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
             assertThat(stats.getDensity(), equalTo(100));
         }
 
-        assertThat(response.getAllFieldStats().get("byte").getMinValue(), equalTo(Byte.toString(minByte)));
-        assertThat(response.getAllFieldStats().get("byte").getMaxValue(), equalTo(Byte.toString(maxByte)));
-        assertThat(response.getAllFieldStats().get("short").getMinValue(), equalTo(Short.toString(minShort)));
-        assertThat(response.getAllFieldStats().get("short").getMaxValue(), equalTo(Short.toString(maxShort)));
-        assertThat(response.getAllFieldStats().get("integer").getMinValue(), equalTo(Integer.toString(minInt)));
-        assertThat(response.getAllFieldStats().get("integer").getMaxValue(), equalTo(Integer.toString(maxInt)));
-        assertThat(response.getAllFieldStats().get("long").getMinValue(), equalTo(Long.toString(minLong)));
-        assertThat(response.getAllFieldStats().get("long").getMaxValue(), equalTo(Long.toString(maxLong)));
-        assertThat(response.getAllFieldStats().get("float").getMinValue(), equalTo(Float.toString(minFloat)));
-        assertThat(response.getAllFieldStats().get("float").getMaxValue(), equalTo(Float.toString(maxFloat)));
-        assertThat(response.getAllFieldStats().get("double").getMinValue(), equalTo(Double.toString(minDouble)));
-        assertThat(response.getAllFieldStats().get("double").getMaxValue(), equalTo(Double.toString(maxDouble)));
+        assertThat(response.getAllFieldStats().get("byte").getMinValue(), equalTo(minByte));
+        assertThat(response.getAllFieldStats().get("byte").getMaxValue(), equalTo(maxByte));
+        assertThat(response.getAllFieldStats().get("short").getMinValue(), equalTo(minShort));
+        assertThat(response.getAllFieldStats().get("short").getMaxValue(), equalTo(maxShort));
+        assertThat(response.getAllFieldStats().get("integer").getMinValue(), equalTo(minInt));
+        assertThat(response.getAllFieldStats().get("integer").getMaxValue(), equalTo(maxInt));
+        assertThat(response.getAllFieldStats().get("long").getMinValue(), equalTo(minLong));
+        assertThat(response.getAllFieldStats().get("long").getMaxValue(), equalTo(maxLong));
+        assertThat(response.getAllFieldStats().get("float").getMinValue(), equalTo(minFloat));
+        assertThat(response.getAllFieldStats().get("float").getMaxValue(), equalTo(maxFloat));
+        assertThat(response.getAllFieldStats().get("double").getMinValue(), equalTo(minDouble));
+        assertThat(response.getAllFieldStats().get("double").getMaxValue(), equalTo(maxDouble));
     }
 
     public void testFieldStatsIndexLevel() throws Exception {
@@ -139,32 +140,32 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         // default:
         FieldStatsResponse response = client().prepareFieldStats().setFields("value").get();
         assertAllSuccessful(response);
-        assertThat(response.getAllFieldStats().get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getAllFieldStats().get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getAllFieldStats().get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getAllFieldStats().get("value").getMaxValue(), equalTo(300l));
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(300l));
 
         // Level: cluster
         response = client().prepareFieldStats().setFields("value").setLevel("cluster").get();
         assertAllSuccessful(response);
-        assertThat(response.getAllFieldStats().get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getAllFieldStats().get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getAllFieldStats().get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getAllFieldStats().get("value").getMaxValue(), equalTo(300l));
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getIndicesMergedFieldStats().get("_all").get("value").getMaxValue(), equalTo(300l));
 
         // Level: indices
         response = client().prepareFieldStats().setFields("value").setLevel("indices").get();
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(3));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(Long.toString(100)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(Long.toString(101)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(Long.toString(200)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(Long.toString(201)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(100l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(101l));
+        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));
 
         // Illegal level option:
         try {
@@ -200,10 +201,10 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         FieldStatsResponse response = client().prepareFieldStats().setFields("value").setLevel("indices").get();
         assertAllSuccessful(response);
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(Long.toString(1)));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(Long.toString(2)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("a"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo("b"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(1l));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(2l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(new BytesRef("a")));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(new BytesRef("b")));
     }
 
     public void testFieldStatsFiltering() throws Exception {
@@ -230,8 +231,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(Long.toString(201)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(201l));
+        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(300l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -241,10 +242,10 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(Long.toString(-10)));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(Long.toString(100)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(Long.toString(101)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(Long.toString(200)));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(-10l));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMaxValue(), equalTo(100l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(101l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(200l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -254,10 +255,10 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(Long.toString(101)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(Long.toString(200)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(Long.toString(201)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(101l));
+        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));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -285,8 +286,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(Long.toString(101)));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(Long.toString(200)));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(101l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMaxValue(), equalTo(200l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -296,8 +297,8 @@ public class FieldStatsIntegrationIT extends ESIntegTestCase {
         assertAllSuccessful(response);
         assertThat(response.getAllFieldStats(), nullValue());
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(Long.toString(201)));
-        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(Long.toString(300)));
+        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMinValue(), equalTo(201l));
+        assertThat(response.getIndicesMergedFieldStats().get("test3").get("value").getMaxValue(), equalTo(300l));
     }
 
     public void testIncompatibleFilter() throws Exception {

+ 55 - 32
core/src/test/java/org/elasticsearch/fieldstats/FieldStatsTests.java

@@ -19,10 +19,12 @@
 
 package org.elasticsearch.fieldstats;
 
+import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.action.fieldstats.FieldStats;
 import org.elasticsearch.action.fieldstats.FieldStatsResponse;
 import org.elasticsearch.action.fieldstats.IndexConstraint;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.mapper.core.DateFieldMapper;
 import org.elasticsearch.test.ESSingleNodeTestCase;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -75,8 +77,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
         assertThat(result.getAllFieldStats().get("field").getMaxDoc(), equalTo(11l));
         assertThat(result.getAllFieldStats().get("field").getDocCount(), equalTo(11l));
         assertThat(result.getAllFieldStats().get("field").getDensity(), equalTo(100));
-        assertThat(result.getAllFieldStats().get("field").getMinValue(), equalTo(String.format(Locale.ENGLISH, "%03d", 0)));
-        assertThat(result.getAllFieldStats().get("field").getMaxValue(), equalTo(String.format(Locale.ENGLISH, "%03d", 10)));
+        assertThat(result.getAllFieldStats().get("field").getMinValue(), equalTo(new BytesRef(String.format(Locale.ENGLISH, "%03d", 0))));
+        assertThat(result.getAllFieldStats().get("field").getMaxValue(), equalTo(new BytesRef(String.format(Locale.ENGLISH, "%03d", 10))));
+        assertThat(result.getAllFieldStats().get("field").getMinValueAsString(), equalTo(String.format(Locale.ENGLISH, "%03d", 0)));
+        assertThat(result.getAllFieldStats().get("field").getMaxValueAsString(), equalTo(String.format(Locale.ENGLISH, "%03d", 10)));
     }
 
     public void testDouble() {
@@ -91,8 +95,9 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
         assertThat(result.getAllFieldStats().get(fieldName).getMaxDoc(), equalTo(11l));
         assertThat(result.getAllFieldStats().get(fieldName).getDocCount(), equalTo(11l));
         assertThat(result.getAllFieldStats().get(fieldName).getDensity(), equalTo(100));
-        assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(Double.toString(-1)));
-        assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(Double.toString(9)));
+        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)));
     }
 
     public void testFloat() {
@@ -107,8 +112,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
         assertThat(result.getAllFieldStats().get(fieldName).getMaxDoc(), equalTo(11l));
         assertThat(result.getAllFieldStats().get(fieldName).getDocCount(), equalTo(11l));
         assertThat(result.getAllFieldStats().get(fieldName).getDensity(), equalTo(100));
-        assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(Float.toString(-1)));
-        assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(Float.toString(9)));
+        assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(-1.0));
+        assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(9.0));
+        assertThat(result.getAllFieldStats().get(fieldName).getMinValueAsString(), equalTo(Float.toString(-1)));
+        assertThat(result.getAllFieldStats().get(fieldName).getMaxValueAsString(), equalTo(Float.toString(9)));
     }
 
     private void testNumberRange(String fieldName, String fieldType, long min, long max) {
@@ -123,8 +130,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
         assertThat(result.getAllFieldStats().get(fieldName).getMaxDoc(), equalTo(numDocs));
         assertThat(result.getAllFieldStats().get(fieldName).getDocCount(), equalTo(numDocs));
         assertThat(result.getAllFieldStats().get(fieldName).getDensity(), equalTo(100));
-        assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(java.lang.Long.toString(min)));
-        assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(java.lang.Long.toString(max)));
+        assertThat(result.getAllFieldStats().get(fieldName).getMinValue(), equalTo(min));
+        assertThat(result.getAllFieldStats().get(fieldName).getMaxValue(), equalTo(max));
+        assertThat(result.getAllFieldStats().get(fieldName).getMinValueAsString(), equalTo(java.lang.Long.toString(min)));
+        assertThat(result.getAllFieldStats().get(fieldName).getMaxValueAsString(), equalTo(java.lang.Long.toString(max)));
         client().admin().indices().prepareDelete("test").get();
     }
 
@@ -193,15 +202,15 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
         assertThat(result.getTotalShards(), equalTo(2));
         assertThat(result.getSuccessfulShards(), equalTo(1));
         assertThat(result.getShardFailures()[0].reason(), either(containsString("field [field1] doesn't exist")).or(containsString("field [field2] doesn't exist")));
-        assertThat(result.getIndicesMergedFieldStats().get("_all").get("field1").getMinValue(), equalTo("a"));
-        assertThat(result.getIndicesMergedFieldStats().get("_all").get("field1").getMaxValue(), equalTo("b"));
+        assertThat(result.getIndicesMergedFieldStats().get("_all").get("field1").getMinValueAsString(), equalTo("a"));
+        assertThat(result.getIndicesMergedFieldStats().get("_all").get("field1").getMaxValueAsString(), equalTo("b"));
     }
 
     public void testNumberFiltering() {
         createIndex("test1", Settings.EMPTY, "type", "value", "type=long");
-        client().prepareIndex("test1", "test").setSource("value", 1).get();
+        client().prepareIndex("test1", "test").setSource("value", 1l).get();
         createIndex("test2", Settings.EMPTY, "type", "value", "type=long");
-        client().prepareIndex("test2", "test").setSource("value", 3).get();
+        client().prepareIndex("test2", "test").setSource("value", 3l).get();
         client().admin().indices().prepareRefresh().get();
 
         FieldStatsResponse response = client().prepareFieldStats()
@@ -209,8 +218,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("1"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("3"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(1l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(3l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -232,7 +241,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("1"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(1l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -240,7 +249,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("1"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(1l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -255,7 +264,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("3"));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(3l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -263,7 +272,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("3"));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(3l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -278,8 +287,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("1"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("3"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(1l));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(3l));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -290,10 +299,15 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
     }
 
     public void testDateFiltering() {
+        DateTime dateTime1 = new DateTime(2014, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC);
+        String dateTime1Str = DateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().print(dateTime1);
+        DateTime dateTime2 = new DateTime(2014, 1, 2, 0, 0, 0, 0, DateTimeZone.UTC);
+        String dateTime2Str = DateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().print(dateTime2);
+
         createIndex("test1", Settings.EMPTY, "type", "value", "type=date");
-        client().prepareIndex("test1", "test").setSource("value", "2014-01-01T00:00:00.000Z").get();
+        client().prepareIndex("test1", "test").setSource("value", dateTime1Str).get();
         createIndex("test2", Settings.EMPTY, "type", "value", "type=date");
-        client().prepareIndex("test2", "test").setSource("value", "2014-01-02T00:00:00.000Z").get();
+        client().prepareIndex("test2", "test").setSource("value", dateTime2Str).get();
         client().admin().indices().prepareRefresh().get();
 
         FieldStatsResponse response = client().prepareFieldStats()
@@ -301,8 +315,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("2014-01-01T00:00:00.000Z"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(dateTime1.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(dateTime2.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValueAsString(), equalTo(dateTime1Str));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -317,7 +333,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("2014-01-01T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(dateTime1.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValueAsString(), equalTo(dateTime1Str));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -325,7 +342,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(dateTime2.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -340,7 +358,8 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(dateTime2.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -348,8 +367,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("2014-01-01T00:00:00.000Z"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(dateTime1.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(dateTime2.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValueAsString(), equalTo(dateTime1Str));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str));
 
         response = client().prepareFieldStats()
                 .setFields("value")
@@ -357,8 +378,10 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(2));
-        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo("2014-01-01T00:00:00.000Z"));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValue(), equalTo(dateTime1.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo(dateTime2.getMillis()));
+        assertThat(response.getIndicesMergedFieldStats().get("test1").get("value").getMinValueAsString(), equalTo(dateTime1Str));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo(dateTime2Str));
     }
 
     public void testDateFiltering_optionalFormat() {
@@ -376,7 +399,7 @@ public class FieldStatsTests extends ESSingleNodeTestCase {
                 .setLevel("indices")
                 .get();
         assertThat(response.getIndicesMergedFieldStats().size(), equalTo(1));
-        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValue(), equalTo("2014-01-02T00:00:00.000Z"));
+        assertThat(response.getIndicesMergedFieldStats().get("test2").get("value").getMinValueAsString(), equalTo("2014-01-02T00:00:00.000Z"));
 
         try {
             client().prepareFieldStats()

+ 2 - 0
docs/reference/migration/index.asciidoc

@@ -20,6 +20,8 @@ include::migrate_3_0.asciidoc[]
 
 include::migrate_2_1.asciidoc[]
 
+include::migrate_2_2.asciidoc[]
+
 include::migrate_2_0.asciidoc[]
 
 include::migrate_1_6.asciidoc[]

+ 16 - 0
docs/reference/migration/migrate_2_2.asciidoc

@@ -0,0 +1,16 @@
+[[breaking-changes-2.2]]
+== Breaking changes in 2.2
+
+This section discusses the changes that you need to be aware of when migrating
+your application to Elasticsearch 2.2.
+
+* <<breaking_22_index_apis>>
+
+[[breaking_22_index_apis]]
+=== Index APIs
+
+==== Field stats API
+
+The field stats' response format has been changed for number based and date fields. The `min_value` and
+`max_value` elements now return values as number and the new `min_value_as_string` and `max_value_as_string`
+return the values as string.

+ 12 - 2
docs/reference/search/field-stats.asciidoc

@@ -79,11 +79,21 @@ document and field.
 
 `min_value`::
 
-The lowest value in the field represented in a displayable form.
+The lowest value in the field.
+
+`min_value_as_string`::
+
+The lowest value in the field represented in a displayable form. All fields,
+but string fields returns this. (since string fields, represent values already as strings)
 
 `max_value`::
 
-The highest value in the field represented in a displayable form.
+The highest value in the field.
+
+`max_value_as_string`::
+
+The highest value in the field represented in a displayable form. All fields,
+but string fields returns this. (since string fields, represent values already as strings)
 
 NOTE: Documents marked as deleted (but not yet removed by the merge process)
 still affect all the mentioned statistics.

+ 4 - 0
rest-api-spec/src/main/resources/rest-api-spec/test/field_stats/10_basics.yaml

@@ -22,7 +22,9 @@
   - match: { indices._all.fields.number.max_doc: 1 }
   - match: { indices._all.fields.number.doc_count: 1 }
   - match: { indices._all.fields.number.min_value: 123 }
+  - match: { indices._all.fields.number.min_value_as_string: "123" }
   - match: { indices._all.fields.number.max_value: 123 }
+  - match: { indices._all.fields.number.max_value_as_string: "123" }
 
 ---
 "Basic field stats with level set to indices":
@@ -49,7 +51,9 @@
   - match: { indices.test_1.fields.number.max_doc: 1 }
   - match: { indices.test_1.fields.number.doc_count: 1 }
   - match: { indices.test_1.fields.number.min_value: 123 }
+  - 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" }
 
 ---
 "Field stats with filtering":