From 790679b1e70ea2e16c3178a86d2e70368551e2ed Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:37:52 -0400 Subject: [PATCH] [8.13] [Tabify] Handle doc_count with care on time shift scenarios (#178394) (#178726) # Backport This will backport the following commits from `main` to `8.13`: - [[Tabify] Handle doc_count with care on time shift scenarios (#178394)](https://github.com/elastic/kibana/pull/178394) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) Co-authored-by: Marco Liberati --- .../data/common/search/aggs/agg_configs.ts | 2 +- .../tabify/fixtures/fake_timeoffset_data.ts | 19 +++++++++++++++++ .../data/common/search/tabify/tabify.test.ts | 21 ++++++++++++++++++- .../data/common/search/tabify/tabify.ts | 16 +++++++++++++- 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/plugins/data/common/search/tabify/fixtures/fake_timeoffset_data.ts diff --git a/src/plugins/data/common/search/aggs/agg_configs.ts b/src/plugins/data/common/search/aggs/agg_configs.ts index 7cab863fba11d..4a95724b6ccf3 100644 --- a/src/plugins/data/common/search/aggs/agg_configs.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.ts @@ -117,7 +117,7 @@ export class AggConfigs { isSamplingEnabled() { return ( isSamplingEnabled(this.opts.probability) && - this.getRequestAggs().filter((agg) => !agg.type.hasNoDsl).length > 0 + this.getRequestAggs().some((agg) => !agg.type.hasNoDsl) ); } diff --git a/src/plugins/data/common/search/tabify/fixtures/fake_timeoffset_data.ts b/src/plugins/data/common/search/tabify/fixtures/fake_timeoffset_data.ts new file mode 100644 index 0000000000000..f17f2a99a2559 --- /dev/null +++ b/src/plugins/data/common/search/tabify/fixtures/fake_timeoffset_data.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export const timeOffsetFiltersWithZeroDocCountResponse = { + hits: { + total: 474, + max_score: 0, + hits: [], + }, + aggregations: { + doc_count: 0, + doc_count_86400000: 234, + }, +}; diff --git a/src/plugins/data/common/search/tabify/tabify.test.ts b/src/plugins/data/common/search/tabify/tabify.test.ts index 4230782f60209..87766f62b6376 100644 --- a/src/plugins/data/common/search/tabify/tabify.test.ts +++ b/src/plugins/data/common/search/tabify/tabify.test.ts @@ -12,15 +12,19 @@ import { AggConfigs, BucketAggParam, IAggConfig, IAggConfigs } from '../aggs'; import { mockAggTypesRegistry } from '../aggs/test_helpers'; import { metricOnly, threeTermBuckets } from './fixtures/fake_hierarchical_data'; import { isSamplingEnabled } from '../aggs/utils/sampler'; +import { timeOffsetFiltersWithZeroDocCountResponse } from './fixtures/fake_timeoffset_data'; describe('tabifyAggResponse Integration', () => { const typesRegistry = mockAggTypesRegistry(); for (const probability of [1, 0.5, undefined]) { function getTitlePostfix() { - if (!isSamplingEnabled(probability)) { + if (probability == null) { return ''; } + if (probability === 1) { + return ` - with no sampling (probability = 1)`; + } return ` - with sampling (probability = ${probability})`; } @@ -243,5 +247,20 @@ describe('tabifyAggResponse Integration', () => { }); }); }); + + describe(`edge cases${getTitlePostfix()}`, () => { + test('it should correctly report zero doc count for unshifted bucket', () => { + const aggConfigs = createAggConfigs([ + mockAggConfig({ type: 'count', schema: 'metric' }), + mockAggConfig({ type: 'count', schema: 'metric', params: { timeShift: '1d' } }), + ]); + + // no need to wrap with sampling as count is not affected by it + const tabbed = tabifyAggResponse(aggConfigs, timeOffsetFiltersWithZeroDocCountResponse, { + metricsAtAllLevels: false, + }); + expect(tabbed.rows[0]).toEqual({ 'col-0-1': 0, 'col-1-2': 234 }); + }); + }); } }); diff --git a/src/plugins/data/common/search/tabify/tabify.ts b/src/plugins/data/common/search/tabify/tabify.ts index 82c91c3579456..67278e44ec438 100644 --- a/src/plugins/data/common/search/tabify/tabify.ts +++ b/src/plugins/data/common/search/tabify/tabify.ts @@ -146,13 +146,27 @@ export function tabifyAggResponse( } const write = new TabbedAggResponseWriter(aggConfigs, respOpts || {}); + // Check whether there's a time shift for a count operation at root level + const hasMultipleDocCountAtRootWithFilters = Object.keys(esResponse.aggregations ?? {}).some( + (key) => /doc_count_/.test(key) + ); + const topLevelBucket: AggResponseBucket = { ...(aggConfigs.isSamplingEnabled() ? esResponse.aggregations?.sampling : esResponse.aggregations), - doc_count: esResponse.aggregations?.doc_count || esResponse.hits?.total, + doc_count: esResponse.aggregations?.doc_count, }; + // The fix itself is one line, but it's a bit hard to clear assess the full impact of it + // therefore here's a check to scope down the impact to the known scenario with the bug https://github.com/elastic/kibana/issues/178073 + // this can be lifted off once the full impact is assessed + if (!topLevelBucket.doc_count) { + if (!hasMultipleDocCountAtRootWithFilters) { + topLevelBucket.doc_count = esResponse.hits?.total; + } + } + collectBucket(aggConfigs, write, topLevelBucket, '', 1); return {