Skip to content

Commit

Permalink
Add Median Absolute Deviation Aggregation (#3627)
Browse files Browse the repository at this point in the history
Relates: #3615
  • Loading branch information
russcam authored Apr 1, 2019
1 parent 605fcd0 commit 69ec076
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/aggregations.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ The values are typically extracted from the fields of the document (using the fi

* <<max-aggregation-usage,Max Aggregation Usage>>

* <<median-absolute-deviation-aggregation-usage,Median Absolute Deviation Aggregation Usage>>

* <<min-aggregation-usage,Min Aggregation Usage>>

* <<percentile-ranks-aggregation-usage,Percentile Ranks Aggregation Usage>>
Expand Down Expand Up @@ -80,6 +82,8 @@ include::aggregations/metric/geo-centroid/geo-centroid-aggregation-usage.asciido

include::aggregations/metric/max/max-aggregation-usage.asciidoc[]

include::aggregations/metric/median-absolute-deviation/median-absolute-deviation-aggregation-usage.asciidoc[]

include::aggregations/metric/min/min-aggregation-usage.asciidoc[]

include::aggregations/metric/percentile-ranks/percentile-ranks-aggregation-usage.asciidoc[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
:ref_current: https://www.elastic.co/guide/en/elasticsearch/reference/6.7

:github: https://github.com/elastic/elasticsearch-net

:nuget: https://www.nuget.org/packages

////
IMPORTANT NOTE
==============
This file has been generated from https://github.com/elastic/elasticsearch-net/tree/6.x/src/Tests/Tests/Aggregations/Metric/MedianAbsoluteDeviation/MedianAbsoluteDeviationAggregationUsageTests.cs.
If you wish to submit a PR for any spelling mistakes, typos or grammatical errors for this file,
please modify the original csharp file found at the link and submit the PR with that change. Thanks!
////

[[median-absolute-deviation-aggregation-usage]]
=== Median Absolute Deviation Aggregation Usage

A single-value aggregation that approximates the median absolute deviation of its search results.

Median absolute deviation is a measure of variability. It is a robust statistic, meaning that it is
useful for describing data that may have outliers, or may not be normally distributed.
For such data it can be more descriptive than standard deviation.

It is calculated as the median of each data point's deviation from the median of the
entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - Xi|)`.

Be sure to read the Elasticsearch documentation on {ref_current}/search-aggregations-metrics-median-absolute-deviation-aggregation.html[Median Absolute Deviation Aggregation]

==== Fluent DSL example

[source,csharp]
----
a => a
.Average("average_commits", avg => avg
.Field(p => p.NumberOfCommits)
)
.MedianAbsoluteDeviation("commit_variability", m => m
.Field(f => f.NumberOfCommits)
)
----

==== Object Initializer syntax example

[source,csharp]
----
new AverageAggregation("average_commits", Infer.Field<Project>(p => p.NumberOfCommits)) &&
new MedianAbsoluteDeviationAggregation("commit_variability", Infer.Field<Project>(p => p.NumberOfCommits))
----

[source,javascript]
.Example json output
----
{
"average_commits": {
"avg": {
"field": "numberOfCommits"
}
},
"commit_variability": {
"median_absolute_deviation": {
"field": "numberOfCommits"
}
}
}
----

==== Handling Responses

[source,csharp]
----
response.ShouldBeValid();
var medianAbsoluteDeviation = response.Aggregations.MedianAbsoluteDeviation("commit_variability");
medianAbsoluteDeviation.Should().NotBeNull();
medianAbsoluteDeviation.Value.Should().BeGreaterThan(0);
----

2 changes: 2 additions & 0 deletions src/Nest/Aggregations/AggregateDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ public CompositeBucketAggregate Composite(string key)

public MatrixStatsAggregate MatrixStats(string key) => TryGet<MatrixStatsAggregate>(key);

public ValueAggregate MedianAbsoluteDeviation(string key) => TryGet<ValueAggregate>(key);

private TAggregate TryGet<TAggregate>(string key)
where TAggregate : class, IAggregate
{
Expand Down
12 changes: 12 additions & 0 deletions src/Nest/Aggregations/AggregationContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ public interface IAggregationContainer
[JsonProperty("weighted_avg")]
IWeightedAverageAggregation WeightedAverage { get; set; }

[JsonProperty("median_absolute_deviation")]
IMedianAbsoluteDeviationAggregation MedianAbsoluteDeviation { get; set; }

void Accept(IAggregationVisitor visitor);
}

Expand Down Expand Up @@ -344,6 +347,8 @@ public class AggregationContainer : IAggregationContainer

public IWeightedAverageAggregation WeightedAverage { get; set; }

public IMedianAbsoluteDeviationAggregation MedianAbsoluteDeviation { get; set; }

public void Accept(IAggregationVisitor visitor)
{
if (visitor.Scope == AggregationVisitorScope.Unknown) visitor.Scope = AggregationVisitorScope.Aggregation;
Expand Down Expand Up @@ -485,6 +490,8 @@ public class AggregationContainerDescriptor<T> : DescriptorBase<AggregationConta

IWeightedAverageAggregation IAggregationContainer.WeightedAverage { get; set; }

IMedianAbsoluteDeviationAggregation IAggregationContainer.MedianAbsoluteDeviation { get; set; }

public void Accept(IAggregationVisitor visitor)
{
if (visitor.Scope == AggregationVisitorScope.Unknown) visitor.Scope = AggregationVisitorScope.Aggregation;
Expand Down Expand Up @@ -757,6 +764,11 @@ Func<WeightedAverageAggregationDescriptor<T>, IWeightedAverageAggregation> selec
) =>
_SetInnerAggregation(name, selector, (a, d) => a.WeightedAverage = d);

public AggregationContainerDescriptor<T> MedianAbsoluteDeviation(string name,
Func<MedianAbsoluteDeviationAggregationDescriptor<T>, IMedianAbsoluteDeviationAggregation> selector
) =>
_SetInnerAggregation(name, selector, (a, d) => a.MedianAbsoluteDeviation = d);

/// <summary>
/// Fluent methods do not assign to properties on `this` directly but on IAggregationContainers inside `this.Aggregations[string, IContainer]
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Newtonsoft.Json;

namespace Nest
{
/// <summary>
/// This single-value aggregation approximates the median absolute deviation of its search results.
///
/// Median absolute deviation is a measure of variability. It is a robust statistic, meaning that
/// it is useful for describing data that may have outliers, or may not be normally distributed.
/// For such data it can be more descriptive than standard deviation.
///
/// It is calculated as the median of each data point’s deviation from the median of the
/// entire sample. That is, for a random variable <code>X</code>, the median absolute deviation
/// is <code>median(|median(X) - Xi|).</code>
///
/// Be sure to read the Elasticsearch documentation on {ref_current}/search-aggregations-metrics-median-absolute-deviation-aggregation.html[Median Absolute Deviation Aggregation]
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
[ContractJsonConverter(typeof(AggregationJsonConverter<MedianAbsoluteDeviationAggregation>))]
public interface IMedianAbsoluteDeviationAggregation : IMetricAggregation
{
/// <summary>
/// TDigest algorithm component that controls memory usage and approximation error.
/// By increasing the compression value, you can increase the accuracy
/// at the cost of more memory. Larger compression values also make
/// the algorithm slower since the underlying tree data structure grows in
/// size, resulting in more expensive operations. The default compression value is <c>100</c>.
/// </summary>
[JsonProperty("compression")]
double? Compression { get; set; }
}

/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation"/>
public class MedianAbsoluteDeviationAggregation : MetricAggregationBase, IMedianAbsoluteDeviationAggregation
{
internal MedianAbsoluteDeviationAggregation() { }

public MedianAbsoluteDeviationAggregation(string name, Field field) : base(name, field) { }

/// <inheritdoc />
public double? Compression { get; set; }

internal override void WrapInContainer(AggregationContainer c) => c.MedianAbsoluteDeviation = this;
}

/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation"/>
public class MedianAbsoluteDeviationAggregationDescriptor<T>
: MetricAggregationDescriptorBase<MedianAbsoluteDeviationAggregationDescriptor<T>, IMedianAbsoluteDeviationAggregation, T>
, IMedianAbsoluteDeviationAggregation
where T : class
{
double? IMedianAbsoluteDeviationAggregation.Compression { get; set; }

/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation.Compression"/>
public MedianAbsoluteDeviationAggregationDescriptor<T> Compression(double? compression) => Assign(a => a.Compression = compression);
}
}
4 changes: 4 additions & 0 deletions src/Nest/Aggregations/Visitor/AggregationVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public interface IAggregationVisitor
void Visit(IGeoCentroidAggregation aggregation);

void Visit(ICompositeAggregation aggregation);

void Visit(IMedianAbsoluteDeviationAggregation aggregation);
}

public class AggregationVisitor : IAggregationVisitor
Expand Down Expand Up @@ -224,6 +226,8 @@ public virtual void Visit(IGeoCentroidAggregation aggregation) { }

public virtual void Visit(ICompositeAggregation aggregation) { }

public virtual void Visit(IMedianAbsoluteDeviationAggregation aggregation) { }

public virtual void Visit(IAggregation aggregation) { }

public virtual void Visit(IAggregationContainer aggregationContainer) { }
Expand Down
1 change: 1 addition & 0 deletions src/Nest/Aggregations/Visitor/AggregationWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public void Walk(IAggregationContainer aggregation, IAggregationVisitor visitor)
AcceptAggregation(aggregation.ValueCount, visitor, (v, d) => v.Visit(d));
AcceptAggregation(aggregation.GeoCentroid, visitor, (v, d) => v.Visit(d));
AcceptAggregation(aggregation.Composite, visitor, (v, d) => v.Visit(d));
AcceptAggregation(aggregation.MedianAbsoluteDeviation, visitor, (v, d) => v.Visit(d));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using Elastic.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;
using Tests.Core.Extensions;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Domain;
using Tests.Framework.Integration;

namespace Tests.Aggregations.Metric.MedianAbsoluteDeviation
{
/**
* A single-value aggregation that approximates the median absolute deviation of its search results.
*
* Median absolute deviation is a measure of variability. It is a robust statistic, meaning that it is
* useful for describing data that may have outliers, or may not be normally distributed.
* For such data it can be more descriptive than standard deviation.
*
* It is calculated as the median of each data point's deviation from the median of the
* entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - Xi|)`.
*/
[SkipVersion("<6.6.0", "Introduced in Elasticsearch 6.6.0")]
public class MedianAbsoluteDeviationAggregationUsageTests : AggregationUsageTestBase
{
public MedianAbsoluteDeviationAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usage) { }

protected override object AggregationJson => new
{
average_commits = new
{
avg = new
{
field = "numberOfCommits",
}
},
commit_variability = new
{
median_absolute_deviation = new
{
field = "numberOfCommits"
}
}
};

protected override Func<AggregationContainerDescriptor<Project>, IAggregationContainer> FluentAggs => a => a
.Average("average_commits", avg => avg
.Field(p => p.NumberOfCommits)
)
.MedianAbsoluteDeviation("commit_variability", m => m
.Field(f => f.NumberOfCommits)
);

protected override AggregationDictionary InitializerAggs =>
new AverageAggregation("average_commits", Infer.Field<Project>(p => p.NumberOfCommits)) &&
new MedianAbsoluteDeviationAggregation("commit_variability", Infer.Field<Project>(p => p.NumberOfCommits));

protected override void ExpectResponse(ISearchResponse<Project> response)
{
response.ShouldBeValid();
var medianAbsoluteDeviation = response.Aggregations.MedianAbsoluteDeviation("commit_variability");
medianAbsoluteDeviation.Should().NotBeNull();
medianAbsoluteDeviation.Value.Should().BeGreaterThan(0);
}
}
}

0 comments on commit 69ec076

Please sign in to comment.