[ES|QL] Add weighted_avg ES|QL function support (#187439)

## Summary

- Adds `weighted_avg` function definition
- Adds basic smoke tests


### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Vadim Kibana 2024-07-03 11:04:12 +02:00 committed by GitHub
parent ce4f4693f4
commit 7e04249054
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 401 additions and 0 deletions

View file

@ -264,4 +264,39 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
`from employees | stats date = top(hire_date, 2, "asc"), double = top(salary_change, 2, "asc"),`,
],
},
{
name: 'weighted_avg',
type: 'agg',
description: i18n.translate(
'kbn-esql-validation-autocomplete.esql.definitions.weightedAvgDoc',
{
defaultMessage:
'An aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.',
}
),
supportedCommands: ['stats', 'metrics'],
signatures: [
{
params: [
{
name: 'number',
type: 'number',
noNestingFunctions: true,
optional: false,
},
{
name: 'weight',
type: 'number',
noNestingFunctions: true,
optional: false,
},
],
returnType: 'number',
},
],
examples: [
`from employees | stats w_avg = weighted_avg(salary, height) by languages | eval w_avg = round(w_avg)`,
`from employees | stats w_avg_1 = weighted_avg(salary, 1), avg = avg(salary), w_avg_2 = weighted_avg(salary, height)`,
],
},
]);

View file

@ -26061,6 +26061,36 @@
],
"warning": []
},
{
"query": "from a_index | stats var = top(stringField, 5, \"asc\")",
"error": [],
"warning": []
},
{
"query": "from a_index | stats top(stringField, 5, \"asc\")",
"error": [],
"warning": []
},
{
"query": "from a_index | stats top(stringField, numberField, \"asc\")",
"error": [
"Argument of [top] must be a constant, received [numberField]"
],
"warning": []
},
{
"query": "from a_index | stats top(null, null, null)",
"error": [],
"warning": []
},
{
"query": "row nullVar = null | stats top(nullVar, nullVar, nullVar)",
"error": [
"Argument of [top] must be a constant, received [nullVar]",
"Argument of [top] must be a constant, received [nullVar]"
],
"warning": []
},
{
"query": "row var = st_distance(to_cartesianpoint(\"POINT (30 10)\"), to_cartesianpoint(\"POINT (30 10)\"))",
"error": [],
@ -26159,6 +26189,184 @@
"error": [],
"warning": []
},
{
"query": "from a_index | stats var = weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var = round(weighted_avg(numberField, numberField))",
"error": [],
"warning": []
},
{
"query": "from a_index | stats round(weighted_avg(numberField, numberField))",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var = round(weighted_avg(numberField, numberField)) + weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats round(weighted_avg(numberField, numberField)) + weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(numberField / 2, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var0 = weighted_avg(numberField / 2, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), weighted_avg(numberField / 2, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), var0 = weighted_avg(numberField / 2, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var0 = weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(numberField, numberField) by round(numberField / 2)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2)",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), weighted_avg(numberField, numberField) by round(numberField / 2), ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2), ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), weighted_avg(numberField, numberField) by round(numberField / 2), numberField / 2",
"error": [],
"warning": []
},
{
"query": "from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2), numberField / 2",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var = weighted_avg(avg(numberField), avg(numberField))",
"error": [
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]"
],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(avg(numberField), avg(numberField))",
"error": [
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]"
],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(booleanField, booleanField)",
"error": [
"Argument of [weighted_avg] must be [number], found value [booleanField] type [boolean]",
"Argument of [weighted_avg] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | sort weighted_avg(numberField, numberField)",
"error": [
"SORT does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | where weighted_avg(numberField, numberField)",
"error": [
"WHERE does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | where weighted_avg(numberField, numberField) > 0",
"error": [
"WHERE does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | eval var = weighted_avg(numberField, numberField)",
"error": [
"EVAL does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | eval var = weighted_avg(numberField, numberField) > 0",
"error": [
"EVAL does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | eval weighted_avg(numberField, numberField)",
"error": [
"EVAL does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | eval weighted_avg(numberField, numberField) > 0",
"error": [
"EVAL does not support function weighted_avg"
],
"warning": []
},
{
"query": "from a_index | stats weighted_avg(null, null)",
"error": [],
"warning": []
},
{
"query": "row nullVar = null | stats weighted_avg(nullVar, nullVar)",
"error": [],
"warning": []
},
{
"query": "f",
"error": [

View file

@ -10253,6 +10253,18 @@ describe('validation logic', () => {
testErrorsAndWarnings('from a_index | eval top(stringField, 5, "asc") > 0', [
'EVAL does not support function top',
]);
testErrorsAndWarnings('from a_index | stats var = top(stringField, 5, "asc")', []);
testErrorsAndWarnings('from a_index | stats top(stringField, 5, "asc")', []);
testErrorsAndWarnings('from a_index | stats top(stringField, numberField, "asc")', [
'Argument of [top] must be a constant, received [numberField]',
]);
testErrorsAndWarnings('from a_index | stats top(null, null, null)', []);
testErrorsAndWarnings('row nullVar = null | stats top(nullVar, nullVar, nullVar)', [
'Argument of [top] must be a constant, received [nullVar]',
'Argument of [top] must be a constant, received [nullVar]',
]);
});
describe('st_distance', () => {
@ -10335,6 +10347,152 @@ describe('validation logic', () => {
testErrorsAndWarnings('from a_index | eval st_distance(null, null)', []);
testErrorsAndWarnings('row nullVar = null | eval st_distance(nullVar, nullVar)', []);
});
describe('weighted_avg', () => {
testErrorsAndWarnings(
'from a_index | stats var = weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings('from a_index | stats weighted_avg(numberField, numberField)', []);
testErrorsAndWarnings(
'from a_index | stats var = round(weighted_avg(numberField, numberField))',
[]
);
testErrorsAndWarnings(
'from a_index | stats round(weighted_avg(numberField, numberField))',
[]
);
testErrorsAndWarnings(
'from a_index | stats var = round(weighted_avg(numberField, numberField)) + weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats round(weighted_avg(numberField, numberField)) + weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats weighted_avg(numberField / 2, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats var0 = weighted_avg(numberField / 2, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), weighted_avg(numberField / 2, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), var0 = weighted_avg(numberField / 2, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats var0 = weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField)',
[]
);
testErrorsAndWarnings(
'from a_index | stats weighted_avg(numberField, numberField) by round(numberField / 2)',
[]
);
testErrorsAndWarnings(
'from a_index | stats var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2)',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), weighted_avg(numberField, numberField) by round(numberField / 2), ipField',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2), ipField',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), weighted_avg(numberField, numberField) by round(numberField / 2), numberField / 2',
[]
);
testErrorsAndWarnings(
'from a_index | stats avg(numberField), var0 = weighted_avg(numberField, numberField) by var1 = round(numberField / 2), numberField / 2',
[]
);
testErrorsAndWarnings(
'from a_index | stats var = weighted_avg(avg(numberField), avg(numberField))',
[
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
]
);
testErrorsAndWarnings(
'from a_index | stats weighted_avg(avg(numberField), avg(numberField))',
[
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
"Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]",
]
);
testErrorsAndWarnings('from a_index | stats weighted_avg(booleanField, booleanField)', [
'Argument of [weighted_avg] must be [number], found value [booleanField] type [boolean]',
'Argument of [weighted_avg] must be [number], found value [booleanField] type [boolean]',
]);
testErrorsAndWarnings('from a_index | sort weighted_avg(numberField, numberField)', [
'SORT does not support function weighted_avg',
]);
testErrorsAndWarnings('from a_index | where weighted_avg(numberField, numberField)', [
'WHERE does not support function weighted_avg',
]);
testErrorsAndWarnings('from a_index | where weighted_avg(numberField, numberField) > 0', [
'WHERE does not support function weighted_avg',
]);
testErrorsAndWarnings('from a_index | eval var = weighted_avg(numberField, numberField)', [
'EVAL does not support function weighted_avg',
]);
testErrorsAndWarnings(
'from a_index | eval var = weighted_avg(numberField, numberField) > 0',
['EVAL does not support function weighted_avg']
);
testErrorsAndWarnings('from a_index | eval weighted_avg(numberField, numberField)', [
'EVAL does not support function weighted_avg',
]);
testErrorsAndWarnings('from a_index | eval weighted_avg(numberField, numberField) > 0', [
'EVAL does not support function weighted_avg',
]);
testErrorsAndWarnings('from a_index | stats weighted_avg(null, null)', []);
testErrorsAndWarnings('row nullVar = null | stats weighted_avg(nullVar, nullVar)', []);
});
});
});