Skip to content

Commit 4033acc

Browse files
Fix DateHistogram aggregation intervals (#4856) (#4857)
This commit fixes FixedInterval and CalendarInterval on DateHistogram aggregation to 1. For FixedInterval to accept only Time 2. For CalendarInterval to accept DateInterval or DateMathTime This aligns with DateHistogramCompositeAggregationSource. Fixes #4839 Co-authored-by: Russ Cam <russ.cam@elastic.co>
1 parent fd9ce4d commit 4033acc

File tree

3 files changed

+91
-35
lines changed

3 files changed

+91
-35
lines changed

docs/aggregations/bucket/date-histogram/date-histogram-aggregation-usage.asciidoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Be sure to read the Elasticsearch documentation on {ref_current}/search-aggregat
3232
a => a
3333
.DateHistogram("projects_started_per_month", date => date
3434
.Field(p => p.StartedOn)
35-
.Interval(DateInterval.Month)
35+
.CalendarInterval(DateInterval.Month)
3636
.MinimumDocumentCount(2)
3737
.Format("yyyy-MM-dd'T'HH:mm:ss")
3838
.ExtendedBounds(FixedDate.AddYears(-1), FixedDate.AddYears(1))
@@ -56,7 +56,7 @@ a => a
5656
new DateHistogramAggregation("projects_started_per_month")
5757
{
5858
Field = Field<Project>(p => p.StartedOn),
59-
Interval = DateInterval.Month,
59+
CalendarInterval = DateInterval.Month,
6060
MinimumDocumentCount = 2,
6161
Format = "yyyy-MM-dd'T'HH:mm:ss",
6262
ExtendedBounds = new ExtendedBounds<DateMath>
@@ -84,7 +84,7 @@ new DateHistogramAggregation("projects_started_per_month")
8484
"projects_started_per_month": {
8585
"date_histogram": {
8686
"field": "startedOn",
87-
"interval": "month",
87+
"calendar_interval": "month",
8888
"min_doc_count": 2,
8989
"format": "yyyy-MM-dd'T'HH:mm:ss||date_optional_time",
9090
"order": {

src/Nest/Aggregations/Bucket/DateHistogram/DateHistogramAggregation.cs

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,81 @@ namespace Nest
1414
[ReadAs(typeof(DateHistogramAggregation))]
1515
public interface IDateHistogramAggregation : IBucketAggregation
1616
{
17+
/// <summary>
18+
/// Extend the bounds of the date histogram beyond the data itself,
19+
/// forcing the aggregation to start building buckets on
20+
/// a specific min and/or max value.
21+
/// Using extended bounds only makes sense when <see cref="MinimumDocumentCount"/> is 0
22+
/// as empty buckets will never be returned if it is greater than 0.
23+
/// </summary>
1724
[DataMember(Name ="extended_bounds")]
1825
ExtendedBounds<DateMath> ExtendedBounds { get; set; }
1926

27+
/// <summary>
28+
/// The field to target
29+
/// </summary>
2030
[DataMember(Name ="field")]
2131
Field Field { get; set; }
2232

33+
/// <summary>
34+
/// Return a formatted date string as the key instead an epoch long
35+
/// </summary>
2336
[DataMember(Name ="format")]
2437
string Format { get; set; }
2538

2639
[Obsolete("Deprecated in version 7.2.0, use CalendarInterval or FixedInterval instead")]
2740
[DataMember(Name ="interval")]
2841
Union<DateInterval, Time> Interval { get; set; }
2942

43+
/// <summary>
44+
/// The calendar interval to use when bucketing documents
45+
/// </summary>
3046
[DataMember(Name ="calendar_interval")]
31-
Union<DateInterval, Time> CalendarInterval { get; set; }
47+
Union<DateInterval?, DateMathTime> CalendarInterval { get; set; }
3248

49+
/// <summary>
50+
/// The fixed interval to use when bucketing documents
51+
/// </summary>
3352
[DataMember(Name ="fixed_interval")]
34-
Union<DateInterval, Time> FixedInterval { get; set; }
53+
Time FixedInterval { get; set; }
3554

55+
/// <summary>
56+
/// The minimum number of documents that a bucket must contain to be returned in the response.
57+
/// The default is 0 meaning that buckets with no documents will be returned.
58+
/// </summary>
3659
[DataMember(Name ="min_doc_count")]
3760
int? MinimumDocumentCount { get; set; }
3861

62+
/// <summary>
63+
/// Defines how to treat documents that are missing a value. By default, they are ignored,
64+
/// but it is also possible to treat them as if they have a value.
65+
/// </summary>
3966
[DataMember(Name ="missing")]
4067
DateTime? Missing { get; set; }
4168

69+
/// <summary>
70+
/// Change the start value of each bucket by the specified positive (+) or negative offset (-) duration,
71+
/// such as 1h for an hour, or 1d for a day.
72+
/// </summary>
4273
[DataMember(Name ="offset")]
4374
string Offset { get; set; }
4475

76+
/// <summary>
77+
/// Defines an order in which returned buckets are sorted.
78+
/// By default the returned buckets are sorted by their key ascending.
79+
/// </summary>
4580
[DataMember(Name ="order")]
4681
HistogramOrder Order { get; set; }
4782

48-
[DataMember(Name ="params")]
49-
IDictionary<string, object> Params { get; set; }
50-
83+
/// <inheritdoc cref="IScript"/>
5184
[DataMember(Name ="script")]
5285
IScript Script { get; set; }
5386

87+
/// <summary>
88+
/// Used to indicate that bucketing should use a different time zone.
89+
/// Time zones may either be specified as an ISO 8601 UTC offset (e.g. +01:00 or -08:00)
90+
/// or as a timezone id, an identifier used in the TZ database like America/Los_Angeles.
91+
/// </summary>
5492
[DataMember(Name ="time_zone")]
5593
string TimeZone { get; set; }
5694
}
@@ -63,9 +101,12 @@ internal DateHistogramAggregation() { }
63101

64102
public DateHistogramAggregation(string name) : base(name) { }
65103

104+
/// <inheritdoc />
66105
public ExtendedBounds<DateMath> ExtendedBounds { get; set; }
106+
/// <inheritdoc />
67107
public Field Field { get; set; }
68108

109+
/// <inheritdoc />
69110
public string Format
70111
{
71112
get => !string.IsNullOrEmpty(_format) &&
@@ -79,15 +120,21 @@ public string Format
79120

80121
[Obsolete("Deprecated in version 7.2.0, use CalendarInterval or FixedInterval instead")]
81122
public Union<DateInterval, Time> Interval { get; set; }
82-
public Union<DateInterval, Time> CalendarInterval { get; set; }
83-
public Union<DateInterval, Time> FixedInterval { get; set; }
84-
123+
/// <inheritdoc />
124+
public Union<DateInterval?, DateMathTime> CalendarInterval { get; set; }
125+
/// <inheritdoc />
126+
public Time FixedInterval { get; set; }
127+
/// <inheritdoc />
85128
public int? MinimumDocumentCount { get; set; }
129+
/// <inheritdoc />
86130
public DateTime? Missing { get; set; }
131+
/// <inheritdoc />
87132
public string Offset { get; set; }
133+
/// <inheritdoc />
88134
public HistogramOrder Order { get; set; }
89-
public IDictionary<string, object> Params { get; set; }
135+
/// <inheritdoc />
90136
public IScript Script { get; set; }
137+
/// <inheritdoc />
91138
public string TimeZone { get; set; }
92139

93140
internal override void WrapInContainer(AggregationContainer c) => c.DateHistogram = this;
@@ -116,29 +163,25 @@ string IDateHistogramAggregation.Format
116163

117164
[Obsolete("Deprecated in version 7.2.0, use CalendarInterval or FixedInterval instead")]
118165
Union<DateInterval, Time> IDateHistogramAggregation.Interval { get; set; }
119-
Union<DateInterval, Time> IDateHistogramAggregation.CalendarInterval { get; set; }
120-
Union<DateInterval, Time> IDateHistogramAggregation.FixedInterval { get; set; }
121-
166+
Union<DateInterval?, DateMathTime> IDateHistogramAggregation.CalendarInterval { get; set; }
167+
Time IDateHistogramAggregation.FixedInterval { get; set; }
122168
int? IDateHistogramAggregation.MinimumDocumentCount { get; set; }
123-
124169
DateTime? IDateHistogramAggregation.Missing { get; set; }
125-
126170
string IDateHistogramAggregation.Offset { get; set; }
127-
128171
HistogramOrder IDateHistogramAggregation.Order { get; set; }
129-
130-
IDictionary<string, object> IDateHistogramAggregation.Params { get; set; }
131-
132172
IScript IDateHistogramAggregation.Script { get; set; }
133-
134173
string IDateHistogramAggregation.TimeZone { get; set; }
135174

175+
/// <inheritdoc cref="IDateHistogramAggregation.Field" />
136176
public DateHistogramAggregationDescriptor<T> Field(Field field) => Assign(field, (a, v) => a.Field = v);
137177

178+
/// <inheritdoc cref="IDateHistogramAggregation.Field" />
138179
public DateHistogramAggregationDescriptor<T> Field<TValue>(Expression<Func<T, TValue>> field) => Assign(field, (a, v) => a.Field = v);
139180

181+
/// <inheritdoc cref="IDateHistogramAggregation.Script" />
140182
public DateHistogramAggregationDescriptor<T> Script(string script) => Assign((InlineScript)script, (a, v) => a.Script = v);
141183

184+
/// <inheritdoc cref="IDateHistogramAggregation.Script" />
142185
public DateHistogramAggregationDescriptor<T> Script(Func<ScriptDescriptor, IScript> scriptSelector) =>
143186
Assign(scriptSelector, (a, v) => a.Script = v?.Invoke(new ScriptDescriptor()));
144187

@@ -149,31 +192,44 @@ public DateHistogramAggregationDescriptor<T> Script(Func<ScriptDescriptor, IScri
149192
public DateHistogramAggregationDescriptor<T> Interval(DateInterval interval) =>
150193
Assign(interval, (a, v) => a.Interval = v);
151194

152-
public DateHistogramAggregationDescriptor<T> CalendarInterval(Time interval) => Assign(interval, (a, v) => a.CalendarInterval = v);
153-
public DateHistogramAggregationDescriptor<T> CalendarInterval(DateInterval interval) => Assign(interval, (a, v) => a.CalendarInterval = v);
195+
/// <inheritdoc cref="IDateHistogramAggregation.CalendarInterval" />
196+
public DateHistogramAggregationDescriptor<T> CalendarInterval(DateMathTime interval) => Assign(interval, (a, v) => a.CalendarInterval = v);
197+
198+
/// <inheritdoc cref="IDateHistogramAggregation.CalendarInterval" />
199+
public DateHistogramAggregationDescriptor<T> CalendarInterval(DateInterval? interval) => Assign(interval, (a, v) => a.CalendarInterval = v);
200+
201+
/// <inheritdoc cref="IDateHistogramAggregation.FixedInterval" />
154202
public DateHistogramAggregationDescriptor<T> FixedInterval(Time interval) => Assign(interval, (a, v) => a.FixedInterval = v);
155-
public DateHistogramAggregationDescriptor<T> FixedInterval(DateInterval interval) => Assign(interval, (a, v) => a.FixedInterval = v);
156203

204+
/// <inheritdoc cref="IDateHistogramAggregation.Format" />
157205
public DateHistogramAggregationDescriptor<T> Format(string format) => Assign(format, (a, v) => a.Format = v);
158206

207+
/// <inheritdoc cref="IDateHistogramAggregation.MinimumDocumentCount" />
159208
public DateHistogramAggregationDescriptor<T> MinimumDocumentCount(int? minimumDocumentCount) =>
160209
Assign(minimumDocumentCount, (a, v) => a.MinimumDocumentCount = v);
161210

211+
/// <inheritdoc cref="IDateHistogramAggregation.TimeZone" />
162212
public DateHistogramAggregationDescriptor<T> TimeZone(string timeZone) => Assign(timeZone, (a, v) => a.TimeZone = v);
163213

214+
/// <inheritdoc cref="IDateHistogramAggregation.Offset" />
164215
public DateHistogramAggregationDescriptor<T> Offset(string offset) => Assign(offset, (a, v) => a.Offset = v);
165216

217+
/// <inheritdoc cref="IDateHistogramAggregation.Order" />
166218
public DateHistogramAggregationDescriptor<T> Order(HistogramOrder order) => Assign(order, (a, v) => a.Order = v);
167219

220+
/// <inheritdoc cref="IDateHistogramAggregation.Order" />
168221
public DateHistogramAggregationDescriptor<T> OrderAscending(string key) =>
169222
Assign(new HistogramOrder { Key = key, Order = SortOrder.Descending }, (a, v) => a.Order = v);
170223

224+
/// <inheritdoc cref="IDateHistogramAggregation.Order" />
171225
public DateHistogramAggregationDescriptor<T> OrderDescending(string key) =>
172226
Assign(new HistogramOrder { Key = key, Order = SortOrder.Descending }, (a, v) => a.Order = v);
173227

228+
/// <inheritdoc cref="IDateHistogramAggregation.ExtendedBounds" />
174229
public DateHistogramAggregationDescriptor<T> ExtendedBounds(DateMath min, DateMath max) =>
175230
Assign(new ExtendedBounds<DateMath> { Minimum = min, Maximum = max }, (a, v) => a.ExtendedBounds = v);
176231

232+
/// <inheritdoc cref="IDateHistogramAggregation.Missing" />
177233
public DateHistogramAggregationDescriptor<T> Missing(DateTime? missing) => Assign(missing, (a, v) => a.Missing = v);
178234
}
179235
}

tests/Tests/Aggregations/Bucket/DateHistogram/DateHistogramAggregationUsageTests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public DateHistogramAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage
3737
date_histogram = new
3838
{
3939
field = "startedOn",
40-
interval = "month",
40+
calendar_interval = "month",
4141
min_doc_count = 2,
4242
format = "yyyy-MM-dd'T'HH:mm:ss||date_optional_time", //<1> Note the inclusion of `date_optional_time` to `format`
4343
order = new { _count = "asc" },
@@ -72,7 +72,7 @@ public DateHistogramAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage
7272
protected override Func<AggregationContainerDescriptor<Project>, IAggregationContainer> FluentAggs => a => a
7373
.DateHistogram("projects_started_per_month", date => date
7474
.Field(p => p.StartedOn)
75-
.Interval(DateInterval.Month)
75+
.CalendarInterval(DateInterval.Month)
7676
.MinimumDocumentCount(2)
7777
.Format("yyyy-MM-dd'T'HH:mm:ss")
7878
.ExtendedBounds(FixedDate.AddYears(-1), FixedDate.AddYears(1))
@@ -92,7 +92,7 @@ public DateHistogramAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage
9292
new DateHistogramAggregation("projects_started_per_month")
9393
{
9494
Field = Field<Project>(p => p.StartedOn),
95-
Interval = DateInterval.Month,
95+
CalendarInterval = DateInterval.Month,
9696
MinimumDocumentCount = 2,
9797
Format = "yyyy-MM-dd'T'HH:mm:ss",
9898
ExtendedBounds = new ExtendedBounds<DateMath>
@@ -147,12 +147,12 @@ public DateHistogramAggregationNoSubAggregationsUsageTests(ReadOnlyCluster i, En
147147

148148
protected override object AggregationJson => new
149149
{
150-
projects_started_per_month = new
150+
projects_started_per_four_weeks = new
151151
{
152152
date_histogram = new
153153
{
154154
field = "startedOn",
155-
interval = "month",
155+
fixed_interval = "28d",
156156
min_doc_count = 2,
157157
format = "yyyy-MM-dd'T'HH:mm:ss||date_optional_time",
158158
order = new { _count = "asc" },
@@ -168,9 +168,9 @@ public DateHistogramAggregationNoSubAggregationsUsageTests(ReadOnlyCluster i, En
168168

169169
#pragma warning disable 618, 612
170170
protected override Func<AggregationContainerDescriptor<Project>, IAggregationContainer> FluentAggs => a => a
171-
.DateHistogram("projects_started_per_month", date => date
171+
.DateHistogram("projects_started_per_four_weeks", date => date
172172
.Field(p => p.StartedOn)
173-
.Interval(DateInterval.Month)
173+
.FixedInterval(new Time(28, TimeUnit.Day))
174174
.MinimumDocumentCount(2)
175175
.Format("yyyy-MM-dd'T'HH:mm:ss")
176176
.ExtendedBounds(FixedDate.AddYears(-1), FixedDate.AddYears(1))
@@ -179,10 +179,10 @@ public DateHistogramAggregationNoSubAggregationsUsageTests(ReadOnlyCluster i, En
179179
);
180180

181181
protected override AggregationDictionary InitializerAggs =>
182-
new DateHistogramAggregation("projects_started_per_month")
182+
new DateHistogramAggregation("projects_started_per_four_weeks")
183183
{
184184
Field = Field<Project>(p => p.StartedOn),
185-
Interval = DateInterval.Month,
185+
FixedInterval = new Time(28, TimeUnit.Day),
186186
MinimumDocumentCount = 2,
187187
Format = "yyyy-MM-dd'T'HH:mm:ss",
188188
ExtendedBounds = new ExtendedBounds<DateMath>
@@ -198,7 +198,7 @@ public DateHistogramAggregationNoSubAggregationsUsageTests(ReadOnlyCluster i, En
198198
protected override void ExpectResponse(ISearchResponse<Project> response)
199199
{
200200
response.ShouldBeValid();
201-
var dateHistogram = response.Aggregations.DateHistogram("projects_started_per_month");
201+
var dateHistogram = response.Aggregations.DateHistogram("projects_started_per_four_weeks");
202202
dateHistogram.Should().NotBeNull();
203203
dateHistogram.Buckets.Should().NotBeNull();
204204
dateHistogram.Buckets.Count.Should().BeGreaterThan(10);

0 commit comments

Comments
 (0)