Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/Add support for weighted average aggregation #197

Merged
merged 4 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -30,10 +30,10 @@
if (!isNil(field)) this._aggsDef.field = field;
}

// TODO: Investigate whether Metrics Aggregations can have sub aggregations

Check warning on line 33 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (10.x)

Unexpected 'todo' comment

Check warning on line 33 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (12.x)

Unexpected 'todo' comment

Check warning on line 33 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (14.x)

Unexpected 'todo' comment
// Hide setters for `aggs` and `aggregations` if required

// TODO: Investigate case when getters will be required

Check warning on line 36 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (10.x)

Unexpected 'todo' comment

Check warning on line 36 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (12.x)

Unexpected 'todo' comment

Check warning on line 36 in src/aggregations/metrics-aggregations/metrics-aggregation-base.js

View workflow job for this annotation

GitHub Actions / check (14.x)

Unexpected 'todo' comment

/**
* Sets field to run aggregation on.
Expand Down Expand Up @@ -75,7 +75,7 @@
}

/**
* 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;
57 changes: 57 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3843,6 +3843,63 @@ 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 {
atreids marked this conversation as resolved.
Show resolved Hide resolved
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
}

/**
* 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 @@ -104,7 +104,8 @@ const {
StatsAggregation,
SumAggregation,
TopHitsAggregation,
ValueCountAggregation
ValueCountAggregation,
WeightedAverageAggregation
},
bucketAggregations: {
AdjacencyMatrixAggregation,
Expand Down Expand Up @@ -343,6 +344,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
Loading