Skip to content

Commit 0eed92a

Browse files
committed
Add Median Absolute Deviation Aggregation (#3627)
Relates: #3615
1 parent 5eb459b commit 0eed92a

File tree

8 files changed

+222
-0
lines changed

8 files changed

+222
-0
lines changed

docs/aggregations.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ The values are typically extracted from the fields of the document (using the fi
4646

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

49+
* <<median-absolute-deviation-aggregation-usage,Median Absolute Deviation Aggregation Usage>>
50+
4951
* <<min-aggregation-usage,Min Aggregation Usage>>
5052

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

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

85+
include::aggregations/metric/median-absolute-deviation/median-absolute-deviation-aggregation-usage.asciidoc[]
86+
8387
include::aggregations/metric/min/min-aggregation-usage.asciidoc[]
8488

8589
include::aggregations/metric/percentile-ranks/percentile-ranks-aggregation-usage.asciidoc[]
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
:ref_current: https://www.elastic.co/guide/en/elasticsearch/reference/6.7
2+
3+
:github: https://github.com/elastic/elasticsearch-net
4+
5+
:nuget: https://www.nuget.org/packages
6+
7+
////
8+
IMPORTANT NOTE
9+
==============
10+
This file has been generated from https://github.com/elastic/elasticsearch-net/tree/6.x/src/Tests/Tests/Aggregations/Metric/MedianAbsoluteDeviation/MedianAbsoluteDeviationAggregationUsageTests.cs.
11+
If you wish to submit a PR for any spelling mistakes, typos or grammatical errors for this file,
12+
please modify the original csharp file found at the link and submit the PR with that change. Thanks!
13+
////
14+
15+
[[median-absolute-deviation-aggregation-usage]]
16+
=== Median Absolute Deviation Aggregation Usage
17+
18+
A single-value aggregation that approximates the median absolute deviation of its search results.
19+
20+
Median absolute deviation is a measure of variability. It is a robust statistic, meaning that it is
21+
useful for describing data that may have outliers, or may not be normally distributed.
22+
For such data it can be more descriptive than standard deviation.
23+
24+
It is calculated as the median of each data point's deviation from the median of the
25+
entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - Xi|)`.
26+
27+
Be sure to read the Elasticsearch documentation on {ref_current}/search-aggregations-metrics-median-absolute-deviation-aggregation.html[Median Absolute Deviation Aggregation]
28+
29+
==== Fluent DSL example
30+
31+
[source,csharp]
32+
----
33+
a => a
34+
.Average("average_commits", avg => avg
35+
.Field(p => p.NumberOfCommits)
36+
)
37+
.MedianAbsoluteDeviation("commit_variability", m => m
38+
.Field(f => f.NumberOfCommits)
39+
)
40+
----
41+
42+
==== Object Initializer syntax example
43+
44+
[source,csharp]
45+
----
46+
new AverageAggregation("average_commits", Infer.Field<Project>(p => p.NumberOfCommits)) &&
47+
new MedianAbsoluteDeviationAggregation("commit_variability", Infer.Field<Project>(p => p.NumberOfCommits))
48+
----
49+
50+
[source,javascript]
51+
.Example json output
52+
----
53+
{
54+
"average_commits": {
55+
"avg": {
56+
"field": "numberOfCommits"
57+
}
58+
},
59+
"commit_variability": {
60+
"median_absolute_deviation": {
61+
"field": "numberOfCommits"
62+
}
63+
}
64+
}
65+
----
66+
67+
==== Handling Responses
68+
69+
[source,csharp]
70+
----
71+
response.ShouldBeValid();
72+
var medianAbsoluteDeviation = response.Aggregations.MedianAbsoluteDeviation("commit_variability");
73+
medianAbsoluteDeviation.Should().NotBeNull();
74+
medianAbsoluteDeviation.Value.Should().BeGreaterThan(0);
75+
----
76+

src/Nest/Aggregations/AggregateDictionary.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ public CompositeBucketAggregate Composite(string key)
210210

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

213+
public ValueAggregate MedianAbsoluteDeviation(string key) => TryGet<ValueAggregate>(key);
214+
213215
private TAggregate TryGet<TAggregate>(string key)
214216
where TAggregate : class, IAggregate
215217
{

src/Nest/Aggregations/AggregationContainer.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ public interface IAggregationContainer
247247
[DataMember(Name = "weighted_avg")]
248248
IWeightedAverageAggregation WeightedAverage { get; set; }
249249

250+
[DataMember(Name = "median_absolute_deviation")]
251+
IMedianAbsoluteDeviationAggregation MedianAbsoluteDeviation { get; set; }
252+
250253
void Accept(IAggregationVisitor visitor);
251254
}
252255

@@ -356,6 +359,8 @@ public class AggregationContainer : IAggregationContainer
356359

357360
public IWeightedAverageAggregation WeightedAverage { get; set; }
358361

362+
public IMedianAbsoluteDeviationAggregation MedianAbsoluteDeviation { get; set; }
363+
359364
public void Accept(IAggregationVisitor visitor)
360365
{
361366
if (visitor.Scope == AggregationVisitorScope.Unknown) visitor.Scope = AggregationVisitorScope.Aggregation;
@@ -497,6 +502,8 @@ public class AggregationContainerDescriptor<T> : DescriptorBase<AggregationConta
497502

498503
IWeightedAverageAggregation IAggregationContainer.WeightedAverage { get; set; }
499504

505+
IMedianAbsoluteDeviationAggregation IAggregationContainer.MedianAbsoluteDeviation { get; set; }
506+
500507
public void Accept(IAggregationVisitor visitor)
501508
{
502509
if (visitor.Scope == AggregationVisitorScope.Unknown) visitor.Scope = AggregationVisitorScope.Aggregation;
@@ -769,6 +776,11 @@ Func<WeightedAverageAggregationDescriptor<T>, IWeightedAverageAggregation> selec
769776
) =>
770777
_SetInnerAggregation(name, selector, (a, d) => a.WeightedAverage = d);
771778

779+
public AggregationContainerDescriptor<T> MedianAbsoluteDeviation(string name,
780+
Func<MedianAbsoluteDeviationAggregationDescriptor<T>, IMedianAbsoluteDeviationAggregation> selector
781+
) =>
782+
_SetInnerAggregation(name, selector, (a, d) => a.MedianAbsoluteDeviation = d);
783+
772784
/// <summary>
773785
/// Fluent methods do not assign to properties on `this` directly but on IAggregationContainers inside
774786
/// `this.Aggregations[string, IContainer]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System.Runtime.Serialization;
2+
using Elasticsearch.Net;
3+
4+
namespace Nest
5+
{
6+
/// <summary>
7+
/// This single-value aggregation approximates the median absolute deviation of its search results.
8+
///
9+
/// Median absolute deviation is a measure of variability. It is a robust statistic, meaning that
10+
/// it is useful for describing data that may have outliers, or may not be normally distributed.
11+
/// For such data it can be more descriptive than standard deviation.
12+
///
13+
/// It is calculated as the median of each data point’s deviation from the median of the
14+
/// entire sample. That is, for a random variable <code>X</code>, the median absolute deviation
15+
/// is <code>median(|median(X) - Xi|).</code>
16+
/// </summary>
17+
[InterfaceDataContract]
18+
[ReadAs(typeof(MedianAbsoluteDeviationAggregation))]
19+
public interface IMedianAbsoluteDeviationAggregation : IMetricAggregation
20+
{
21+
/// <summary>
22+
/// TDigest algorithm component that controls memory usage and approximation error.
23+
/// By increasing the compression value, you can increase the accuracy
24+
/// at the cost of more memory. Larger compression values also make
25+
/// the algorithm slower since the underlying tree data structure grows in
26+
/// size, resulting in more expensive operations. The default compression value is <c>100</c>.
27+
/// </summary>
28+
[DataMember(Name = "compression")]
29+
double? Compression { get; set; }
30+
}
31+
32+
/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation"/>
33+
public class MedianAbsoluteDeviationAggregation : MetricAggregationBase, IMedianAbsoluteDeviationAggregation
34+
{
35+
internal MedianAbsoluteDeviationAggregation() { }
36+
37+
public MedianAbsoluteDeviationAggregation(string name, Field field) : base(name, field) { }
38+
39+
/// <inheritdoc />
40+
public double? Compression { get; set; }
41+
42+
internal override void WrapInContainer(AggregationContainer c) => c.MedianAbsoluteDeviation = this;
43+
}
44+
45+
/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation"/>
46+
public class MedianAbsoluteDeviationAggregationDescriptor<T>
47+
: MetricAggregationDescriptorBase<MedianAbsoluteDeviationAggregationDescriptor<T>, IMedianAbsoluteDeviationAggregation, T>
48+
, IMedianAbsoluteDeviationAggregation
49+
where T : class
50+
{
51+
double? IMedianAbsoluteDeviationAggregation.Compression { get; set; }
52+
53+
/// <inheritdoc cref="IMedianAbsoluteDeviationAggregation.Compression"/>
54+
public MedianAbsoluteDeviationAggregationDescriptor<T> Compression(double? compression) => Assign(compression, (a, v) => a.Compression = v);
55+
}
56+
}

src/Nest/Aggregations/Visitor/AggregationVisitor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ public interface IAggregationVisitor
119119
void Visit(IGeoCentroidAggregation aggregation);
120120

121121
void Visit(ICompositeAggregation aggregation);
122+
123+
void Visit(IMedianAbsoluteDeviationAggregation aggregation);
122124
}
123125

124126
public class AggregationVisitor : IAggregationVisitor
@@ -223,6 +225,8 @@ public virtual void Visit(IGeoCentroidAggregation aggregation) { }
223225

224226
public virtual void Visit(ICompositeAggregation aggregation) { }
225227

228+
public virtual void Visit(IMedianAbsoluteDeviationAggregation aggregation) { }
229+
226230
public virtual void Visit(IAggregation aggregation) { }
227231

228232
public virtual void Visit(IAggregationContainer aggregationContainer) { }

src/Nest/Aggregations/Visitor/AggregationWalker.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ public void Walk(IAggregationContainer aggregation, IAggregationVisitor visitor)
160160
AcceptAggregation(aggregation.ValueCount, visitor, (v, d) => v.Visit(d));
161161
AcceptAggregation(aggregation.GeoCentroid, visitor, (v, d) => v.Visit(d));
162162
AcceptAggregation(aggregation.Composite, visitor, (v, d) => v.Visit(d));
163+
AcceptAggregation(aggregation.MedianAbsoluteDeviation, visitor, (v, d) => v.Visit(d));
163164
}
164165
}
165166
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using Elastic.Xunit.XunitPlumbing;
3+
using FluentAssertions;
4+
using Nest;
5+
using Tests.Core.Extensions;
6+
using Tests.Core.ManagedElasticsearch.Clusters;
7+
using Tests.Domain;
8+
using Tests.Framework.Integration;
9+
10+
namespace Tests.Aggregations.Metric.MedianAbsoluteDeviation
11+
{
12+
/**
13+
* A single-value aggregation that approximates the median absolute deviation of its search results.
14+
*
15+
* Median absolute deviation is a measure of variability. It is a robust statistic, meaning that it is
16+
* useful for describing data that may have outliers, or may not be normally distributed.
17+
* For such data it can be more descriptive than standard deviation.
18+
*
19+
* It is calculated as the median of each data point's deviation from the median of the
20+
* entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - Xi|)`.
21+
*
22+
* Be sure to read the Elasticsearch documentation on {ref_current}/search-aggregations-metrics-median-absolute-deviation-aggregation.html[Median Absolute Deviation Aggregation]
23+
*/
24+
[SkipVersion("<6.6.0", "Introduced in Elasticsearch 6.6.0")]
25+
public class MedianAbsoluteDeviationAggregationUsageTests : AggregationUsageTestBase
26+
{
27+
public MedianAbsoluteDeviationAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usage) { }
28+
29+
protected override object AggregationJson => new
30+
{
31+
average_commits = new
32+
{
33+
avg = new
34+
{
35+
field = "numberOfCommits",
36+
}
37+
},
38+
commit_variability = new
39+
{
40+
median_absolute_deviation = new
41+
{
42+
field = "numberOfCommits"
43+
}
44+
}
45+
};
46+
47+
protected override Func<AggregationContainerDescriptor<Project>, IAggregationContainer> FluentAggs => a => a
48+
.Average("average_commits", avg => avg
49+
.Field(p => p.NumberOfCommits)
50+
)
51+
.MedianAbsoluteDeviation("commit_variability", m => m
52+
.Field(f => f.NumberOfCommits)
53+
);
54+
55+
protected override AggregationDictionary InitializerAggs =>
56+
new AverageAggregation("average_commits", Infer.Field<Project>(p => p.NumberOfCommits)) &&
57+
new MedianAbsoluteDeviationAggregation("commit_variability", Infer.Field<Project>(p => p.NumberOfCommits));
58+
59+
protected override void ExpectResponse(SearchResponse<Project> response)
60+
{
61+
response.ShouldBeValid();
62+
var medianAbsoluteDeviation = response.Aggregations.MedianAbsoluteDeviation("commit_variability");
63+
medianAbsoluteDeviation.Should().NotBeNull();
64+
medianAbsoluteDeviation.Value.Should().BeGreaterThan(0);
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)