Skip to content

Commit 8ceccc5

Browse files
alexwizpkibanamachine
authored andcommitted
[Lens] Expose Elasticsearch accuracy warnings to the user (#116632)
* [Lens] Expose Elasticsearch accuracy warnings to the user Closes: #94918 * fix comments * update text Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent 9762086 commit 8ceccc5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+293
-59
lines changed

docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ readonly links: {
8989
readonly range: string;
9090
readonly significant_terms: string;
9191
readonly terms: string;
92+
readonly terms_doc_count_error: string;
9293
readonly avg: string;
9394
readonly avg_bucket: string;
9495
readonly max_bucket: string;

docs/development/core/public/kibana-plugin-core-public.doclinksstart.md

+1-1
Large diffs are not rendered by default.

src/core/public/doc_links/doc_links_service.ts

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export class DocLinksService {
118118
range: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-range-aggregation.html`,
119119
significant_terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-significantterms-aggregation.html`,
120120
terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html`,
121+
terms_doc_count_error: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html#_per_bucket_document_count_error`,
121122
avg: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-avg-aggregation.html`,
122123
avg_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-avg-bucket-aggregation.html`,
123124
max_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-max-bucket-aggregation.html`,
@@ -613,6 +614,7 @@ export interface DocLinksStart {
613614
readonly range: string;
614615
readonly significant_terms: string;
615616
readonly terms: string;
617+
readonly terms_doc_count_error: string;
616618
readonly avg: string;
617619
readonly avg_bucket: string;
618620
readonly max_bucket: string;

src/core/public/public.api.md

+1
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ export interface DocLinksStart {
557557
readonly range: string;
558558
readonly significant_terms: string;
559559
readonly terms: string;
560+
readonly terms_doc_count_error: string;
560561
readonly avg: string;
561562
readonly avg_bucket: string;
562563
readonly max_bucket: string;

src/plugins/data/common/search/aggs/agg_type.ts

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface AggTypeConfig<
5353
json?: boolean;
5454
decorateAggConfig?: () => any;
5555
postFlightRequest?: PostFlightRequestFn<TAggConfig>;
56+
hasPrecisionError?: (aggBucket: Record<string, unknown>) => boolean;
5657
getSerializedFormat?: (agg: TAggConfig) => SerializedFieldFormat;
5758
getValue?: (agg: TAggConfig, bucket: any) => any;
5859
getKey?: (bucket: any, key: any, agg: TAggConfig) => any;
@@ -180,6 +181,9 @@ export class AggType<
180181
* is created, giving the agg type a chance to modify the agg config
181182
*/
182183
decorateAggConfig: () => any;
184+
185+
hasPrecisionError?: (aggBucket: Record<string, unknown>) => boolean;
186+
183187
/**
184188
* A function that needs to be called after the main request has been made
185189
* and should return an updated response
@@ -283,6 +287,7 @@ export class AggType<
283287
this.getResponseAggs = config.getResponseAggs || (() => {});
284288
this.decorateAggConfig = config.decorateAggConfig || (() => ({}));
285289
this.postFlightRequest = config.postFlightRequest || identity;
290+
this.hasPrecisionError = config.hasPrecisionError;
286291

287292
this.getSerializedFormat =
288293
config.getSerializedFormat ||

src/plugins/data/common/search/aggs/buckets/terms.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,19 @@ describe('Terms Agg', () => {
286286
{ typesRegistry: mockAggTypesRegistry() }
287287
);
288288
const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl();
289+
289290
expect(params.order).toEqual({ 'test-orderAgg.50': 'desc' });
290291
});
292+
293+
test('should override "hasPrecisionError" for the "terms" bucket type', () => {
294+
const aggConfigs = getAggConfigs();
295+
const { type } = aggConfigs.aggs[0];
296+
297+
expect(type.hasPrecisionError).toBeInstanceOf(Function);
298+
299+
expect(type.hasPrecisionError!({})).toBeFalsy();
300+
expect(type.hasPrecisionError!({ doc_count_error_upper_bound: 0 })).toBeFalsy();
301+
expect(type.hasPrecisionError!({ doc_count_error_upper_bound: -1 })).toBeTruthy();
302+
});
291303
});
292304
});

src/plugins/data/common/search/aggs/buckets/terms.ts

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export const getTermsBucketAgg = () =>
8585
};
8686
},
8787
createFilter: createFilterTerms,
88+
hasPrecisionError: (aggBucket) => Boolean(aggBucket?.doc_count_error_upper_bound),
8889
postFlightRequest: async (
8990
resp,
9091
aggConfigs,

src/plugins/data/common/search/tabify/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
export { tabifyDocs, flattenHit } from './tabify_docs';
1010
export { tabifyAggResponse } from './tabify';
1111
export { tabifyGetColumns } from './get_columns';
12+
export { checkColumnForPrecisionError } from './utils';

src/plugins/data/common/search/tabify/response_writer.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ describe('TabbedAggResponseWriter class', () => {
166166
field: 'geo.src',
167167
source: 'esaggs',
168168
sourceParams: {
169+
hasPrecisionError: false,
169170
enabled: true,
170171
id: '1',
171172
indexPatternId: '1234',
@@ -193,6 +194,7 @@ describe('TabbedAggResponseWriter class', () => {
193194
},
194195
source: 'esaggs',
195196
sourceParams: {
197+
hasPrecisionError: false,
196198
appliedTimeRange: undefined,
197199
enabled: true,
198200
id: '2',
@@ -227,6 +229,7 @@ describe('TabbedAggResponseWriter class', () => {
227229
field: 'geo.src',
228230
source: 'esaggs',
229231
sourceParams: {
232+
hasPrecisionError: false,
230233
enabled: true,
231234
id: '1',
232235
indexPatternId: '1234',
@@ -254,6 +257,7 @@ describe('TabbedAggResponseWriter class', () => {
254257
},
255258
source: 'esaggs',
256259
sourceParams: {
260+
hasPrecisionError: false,
257261
appliedTimeRange: undefined,
258262
enabled: true,
259263
id: '2',

src/plugins/data/common/search/tabify/response_writer.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { isEmpty } from 'lodash';
1010
import { IAggConfigs } from '../aggs';
1111
import { tabifyGetColumns } from './get_columns';
1212

13-
import { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow } from './types';
13+
import type { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow } from './types';
1414
import { Datatable, DatatableColumn } from '../../../../expressions/common/expression_types/specs';
1515

1616
interface BufferColumn {
@@ -80,6 +80,7 @@ export class TabbedAggResponseWriter {
8080
params: column.aggConfig.toSerializedFieldFormat(),
8181
source: 'esaggs',
8282
sourceParams: {
83+
hasPrecisionError: Boolean(column.hasPrecisionError),
8384
indexPatternId: column.aggConfig.getIndexPattern()?.id,
8485
appliedTimeRange:
8586
column.aggConfig.params.field?.name &&

src/plugins/data/common/search/tabify/tabify.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ export function tabifyAggResponse(
4242

4343
switch (agg.type.type) {
4444
case AggGroupNames.Buckets:
45-
const aggBucket = get(bucket, agg.id);
45+
const aggBucket = get(bucket, agg.id) as Record<string, unknown>;
4646
const tabifyBuckets = new TabifyBuckets(aggBucket, agg.params, respOpts?.timeRange);
47+
const precisionError = agg.type.hasPrecisionError?.(aggBucket);
48+
49+
if (precisionError) {
50+
// "сolumn" mutation, we have to do this here as this value is filled in based on aggBucket value
51+
column.hasPrecisionError = true;
52+
}
4753

4854
if (tabifyBuckets.length) {
4955
tabifyBuckets.forEach((subBucket, tabifyBucketKey) => {

src/plugins/data/common/search/tabify/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface TabbedAggColumn {
4141
aggConfig: IAggConfig;
4242
id: string;
4343
name: string;
44+
hasPrecisionError?: boolean;
4445
}
4546

4647
/** @public **/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import { checkColumnForPrecisionError } from './utils';
10+
import type { DatatableColumn } from '../../../../expressions';
11+
12+
describe('tabify utils', () => {
13+
describe('checkDatatableForPrecisionError', () => {
14+
test('should return true if there is a precision error in the column', () => {
15+
expect(
16+
checkColumnForPrecisionError({
17+
meta: {
18+
sourceParams: {
19+
hasPrecisionError: true,
20+
},
21+
},
22+
} as unknown as DatatableColumn)
23+
).toBeTruthy();
24+
});
25+
test('should return false if there is no precision error in the column', () => {
26+
expect(
27+
checkColumnForPrecisionError({
28+
meta: {
29+
sourceParams: {
30+
hasPrecisionError: false,
31+
},
32+
},
33+
} as unknown as DatatableColumn)
34+
).toBeFalsy();
35+
});
36+
test('should return false if precision error is not defined', () => {
37+
expect(
38+
checkColumnForPrecisionError({
39+
meta: {
40+
sourceParams: {},
41+
},
42+
} as unknown as DatatableColumn)
43+
).toBeFalsy();
44+
});
45+
});
46+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import type { DatatableColumn } from '../../../../expressions';
10+
11+
/** @public **/
12+
export const checkColumnForPrecisionError = (column: DatatableColumn) =>
13+
column.meta.sourceParams?.hasPrecisionError;

src/plugins/data/public/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ import {
139139
// tabify
140140
tabifyAggResponse,
141141
tabifyGetColumns,
142+
checkColumnForPrecisionError,
142143
} from '../common';
143144

144145
export { AggGroupLabels, AggGroupNames, METRIC_TYPES, BUCKET_TYPES } from '../common';
@@ -246,6 +247,7 @@ export const search = {
246247
getResponseInspectorStats,
247248
tabifyAggResponse,
248249
tabifyGetColumns,
250+
checkColumnForPrecisionError,
249251
};
250252

251253
/*

src/plugins/data/public/search/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export {
3636
parseSearchSourceJSON,
3737
SearchSource,
3838
SortDirection,
39+
checkColumnForPrecisionError,
3940
} from '../../common/search';
4041
export type {
4142
ISessionService,
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
1+
{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
1+
{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
1+
{"as":"metricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"labels":{"show":true},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}

0 commit comments

Comments
 (0)