ExpressionFunctionDerivative
| |
| [font](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.font.md) | ExpressionFunctionFont
| |
| [moving\_average](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.moving_average.md) | ExpressionFunctionMovingAverage
| |
+| [overall\_metric](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.overall_metric.md) | ExpressionFunctionOverallMetric
| |
| [theme](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.theme.md) | ExpressionFunctionTheme
| |
| [var\_set](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.var_set.md) | ExpressionFunctionVarSet
| |
| [var](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.var.md) | ExpressionFunctionVar
| |
diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.overall_metric.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.overall_metric.md
new file mode 100644
index 0000000000000..8685788a2f351
--- /dev/null
+++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.overall_metric.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md) > [overall\_metric](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.overall_metric.md)
+
+## ExpressionFunctionDefinitions.overall\_metric property
+
+Signature:
+
+```typescript
+overall_metric: ExpressionFunctionOverallMetric;
+```
diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md
index 219678244951b..f55fed99e1d3d 100644
--- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md
+++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md
@@ -21,6 +21,7 @@ export interface ExpressionFunctionDefinitions
| [derivative](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.derivative.md) | ExpressionFunctionDerivative
| |
| [font](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.font.md) | ExpressionFunctionFont
| |
| [moving\_average](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.moving_average.md) | ExpressionFunctionMovingAverage
| |
+| [overall\_metric](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.overall_metric.md) | ExpressionFunctionOverallMetric
| |
| [theme](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.theme.md) | ExpressionFunctionTheme
| |
| [var\_set](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.var_set.md) | ExpressionFunctionVarSet
| |
| [var](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.var.md) | ExpressionFunctionVar
| |
diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.overall_metric.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.overall_metric.md
new file mode 100644
index 0000000000000..b8564a696e6e4
--- /dev/null
+++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.overall_metric.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md) > [overall\_metric](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.overall_metric.md)
+
+## ExpressionFunctionDefinitions.overall\_metric property
+
+Signature:
+
+```typescript
+overall_metric: ExpressionFunctionOverallMetric;
+```
diff --git a/src/dev/typescript/build_ts_refs.ts b/src/dev/typescript/build_ts_refs.ts
index 2e25827996e45..26425b7a3e61d 100644
--- a/src/dev/typescript/build_ts_refs.ts
+++ b/src/dev/typescript/build_ts_refs.ts
@@ -13,12 +13,20 @@ import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';
export const REF_CONFIG_PATHS = [Path.resolve(REPO_ROOT, 'tsconfig.refs.json')];
-export async function buildAllTsRefs(log: ToolingLog) {
+export async function buildAllTsRefs(log: ToolingLog): Promise<{ failed: boolean }> {
for (const path of REF_CONFIG_PATHS) {
const relative = Path.relative(REPO_ROOT, path);
log.debug(`Building TypeScript projects refs for ${relative}...`);
- await execa(require.resolve('typescript/bin/tsc'), ['-b', relative, '--pretty'], {
- cwd: REPO_ROOT,
- });
+ const { failed, stdout } = await execa(
+ require.resolve('typescript/bin/tsc'),
+ ['-b', relative, '--pretty'],
+ {
+ cwd: REPO_ROOT,
+ reject: false,
+ }
+ );
+ log.info(stdout);
+ if (failed) return { failed };
}
+ return { failed: false };
}
diff --git a/src/dev/typescript/run_type_check_cli.ts b/src/dev/typescript/run_type_check_cli.ts
index f95c230f44b9e..d9e9eb036fe0f 100644
--- a/src/dev/typescript/run_type_check_cli.ts
+++ b/src/dev/typescript/run_type_check_cli.ts
@@ -69,7 +69,11 @@ export async function runTypeCheckCli() {
process.exit();
}
- await buildAllTsRefs(log);
+ const { failed } = await buildAllTsRefs(log);
+ if (failed) {
+ log.error('Unable to build TS project refs');
+ process.exit(1);
+ }
const tscArgs = [
// composite project cannot be used with --noEmit
diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
index 2aa0d346afe34..523bbe1f01018 100644
--- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
+++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts
@@ -174,6 +174,57 @@ const nestedTermResponse = {
status: 200,
};
+const exhaustiveNestedTermResponse = {
+ took: 10,
+ timed_out: false,
+ _shards: {
+ total: 1,
+ successful: 1,
+ skipped: 0,
+ failed: 0,
+ },
+ hits: {
+ total: 14005,
+ max_score: 0,
+ hits: [],
+ },
+ aggregations: {
+ '1': {
+ doc_count_error_upper_bound: 0,
+ sum_other_doc_count: 8325,
+ buckets: [
+ {
+ '2': {
+ doc_count_error_upper_bound: 0,
+ sum_other_doc_count: 0,
+ buckets: [
+ { key: 'ios', doc_count: 2850 },
+ { key: 'win xp', doc_count: 2830 },
+ { key: '__missing__', doc_count: 1430 },
+ ],
+ },
+ key: 'US-with-dash',
+ doc_count: 2850,
+ },
+ {
+ '2': {
+ doc_count_error_upper_bound: 0,
+ sum_other_doc_count: 0,
+ buckets: [
+ { key: 'ios', doc_count: 1850 },
+ { key: 'win xp', doc_count: 1830 },
+ { key: '__missing__', doc_count: 130 },
+ ],
+ },
+ key: 'IN-with-dash',
+ doc_count: 2830,
+ },
+ ],
+ },
+ },
+ status: 200,
+};
+
const nestedTermResponseNoResults = {
took: 10,
timed_out: false,
@@ -326,6 +377,17 @@ describe('Terms Agg Other bucket helper', () => {
}
});
+ test('does not build query if sum_other_doc_count is 0 (exhaustive terms)', () => {
+ const aggConfigs = getAggConfigs(nestedTerm.aggs);
+ expect(
+ buildOtherBucketAgg(
+ aggConfigs,
+ aggConfigs.aggs[1] as IBucketAggConfig,
+ exhaustiveNestedTermResponse
+ )
+ ).toBeFalsy();
+ });
+
test('excludes exists filter for scripted fields', () => {
const aggConfigs = getAggConfigs(nestedTerm.aggs);
aggConfigs.aggs[1].params.field.scripted = true;
diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts
index 372d487bcf7a3..2a1cd873f6282 100644
--- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts
+++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts
@@ -156,6 +156,7 @@ export const buildOtherBucketAgg = (
};
let noAggBucketResults = false;
+ let exhaustiveBuckets = true;
// recursively create filters for all parent aggregation buckets
const walkBucketTree = (
@@ -175,6 +176,9 @@ export const buildOtherBucketAgg = (
const newAggIndex = aggIndex + 1;
const newAgg = bucketAggs[newAggIndex];
const currentAgg = bucketAggs[aggIndex];
+ if (aggIndex === index && agg && agg.sum_other_doc_count > 0) {
+ exhaustiveBuckets = false;
+ }
if (aggIndex < index) {
each(agg.buckets, (bucket: any, bucketObjKey) => {
const bucketKey = currentAgg.getKey(
@@ -223,7 +227,7 @@ export const buildOtherBucketAgg = (
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
// bail if there were no bucket results
- if (noAggBucketResults) {
+ if (noAggBucketResults || exhaustiveBuckets) {
return false;
}
diff --git a/src/plugins/expressions/common/expression_functions/specs/index.ts b/src/plugins/expressions/common/expression_functions/specs/index.ts
index 20a6f9aac4567..c6d89f41d0e0d 100644
--- a/src/plugins/expressions/common/expression_functions/specs/index.ts
+++ b/src/plugins/expressions/common/expression_functions/specs/index.ts
@@ -12,6 +12,7 @@ export * from './var_set';
export * from './var';
export * from './theme';
export * from './cumulative_sum';
+export * from './overall_metric';
export * from './derivative';
export * from './moving_average';
export * from './ui_setting';
diff --git a/src/plugins/expressions/common/expression_functions/specs/overall_metric.ts b/src/plugins/expressions/common/expression_functions/specs/overall_metric.ts
new file mode 100644
index 0000000000000..e42112d3a23ed
--- /dev/null
+++ b/src/plugins/expressions/common/expression_functions/specs/overall_metric.ts
@@ -0,0 +1,168 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { ExpressionFunctionDefinition } from '../types';
+import { Datatable } from '../../expression_types';
+import { buildResultColumns, getBucketIdentifier } from '../series_calculation_helpers';
+
+export interface OverallMetricArgs {
+ by?: string[];
+ inputColumnId: string;
+ outputColumnId: string;
+ outputColumnName?: string;
+ metric: 'sum' | 'min' | 'max' | 'average';
+}
+
+export type ExpressionFunctionOverallMetric = ExpressionFunctionDefinition<
+ 'overall_metric',
+ Datatable,
+ OverallMetricArgs,
+ Datatable
+>;
+
+function getValueAsNumberArray(value: unknown) {
+ if (Array.isArray(value)) {
+ return value.map((innerVal) => Number(innerVal));
+ } else {
+ return [Number(value)];
+ }
+}
+
+/**
+ * Calculates the overall metric of a specified column in the data table.
+ *
+ * Also supports multiple series in a single data table - use the `by` argument
+ * to specify the columns to split the calculation by.
+ * For each unique combination of all `by` columns a separate overall metric will be calculated.
+ * The order of rows won't be changed - this function is not modifying any existing columns, it's only
+ * adding the specified `outputColumnId` column to every row of the table without adding or removing rows.
+ *
+ * Behavior:
+ * * Will write the overall metric of `inputColumnId` into `outputColumnId`
+ * * If provided will use `outputColumnName` as name for the newly created column. Otherwise falls back to `outputColumnId`
+ * * Each cell will contain the calculated metric based on the values of all cells belonging to the current series.
+ *
+ * Edge cases:
+ * * Will return the input table if `inputColumnId` does not exist
+ * * Will throw an error if `outputColumnId` exists already in provided data table
+ * * If the row value contains `null` or `undefined`, it will be ignored and overwritten with the overall metric of
+ * all cells of the same series.
+ * * For all values besides `null` and `undefined`, the value will be cast to a number before it's added to the
+ * overall metric of the current series - if this results in `NaN` (like in case of objects), all cells of the
+ * current series will be set to `NaN`.
+ * * To determine separate series defined by the `by` columns, the values of these columns will be cast to strings
+ * before comparison. If the values are objects, the return value of their `toString` method will be used for comparison.
+ * Missing values (`null` and `undefined`) will be treated as empty strings.
+ */
+export const overallMetric: ExpressionFunctionOverallMetric = {
+ name: 'overall_metric',
+ type: 'datatable',
+
+ inputTypes: ['datatable'],
+
+ help: i18n.translate('expressions.functions.overallMetric.help', {
+ defaultMessage: 'Calculates the overall sum, min, max or average of a column in a data table',
+ }),
+
+ args: {
+ by: {
+ help: i18n.translate('expressions.functions.overallMetric.args.byHelpText', {
+ defaultMessage: 'Column to split the overall calculation by',
+ }),
+ multi: true,
+ types: ['string'],
+ required: false,
+ },
+ metric: {
+ help: i18n.translate('expressions.functions.overallMetric.metricHelpText', {
+ defaultMessage: 'Metric to calculate',
+ }),
+ types: ['string'],
+ options: ['sum', 'min', 'max', 'average'],
+ },
+ inputColumnId: {
+ help: i18n.translate('expressions.functions.overallMetric.args.inputColumnIdHelpText', {
+ defaultMessage: 'Column to calculate the overall metric of',
+ }),
+ types: ['string'],
+ required: true,
+ },
+ outputColumnId: {
+ help: i18n.translate('expressions.functions.overallMetric.args.outputColumnIdHelpText', {
+ defaultMessage: 'Column to store the resulting overall metric in',
+ }),
+ types: ['string'],
+ required: true,
+ },
+ outputColumnName: {
+ help: i18n.translate('expressions.functions.overallMetric.args.outputColumnNameHelpText', {
+ defaultMessage: 'Name of the column to store the resulting overall metric in',
+ }),
+ types: ['string'],
+ required: false,
+ },
+ },
+
+ fn(input, { by, inputColumnId, outputColumnId, outputColumnName, metric }) {
+ const resultColumns = buildResultColumns(
+ input,
+ outputColumnId,
+ inputColumnId,
+ outputColumnName
+ );
+
+ if (!resultColumns) {
+ return input;
+ }
+
+ const accumulators: Partial
+
+
+
{content}
) : isOverflow == null || isOverflow === true ? ( -