Date Histogram Aggregation Usage

edit

A multi-bucket aggregation similar to the histogram except it can only be applied on date values. From a functionality perspective, this histogram supports the same features as the normal histogram. The main difference is that the interval can be specified by date/time expressions.

When specifying a format and extended_bounds or missing, in order for Elasticsearch to be able to parse the serialized DateTime of extended_bounds or missing correctly, the date_optional_time format is included as part of the format value.

Be sure to read the Elasticsearch documentation on Date Histogram Aggregation.

Fluent DSL example

edit
a => a
.DateHistogram("projects_started_per_month", date => date
    .Field(p => p.StartedOn)
    .Interval(DateInterval.Month)
    .MinimumDocumentCount(2)
    .Format("yyyy-MM-dd'T'HH:mm:ss")
    .ExtendedBounds(FixedDate.AddYears(-1), FixedDate.AddYears(1))
    .Order(HistogramOrder.CountAscending)
    .Missing(FixedDate)
    .Aggregations(childAggs => childAggs
        .Nested("project_tags", n => n
            .Path(p => p.Tags)
            .Aggregations(nestedAggs => nestedAggs
                .Terms("tags", avg => avg.Field(p => p.Tags.First().Name))
            )
        )
    )
)

Object Initializer syntax example

edit
new DateHistogramAggregation("projects_started_per_month")
{
    Field = Field<Project>(p => p.StartedOn),
    Interval = DateInterval.Month,
    MinimumDocumentCount = 2,
    Format = "yyyy-MM-dd'T'HH:mm:ss",
    ExtendedBounds = new ExtendedBounds<DateMath>
    {
        Minimum = FixedDate.AddYears(-1),
        Maximum = FixedDate.AddYears(1),
    },
    Order = HistogramOrder.CountAscending,
    Missing = FixedDate,
    Aggregations = new NestedAggregation("project_tags")
    {
        Path = Field<Project>(p => p.Tags),
        Aggregations = new TermsAggregation("tags")
        {
            Field = Field<Project>(p => p.Tags.First().Name)
        }
    }
}

Example json output.

{
  "projects_started_per_month": {
    "date_histogram": {
      "field": "startedOn",
      "interval": "month",
      "min_doc_count": 2,
      "format": "yyyy-MM-dd'T'HH:mm:ss||date_optional_time",
      "order": {
        "_count": "asc"
      },
      "extended_bounds": {
        "min": "2014-06-06T12:01:02.123",
        "max": "2016-06-06T12:01:02.123"
      },
      "missing": "2015-06-06T12:01:02.123"
    },
    "aggs": {
      "project_tags": {
        "nested": {
          "path": "tags"
        },
        "aggs": {
          "tags": {
            "terms": {
              "field": "tags.name"
            }
          }
        }
      }
    }
  }
}

Handling responses

edit

The AggregateDictionary found on `.Aggregations on ISearchResponse<T> has several helper methods so we can fetch our aggregation results easily in the correct type. Be sure to read more about these helper methods

response.ShouldBeValid();

var dateHistogram = response.Aggregations.DateHistogram("projects_started_per_month");
dateHistogram.Should().NotBeNull();
dateHistogram.Buckets.Should().NotBeNull();
dateHistogram.Buckets.Count.Should().BeGreaterThan(10);
foreach (var item in dateHistogram.Buckets)
{
    item.Date.Should().NotBe(default(DateTime));
    item.DocCount.Should().BeGreaterThan(0);

    var nested = item.Nested("project_tags");
    nested.Should().NotBeNull();

    var nestedTerms = nested.Terms("tags");
    nestedTerms.Buckets.Count.Should().BeGreaterThan(0);
}