From d476d927432c7014e61a8088e6ad1e60f6a95dc3 Mon Sep 17 00:00:00 2001 From: Mark Tozzi Date: Fri, 4 Oct 2019 16:01:28 -0400 Subject: [PATCH] DocValueFormat implementation for date range fields (#47472) --- .../bucket/range-field-note.asciidoc | 13 +++++++++++-- .../index/mapper/RangeFieldMapper.java | 19 +++++++++++++++++++ .../DateRangeHistogramAggregatorTests.java | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/docs/reference/aggregations/bucket/range-field-note.asciidoc b/docs/reference/aggregations/bucket/range-field-note.asciidoc index 0e49c0035b15f..89056586a1b07 100644 --- a/docs/reference/aggregations/bucket/range-field-note.asciidoc +++ b/docs/reference/aggregations/bucket/range-field-note.asciidoc @@ -117,7 +117,8 @@ POST /range_index/_search?size=0 "november_data" : { "date_histogram" : { "field" : "time_frame", - "calendar_interval" : "day" + "calendar_interval" : "day", + "format": "yyyy-MM-dd" } } } @@ -135,35 +136,43 @@ calculated over the ranges of all matching documents. "aggregations" : { "november_data" : { "buckets" : [ - { + { + "key_as_string" : "2019-10-28", "key" : 1572220800000, "doc_count" : 1 }, { + "key_as_string" : "2019-10-29", "key" : 1572307200000, "doc_count" : 1 }, { + "key_as_string" : "2019-10-30", "key" : 1572393600000, "doc_count" : 1 }, { + "key_as_string" : "2019-10-31", "key" : 1572480000000, "doc_count" : 1 }, { + "key_as_string" : "2019-11-01", "key" : 1572566400000, "doc_count" : 1 }, { + "key_as_string" : "2019-11-02", "key" : 1572652800000, "doc_count" : 1 }, { + "key_as_string" : "2019-11-03", "key" : 1572739200000, "doc_count" : 1 }, { + "key_as_string" : "2019-11-04", "key" : 1572825600000, "doc_count" : 1 } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index c4fe6ca934f96..3bb4f24aa61da 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -44,11 +44,13 @@ import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.plain.DocValuesIndexFieldData; import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.search.DocValueFormat; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -268,6 +270,23 @@ public Query existsQuery(QueryShardContext context) { } } + @Override + public DocValueFormat docValueFormat(String format, ZoneId timeZone) { + if (rangeType == RangeType.DATE) { + DateFormatter dateTimeFormatter = this.dateTimeFormatter; + if (format != null) { + dateTimeFormatter = DateFormatter.forPattern(format).withLocale(dateTimeFormatter.locale()); + } + if (timeZone == null) { + timeZone = ZoneOffset.UTC; + } + // the resolution here is always set to milliseconds, as aggregations use this formatter mainly and those are always in + // milliseconds. The only special case here is docvalue fields, which are handled somewhere else + return new DocValueFormat.DateTime(dateTimeFormatter, timeZone, DateFieldMapper.Resolution.MILLISECONDS); + } + return super.docValueFormat(format, timeZone); + } + @Override public Query termQuery(Object value, QueryShardContext context) { Query query = rangeQuery(value, value, true, true, ShapeRelation.INTERSECTS, null, null, context); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/DateRangeHistogramAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/DateRangeHistogramAggregatorTests.java index 1a629b745b4e1..af6f51da50a8c 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/DateRangeHistogramAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/histogram/DateRangeHistogramAggregatorTests.java @@ -65,6 +65,22 @@ public void testBasics() throws Exception { ); } + public void testFormat() throws Exception { + RangeFieldMapper.Range range = new RangeFieldMapper.Range(RangeType.DATE, asLong("2019-08-01T12:14:36"), + asLong("2019-08-01T15:07:22"), true, true); + testCase( + new MatchAllDocsQuery(), + builder -> builder.calendarInterval(DateHistogramInterval.DAY).format("yyyy-MM-dd"), + writer -> writer.addDocument(singleton(new BinaryDocValuesField(FIELD_NAME, RangeType.DATE.encodeRanges(singleton(range))))), + histo -> { + assertEquals(1, histo.getBuckets().size()); + assertTrue(AggregationInspectionHelper.hasValue(histo)); + + assertEquals("2019-08-01", histo.getBuckets().get(0).getKeyAsString()); + } + ); + } + public void testUnsupportedRangeType() throws Exception { RangeType rangeType = RangeType.LONG; final String fieldName = "field";