Aggregations: Format bucket key_as_string in `date_histogram` according to `time_zone`
Change bucket key_as_string to reflect `time_zone` parameter. Currently `time_zone` shifts bucket boundaries to other time zone, but keys are displayed in UTC, so e.g. daily buckets in "+01:00" time zone have key_as_string like "2014-01-01T23:00:00Z". With this change the default is to format this dates according to the local time zone, so the above bucket key would be "2014-01-02T00:00:00+01:00". Closes #9710 Closes #9744
This commit is contained in:
parent
4125e406c7
commit
6d41601b4e
|
@ -31,7 +31,9 @@ import org.elasticsearch.search.SearchParseException;
|
|||
import org.elasticsearch.search.aggregations.Aggregator;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactory;
|
||||
import org.elasticsearch.search.aggregations.support.ValueType;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSourceParser;
|
||||
import org.elasticsearch.search.aggregations.support.format.ValueFormatter.DateTime;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
|
@ -185,7 +187,11 @@ public class DateHistogramParser implements Aggregator.Parser {
|
|||
.timeZone(timeZone)
|
||||
.offset(offset).build();
|
||||
|
||||
return new HistogramAggregator.Factory(aggregationName, vsParser.config(), rounding, order, keyed, minDocCount, extendedBounds,
|
||||
ValuesSourceConfig config = vsParser.config();
|
||||
if (config.formatter()!=null) {
|
||||
((DateTime) config.formatter()).setTimeZone(timeZone);
|
||||
}
|
||||
return new HistogramAggregator.Factory(aggregationName, config, rounding, order, keyed, minDocCount, extendedBounds,
|
||||
new InternalDateHistogram.Factory());
|
||||
|
||||
}
|
||||
|
|
|
@ -28,12 +28,14 @@ import org.elasticsearch.common.joda.FormatDateTimeFormatter;
|
|||
import org.elasticsearch.common.joda.Joda;
|
||||
import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
||||
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* A strategy for formatting time represented as millis long value to string
|
||||
|
@ -101,6 +103,7 @@ public interface ValueFormatter extends Streamable {
|
|||
public static class DateTime implements ValueFormatter {
|
||||
|
||||
public static final ValueFormatter DEFAULT = new ValueFormatter.DateTime(DateFieldMapper.Defaults.DATE_TIME_FORMATTER);
|
||||
private DateTimeZone timeZone = DateTimeZone.UTC;
|
||||
|
||||
public static DateTime mapper(DateFieldMapper mapper) {
|
||||
return new DateTime(mapper.dateTimeFormatter());
|
||||
|
@ -122,9 +125,13 @@ public interface ValueFormatter extends Streamable {
|
|||
|
||||
@Override
|
||||
public String format(long time) {
|
||||
return formatter.printer().print(time);
|
||||
return formatter.printer().withZone(timeZone).print(time);
|
||||
}
|
||||
|
||||
|
||||
public void setTimeZone(DateTimeZone timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
public String format(double value) {
|
||||
return format((long) value);
|
||||
}
|
||||
|
@ -137,11 +144,13 @@ public interface ValueFormatter extends Streamable {
|
|||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
formatter = Joda.forPattern(in.readString());
|
||||
timeZone = DateTimeZone.forID(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(formatter.format());
|
||||
out.writeString(timeZone.getID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hamcrest.Matchers;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.tz.DateTimeZoneBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -123,7 +124,11 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
}
|
||||
|
||||
private static String getBucketKeyAsString(DateTime key) {
|
||||
return Joda.forPattern(DateFieldMapper.Defaults.DATE_TIME_FORMATTER.format()).printer().print(key);
|
||||
return getBucketKeyAsString(key, DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
private static String getBucketKeyAsString(DateTime key, DateTimeZone tz) {
|
||||
return Joda.forPattern(DateFieldMapper.Defaults.DATE_TIME_FORMATTER.format()).printer().withZone(tz).print(key);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -167,7 +172,7 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
SearchResponse response = client().prepareSearch("idx")
|
||||
.addAggregation(dateHistogram("histo").field("date").interval(DateHistogramInterval.DAY).timeZone("+01:00")).execute()
|
||||
.actionGet();
|
||||
|
||||
DateTimeZone tz = DateTimeZone.forID("+01:00");
|
||||
assertSearchResponse(response);
|
||||
|
||||
Histogram histo = response.getAggregations().get("histo");
|
||||
|
@ -179,43 +184,43 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
DateTime key = new DateTime(2012, 1, 1, 23, 0, DateTimeZone.UTC);
|
||||
Histogram.Bucket bucket = buckets.get(0);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 2, 1, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(1);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 2, 14, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(2);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 3, 1, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(3);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 3, 14, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(4);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key.withZone(DateTimeZone.UTC)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 3, 22, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(5);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key.withZone(DateTimeZone.UTC)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1063,7 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
.field("date")
|
||||
.timeZone("-02:00")
|
||||
.interval(DateHistogramInterval.DAY)
|
||||
.format("yyyy-MM-dd:hh-mm-ss"))
|
||||
.format("yyyy-MM-dd:HH-mm-ssZZ"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(response.getHits().getTotalHits(), equalTo(5l));
|
||||
|
@ -1069,12 +1074,12 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
Histogram.Bucket bucket = buckets.get(0);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo("2014-03-10:02-00-00"));
|
||||
assertThat(bucket.getKeyAsString(), equalTo("2014-03-10:00-00-00-02:00"));
|
||||
assertThat(bucket.getDocCount(), equalTo(2l));
|
||||
|
||||
bucket = buckets.get(1);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo("2014-03-11:02-00-00"));
|
||||
assertThat(bucket.getKeyAsString(), equalTo("2014-03-11:00-00-00-02:00"));
|
||||
assertThat(bucket.getDocCount(), equalTo(3l));
|
||||
}
|
||||
|
||||
|
@ -1233,6 +1238,8 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
DateTimeZone tz = DateTimeZone.forID("+01:00");
|
||||
|
||||
Histogram histo = response.getAggregations().get("histo");
|
||||
assertThat(histo, notNullValue());
|
||||
|
@ -1243,21 +1250,21 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
DateTime key = new DateTime(2011, 12, 31, 23, 0, DateTimeZone.UTC);
|
||||
Histogram.Bucket bucket = buckets.get(0);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||
|
||||
key = new DateTime(2012, 1, 31, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(1);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(2l));
|
||||
|
||||
key = new DateTime(2012, 2, 29, 23, 0, DateTimeZone.UTC);
|
||||
bucket = buckets.get(2);
|
||||
assertThat(bucket, notNullValue());
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key)));
|
||||
assertThat(bucket.getKeyAsString(), equalTo(getBucketKeyAsString(key, tz)));
|
||||
assertThat(((DateTime) bucket.getKey()), equalTo(key));
|
||||
assertThat(bucket.getDocCount(), equalTo(3l));
|
||||
}
|
||||
|
@ -1273,7 +1280,7 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
|
|||
assertSearchResponse(response);
|
||||
Histogram histo = response.getAggregations().get("histo");
|
||||
assertThat(histo.getBuckets().size(), equalTo(1));
|
||||
assertThat(histo.getBuckets().get(0).getKeyAsString(), equalTo("2013-12-31T22:00:00.000Z"));
|
||||
assertThat(histo.getBuckets().get(0).getKeyAsString(), equalTo("2014-01-01T00:00:00.000+02:00"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue