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

[AggConfigs] Add TopMetrics agg #125936

Merged
merged 2 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from all 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 packages/kbn-doc-links/src/get_doc_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => {
std_dev: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-extendedstats-aggregation.html`,
sum: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-sum-aggregation.html`,
top_hits: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-top-hits-aggregation.html`,
top_metrics: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-top-metrics.html`,
},
runtimeFields: {
overview: `${ELASTICSEARCH_DOCS}runtime.html`,
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/common/search/aggs/agg_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const getAggTypes = () => ({
{ name: METRIC_TYPES.PERCENTILES, fn: metrics.getPercentilesMetricAgg },
{ name: METRIC_TYPES.PERCENTILE_RANKS, fn: metrics.getPercentileRanksMetricAgg },
{ name: METRIC_TYPES.TOP_HITS, fn: metrics.getTopHitMetricAgg },
{ name: METRIC_TYPES.TOP_METRICS, fn: metrics.getTopMetricsMetricAgg },
{ name: METRIC_TYPES.DERIVATIVE, fn: metrics.getDerivativeMetricAgg },
{ name: METRIC_TYPES.CUMULATIVE_SUM, fn: metrics.getCumulativeSumMetricAgg },
{ name: METRIC_TYPES.MOVING_FN, fn: metrics.getMovingAvgMetricAgg },
Expand Down Expand Up @@ -109,4 +110,5 @@ export const getAggTypesFunctions = () => [
metrics.aggStdDeviation,
metrics.aggSum,
metrics.aggTopHit,
metrics.aggTopMetrics,
];
2 changes: 2 additions & 0 deletions src/plugins/data/common/search/aggs/aggs_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ describe('Aggs service', () => {
"percentiles",
"percentile_ranks",
"top_hits",
"top_metrics",
"derivative",
"cumulative_sum",
"moving_avg",
Expand Down Expand Up @@ -147,6 +148,7 @@ describe('Aggs service', () => {
"percentiles",
"percentile_ranks",
"top_hits",
"top_metrics",
"derivative",
"cumulative_sum",
"moving_avg",
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/common/search/aggs/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ export * from './sum_fn';
export * from './sum';
export * from './top_hit_fn';
export * from './top_hit';
export * from './top_metrics';
export * from './top_metrics_fn';
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { parentPipelineAggWriter } from './parent_pipeline_agg_writer';

const metricAggFilter = [
'!top_hits',
'!top_metrics',
'!percentiles',
'!percentile_ranks',
'!median',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type';

const metricAggFilter: string[] = [
'!top_hits',
'!top_metrics',
'!percentiles',
'!percentile_ranks',
'!median',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface MetricAggParam<TMetricAggConfig extends AggConfig>
extends AggParamType<TMetricAggConfig> {
filterFieldTypes?: FieldTypes;
onlyAggregatable?: boolean;
scriptable?: boolean;
}

const metricType = 'metrics';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum METRIC_TYPES {
SERIAL_DIFF = 'serial_diff',
SUM = 'sum',
TOP_HITS = 'top_hits',
TOP_METRICS = 'top_metrics',
PERCENTILES = 'percentiles',
PERCENTILE_RANKS = 'percentile_ranks',
STD_DEV = 'std_dev',
Expand Down
194 changes: 194 additions & 0 deletions src/plugins/data/common/search/aggs/metrics/top_metrics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* 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 { getTopMetricsMetricAgg } from './top_metrics';
import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { IMetricAggConfig } from './metric_agg_type';
import { KBN_FIELD_TYPES } from '../../../../common';

describe('Top metrics metric', () => {
let aggConfig: IMetricAggConfig;

const init = ({
fieldName = 'field',
fieldType = KBN_FIELD_TYPES.NUMBER,
sortFieldName = 'sortField',
sortFieldType = KBN_FIELD_TYPES.NUMBER,
sortOrder = 'desc',
size = 1,
}: any) => {
const typesRegistry = mockAggTypesRegistry();
const field = {
name: fieldName,
displayName: fieldName,
type: fieldType,
};

const sortField = {
name: sortFieldName,
displayName: sortFieldName,
type: sortFieldType,
};

const params = {
size,
field: field.name,
sortField: sortField.name,
sortOrder: {
value: sortOrder,
},
};

const indexPattern = {
id: '1234',
title: 'logstash-*',
fields: {
getByName: (name: string) => {
if (name === sortFieldName) return sortField;
if (name === fieldName) return field;
return null;
},
filter: () => [field, sortField],
},
} as any;

const aggConfigs = new AggConfigs(
indexPattern,
[
{
id: '1',
type: 'top_metrics',
schema: 'metric',
params,
},
],
{ typesRegistry }
);

// Grab the aggConfig off the vis (we don't actually use the vis for anything else)
aggConfig = aggConfigs.aggs[0] as IMetricAggConfig;
};

it('should return a label prefixed with Last if sorting in descending order', () => {
init({ fieldName: 'bytes', sortFieldName: '@timestamp' });
expect(getTopMetricsMetricAgg().makeLabel(aggConfig)).toEqual(
'Last "bytes" value by "@timestamp"'
);
});

it('should return a label prefixed with First if sorting in ascending order', () => {
init({
fieldName: 'bytes',
sortFieldName: '@timestamp',
sortOrder: 'asc',
});
expect(getTopMetricsMetricAgg().makeLabel(aggConfig)).toEqual(
'First "bytes" value by "@timestamp"'
);
});

it('should return a label with size if larger then 1', () => {
init({
fieldName: 'bytes',
sortFieldName: '@timestamp',
sortOrder: 'asc',
size: 3,
});
expect(getTopMetricsMetricAgg().makeLabel(aggConfig)).toEqual(
'First 3 "bytes" values by "@timestamp"'
);
});

it('should return a fieldName in getValueBucketPath', () => {
init({
fieldName: 'bytes',
sortFieldName: '@timestamp',
sortOrder: 'asc',
size: 3,
});
expect(getTopMetricsMetricAgg().getValueBucketPath(aggConfig)).toEqual('1[bytes]');
});

it('produces the expected expression ast', () => {
init({ fieldName: 'machine.os', sortFieldName: '@timestamp' });
expect(aggConfig.toExpressionAst()).toMatchInlineSnapshot(`
Object {
"chain": Array [
Object {
"arguments": Object {
"enabled": Array [
true,
],
"field": Array [
"machine.os",
],
"id": Array [
"1",
],
"schema": Array [
"metric",
],
"size": Array [
1,
],
"sortField": Array [
"@timestamp",
],
"sortOrder": Array [
"desc",
],
},
"function": "aggTopMetrics",
"type": "function",
},
],
"type": "expression",
}
`);
});

describe('gets value from top metrics bucket', () => {
it('should return null if there is no hits', () => {
const bucket = {
'1': {
top: [],
},
};

init({ fieldName: 'bytes' });
expect(getTopMetricsMetricAgg().getValue(aggConfig, bucket)).toBe(null);
});

it('should return a single value if there is a single hit', () => {
const bucket = {
'1': {
top: [{ sort: [3], metrics: { bytes: 1024 } }],
},
};

init({ fieldName: 'bytes' });
expect(getTopMetricsMetricAgg().getValue(aggConfig, bucket)).toBe(1024);
});

it('should return an array of values if there is a multiple results', () => {
const bucket = {
'1': {
top: [
{ sort: [3], metrics: { bytes: 1024 } },
{ sort: [2], metrics: { bytes: 512 } },
{ sort: [1], metrics: { bytes: 256 } },
],
},
};

init({ fieldName: 'bytes' });
expect(getTopMetricsMetricAgg().getValue(aggConfig, bucket)).toEqual([1024, 512, 256]);
});
});
});
Loading