mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Data Table] Expensive queries are causing unnecessary load and delays on Elasticsearch (#98903) (#110457)
* [Data Table] Expensive queries are causing unnecessary load and delays on Elasticsearch Part of #93770 * remove extra cycles * fix PR comments * fix finder.close * code cleanup * add namespaces: ['*'], * fix jest Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
eb0902b3c8
commit
eaec7f5a5e
4 changed files with 59 additions and 35 deletions
|
@ -6,8 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsClientContract } from 'kibana/server';
|
||||
import { getStats } from './get_stats';
|
||||
import type { SavedObjectsClientContract } from '../../../../core/server';
|
||||
|
||||
const mockVisualizations = {
|
||||
saved_objects: [
|
||||
|
@ -42,15 +42,23 @@ const mockVisualizations = {
|
|||
|
||||
describe('vis_type_table getStats', () => {
|
||||
const mockSoClient = ({
|
||||
find: jest.fn().mockResolvedValue(mockVisualizations),
|
||||
createPointInTimeFinder: jest.fn().mockResolvedValue({
|
||||
close: jest.fn(),
|
||||
find: function* asyncGenerator() {
|
||||
yield mockVisualizations;
|
||||
},
|
||||
}),
|
||||
} as unknown) as SavedObjectsClientContract;
|
||||
|
||||
test('Returns stats from saved objects for table vis only', async () => {
|
||||
const result = await getStats(mockSoClient);
|
||||
expect(mockSoClient.find).toHaveBeenCalledWith({
|
||||
|
||||
expect(mockSoClient.createPointInTimeFinder).toHaveBeenCalledWith({
|
||||
type: 'visualization',
|
||||
perPage: 10000,
|
||||
perPage: 1000,
|
||||
namespaces: ['*'],
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
total: 4,
|
||||
total_split: 3,
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ISavedObjectsRepository, SavedObjectsClientContract } from 'kibana/server';
|
||||
import {
|
||||
SavedVisState,
|
||||
VisualizationSavedObjectAttributes,
|
||||
} from 'src/plugins/visualizations/common';
|
||||
import { TableVisParams, VIS_TYPE_TABLE } from '../../common';
|
||||
import { VIS_TYPE_TABLE } from '../../common';
|
||||
|
||||
import type {
|
||||
ISavedObjectsRepository,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsFindResult,
|
||||
} from '../../../../core/server';
|
||||
import type { SavedVisState } from '../../../visualizations/common';
|
||||
|
||||
export interface VisTypeTableUsage {
|
||||
/**
|
||||
|
@ -44,17 +46,14 @@ export interface VisTypeTableUsage {
|
|||
export async function getStats(
|
||||
soClient: SavedObjectsClientContract | ISavedObjectsRepository
|
||||
): Promise<VisTypeTableUsage | undefined> {
|
||||
const visualizations = await soClient.find<VisualizationSavedObjectAttributes>({
|
||||
const finder = await soClient.createPointInTimeFinder({
|
||||
type: 'visualization',
|
||||
perPage: 10000,
|
||||
perPage: 1000,
|
||||
namespaces: ['*'],
|
||||
});
|
||||
|
||||
const tableVisualizations = visualizations.saved_objects
|
||||
.map<SavedVisState<TableVisParams>>(({ attributes }) => JSON.parse(attributes.visState))
|
||||
.filter(({ type }) => type === VIS_TYPE_TABLE);
|
||||
|
||||
const defaultStats = {
|
||||
total: tableVisualizations.length,
|
||||
const stats: VisTypeTableUsage = {
|
||||
total: 0,
|
||||
total_split: 0,
|
||||
split_columns: {
|
||||
total: 0,
|
||||
|
@ -66,20 +65,39 @@ export async function getStats(
|
|||
},
|
||||
};
|
||||
|
||||
return tableVisualizations.reduce((acc, { aggs, params }) => {
|
||||
const doTelemetry = ({ aggs, params }: SavedVisState) => {
|
||||
stats.total += 1;
|
||||
|
||||
const hasSplitAgg = aggs.find((agg) => agg.schema === 'split');
|
||||
|
||||
if (hasSplitAgg) {
|
||||
acc.total_split += 1;
|
||||
stats.total_split += 1;
|
||||
|
||||
const isSplitRow = params.row;
|
||||
const isSplitEnabled = hasSplitAgg.enabled;
|
||||
const container = isSplitRow ? stats.split_rows : stats.split_columns;
|
||||
|
||||
const container = isSplitRow ? acc.split_rows : acc.split_columns;
|
||||
container.total += 1;
|
||||
container.enabled = isSplitEnabled ? container.enabled + 1 : container.enabled;
|
||||
}
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, defaultStats);
|
||||
for await (const response of finder.find()) {
|
||||
(response.saved_objects || []).forEach(({ attributes }: SavedObjectsFindResult<any>) => {
|
||||
if (attributes?.visState) {
|
||||
try {
|
||||
const visState: SavedVisState = JSON.parse(attributes.visState);
|
||||
|
||||
if (visState.type === VIS_TYPE_TABLE) {
|
||||
doTelemetry(visState);
|
||||
}
|
||||
} catch {
|
||||
// nothing to be here, "so" not valid
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
await finder.close();
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
createUsageCollectionSetupMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from '../../../usage_collection/server/mocks';
|
||||
import { registerVisTypeTableUsageCollector } from './register_usage_collector';
|
||||
import { getStats } from './get_stats';
|
||||
|
||||
jest.mock('./get_stats', () => ({
|
||||
getStats: jest.fn().mockResolvedValue({ somestat: 1 }),
|
||||
}));
|
||||
|
||||
import {
|
||||
createUsageCollectionSetupMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
import { registerVisTypeTableUsageCollector } from './register_usage_collector';
|
||||
import { getStats } from './get_stats';
|
||||
|
||||
describe('registerVisTypeTableUsageCollector', () => {
|
||||
it('Usage collector configs fit the shape', () => {
|
||||
test('Usage collector configs fit the shape', () => {
|
||||
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||
registerVisTypeTableUsageCollector(mockCollectorSet);
|
||||
expect(mockCollectorSet.makeUsageCollector).toBeCalledTimes(1);
|
||||
|
@ -45,7 +44,7 @@ describe('registerVisTypeTableUsageCollector', () => {
|
|||
expect(usageCollectorConfig.isReady()).toBe(true);
|
||||
});
|
||||
|
||||
it('Usage collector config.fetch calls getStats', async () => {
|
||||
test('Usage collector config.fetch calls getStats', async () => {
|
||||
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||
registerVisTypeTableUsageCollector(mockCollectorSet);
|
||||
const usageCollector = mockCollectorSet.makeUsageCollector.mock.results[0].value;
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
|
||||
import { getStats, VisTypeTableUsage } from './get_stats';
|
||||
import type { UsageCollectionSetup } from '../../../usage_collection/server';
|
||||
|
||||
export function registerVisTypeTableUsageCollector(collectorSet: UsageCollectionSetup) {
|
||||
const collector = collectorSet.makeUsageCollector<VisTypeTableUsage | undefined>({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue