Skip to content

Commit

Permalink
feat: Add support for weighted average aggregation (#197)
Browse files Browse the repository at this point in the history
Weighted avg aggregation was added in Elasticsearch 6.4.
  • Loading branch information
atreids authored Mar 10, 2024
1 parent 70fcf8d commit 3de7f2d
Show file tree
Hide file tree
Showing 6 changed files with 461 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/aggregations/metrics-aggregations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ exports.StatsAggregation = require('./stats-aggregation');
exports.SumAggregation = require('./sum-aggregation');
exports.TopHitsAggregation = require('./top-hits-aggregation');
exports.ValueCountAggregation = require('./value-count-aggregation');
exports.WeightedAverageAggregation = require('./weighted-average-aggregation');
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class MetricsAggregationBase extends Aggregation {
}

/**
* Sets the missing parameter ehich defines how documents
* Sets the missing parameter which defines how documents
* that are missing a value should be treated.
*
* @example
Expand Down
171 changes: 171 additions & 0 deletions src/aggregations/metrics-aggregations/weighted-average-aggregation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
'use strict';

const { Script } = require('../../core');
const MetricsAggregationBase = require('./metrics-aggregation-base');
const isNil = require('lodash.isnil');

const ES_REF_URL =
'https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-weight-avg-aggregation.html';

/**
* A single-value metrics aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.
* These values can be extracted either from specific numeric fields in the documents.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-weight-avg-aggregation.html)
*
* Added in Elasticsearch v6.4.0
* [Release notes](https://www.elastic.co/guide/en/elasticsearch/reference/6.4/release-notes-6.4.0.html)
*
* As a formula, a weighted average is ∑(value * weight) / ∑(weight)
*
* @example
* // Compute the average grade over all documents, weighing by teacher score.
* const agg = esb.weightedAverageAggregation('avg_grade', 'grade', 'teacher_score');
*
* @example
* // Compute the average grade where the weight is calculated by a script.
* // Filling in missing values as '10'.
* const agg = esb.weightedAverageAggregation('avg_grade', 'grade')
* .weight(esb.script('inline', "doc['teacher_score'].value").lang('painless'), 10)
* );
*
* @example
* // Compute the average grade, weighted by teacher score, filling in missing values.
* const agg = esb.weightedAverageAggregation('avg_grade').value('grade', 5).weight('teacher_score', 10));
*
* @example
* // Compute the average grade over all documents, weighing by teacher score.
* const agg = esb.weightedAverageAggregation('avg_grade').value('grade').weight('teacher_score');
*
*
* @param {string} name The name which will be used to refer to this aggregation.
* @param {string=} value The field or script to use as the value
* @param {string=} weight The field or script to use as the weight
*
* @extends MetricsAggregationBase
*/
class WeightedAverageAggregation extends MetricsAggregationBase {
/**
* Creates an instance of `WeightedAverageAggregation`
*
* @param {string} name The name which will be used to refer to this aggregation.
* @param {string=} value The field or script to be used as the value.
* @param {string=} weight The field or script to be used as the weighting.
*/
constructor(name, value, weight) {
super(name, 'weighted_avg');

this._aggsDef.value = {};
this._aggsDef.weight = {};

if (!isNil(value)) {
this.value(value);
}

if (!isNil(weight)) {
this.weight(weight);
}
}

/**
* Sets the value
*
* @param {string | Script} value Field name or script to use as the value.
*
* @param {number=} missing Sets the missing parameter which defines how documents
* that are missing a value should be treated.
* @returns {WeightedAverageAggregation} returns `this` so that calls can be chained
*/
value(value, missing) {
if (typeof value !== 'string' && !(value instanceof Script)) {
throw new TypeError(
'Value must be either a string or instanceof Script'
);
}

if (value instanceof Script) {
if (this._aggsDef.value.field) {
delete this._aggsDef.value.field;
}
this._aggsDef.value.script = value;
} else {
if (this._aggsDef.value.script) {
delete this._aggsDef.value.script;
}
this._aggsDef.value.field = value;
}

if (!isNil(missing)) {
this._aggsDef.value.missing = missing;
}

return this;
}

/**
* Sets the weight
*
* @param {string | Script} weight Field name or script to use as the weight.
* @param {number=} missing Sets the missing parameter which defines how documents
* that are missing a value should be treated.
* @returns {WeightedAverageAggregation} returns `this` so that calls can be chained
*/
weight(weight, missing) {
if (typeof weight !== 'string' && !(weight instanceof Script)) {
throw new TypeError(
'Weight must be either a string or instanceof Script'
);
}

if (weight instanceof Script) {
if (this._aggsDef.weight.field) {
delete this._aggsDef.weight.field;
}
this._aggsDef.weight.script = weight;
} else {
if (this._aggsDef.weight.script) {
delete this._aggsDef.weight.script;
}
this._aggsDef.weight.field = weight;
}

if (!isNil(missing)) {
this._aggsDef.weight.missing = missing;
}

return this;
}

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
script() {
console.log(`Please refer ${ES_REF_URL}`);
throw new Error(
'script is not supported in WeightedAverageAggregation'
);
}

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
missing() {
console.log(`Please refer ${ES_REF_URL}`);
throw new Error(
'missing is not supported in WeightedAverageAggregation'
);
}

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
field() {
console.log(`Please refer ${ES_REF_URL}`);
throw new Error('field is not supported in WeightedAverageAggregation');
}
}

module.exports = WeightedAverageAggregation;
75 changes: 75 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3843,6 +3843,81 @@ declare namespace esb {
field?: string
): AvgAggregation;

/**
* A single-value metrics aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.
* These values can be extracted either from specific numeric fields in the documents.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-weight-avg-aggregation.html)
*
* Added in Elasticsearch v6.4.0
* [Release notes](https://www.elastic.co/guide/en/elasticsearch/reference/6.4/release-notes-6.4.0.html)
*
* @param {string} name The name which will be used to refer to this aggregation.
* @param {string=} value The field or script to be used as the value.
* @param {string | Script =} weight The field or script to be used as the weighting.
* @extends MetricsAggregationBase
*/
export class WeightedAverageAggregation extends MetricsAggregationBase {
constructor(name: string, value?: string | Script, weight?: string | Script);

/**
* Sets the value
*
* @param {string | Script} value Field name or script to be used as the value
* @param {number=} missing Sets the missing parameter which defines how documents
* that are missing a value should be treated.
* @return {WeightedAverageAggregation} returns `this` so that calls can be chained
*/
value(value: string | Script, missing?: number): WeightedAverageAggregation

/**
* Sets the weight
*
* @param {string | Script} weight Field name or script to be used as the weight
* @param {number=} missing Sets the missing parameter which defines how documents
* that are missing a value should be treated.
* @return {WeightedAverageAggregation} returns `this` so that calls can be chained
*/
weight(weight: string | Script, missing?: number): WeightedAverageAggregation

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
script(): never;

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
missing(): never;

/**
* @override
* @throws {Error} This method cannot be called on WeightedAverageAggregation
*/
field(): never;
}

/**
* A single-value metrics aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.
* These values can be extracted either from specific numeric fields in the documents.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-weight-avg-aggregation.html)
*
* Added in Elasticsearch v6.4.0
* [Release notes](https://www.elastic.co/guide/en/elasticsearch/reference/6.4/release-notes-6.4.0.html)
*
* @param {string} name The name which will be used to refer to this aggregation.
* @param {string | Script =} value The field or script to be used as the value.
* @param {string | Script =} weight The field or script to be used as the weighting.
*/
export function weightedAverageAggregation(
name: string,
value?: string | Script,
weight?: string | Script
): WeightedAverageAggregation;

/**
* A single-value metrics aggregation that calculates an approximate count of
* distinct values. Values can be extracted either from specific fields in the
Expand Down
8 changes: 7 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ const {
StatsAggregation,
SumAggregation,
TopHitsAggregation,
ValueCountAggregation
ValueCountAggregation,
WeightedAverageAggregation
},
bucketAggregations: {
AdjacencyMatrixAggregation,
Expand Down Expand Up @@ -347,6 +348,11 @@ exports.spanFieldMaskingQuery = constructorWrapper(SpanFieldMaskingQuery);
exports.AvgAggregation = AvgAggregation;
exports.avgAggregation = constructorWrapper(AvgAggregation);

exports.WeightedAverageAggregation = WeightedAverageAggregation;
exports.weightedAverageAggregation = constructorWrapper(
WeightedAverageAggregation
);

exports.CardinalityAggregation = CardinalityAggregation;
exports.cardinalityAggregation = constructorWrapper(CardinalityAggregation);

Expand Down
Loading

0 comments on commit 3de7f2d

Please sign in to comment.