Skip to content

Commit

Permalink
[ML] Transforms: Support sub-aggregations (elastic#68306)
Browse files Browse the repository at this point in the history
* [ML] WIP UI support for the sug-aggs

* [ML] extract sug-aggs from es config

* [ML] fix for range filter

* [ML] delete sub-aggregation

* [ML] isConfigInvalid

* [ML] fix actions, support parent agg

* [ML] update getAggConfigFromEsAgg

* [ML] unit tests

* [ML] SubAggsSection

* [ML] fix snapshot, add validation

* [ML] fix label capping

* [ML] rename Filter query label

* [ML] fix updateSubAggregation validation

* [ML] fix state update warning

* [ML] increase MAX_NESTING_SUB_AGGS

* [ML] functional tests for sub-aggregations

* [ML] change the tooltip message

* [ML] update functional tests

* [ML] fix typo
  • Loading branch information
darnautov committed Jun 9, 2020
1 parent 4f8d5a4 commit 1c0000b
Show file tree
Hide file tree
Showing 19 changed files with 700 additions and 258 deletions.
25 changes: 25 additions & 0 deletions x-pack/plugins/transform/public/app/common/pivot_aggs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,29 @@ describe('getAggConfigFromEsAgg', () => {
},
});
});

test('should resolve sub-aggregations', () => {
const esConfig = {
filter: {
term: { region: 'sa-west-1' },
},
aggs: {
test_avg: {
avg: {
field: 'test_field',
},
},
},
};

const result = getAggConfigFromEsAgg(esConfig, 'test_3');

expect(result.subAggs!.test_avg).toEqual({
agg: 'avg',
aggName: 'test_avg',
dropDownName: 'test_avg',
field: 'test_field',
parentAgg: result,
});
});
});
44 changes: 41 additions & 3 deletions x-pack/plugins/transform/public/app/common/pivot_aggs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,32 @@ export type PivotAggDict = {
[key in AggName]: PivotAgg;
};

/**
* The maximum level of sub-aggregations
*/
export const MAX_NESTING_SUB_AGGS = 10;

// The internal representation of an aggregation definition.
export interface PivotAggsConfigBase {
agg: PivotSupportedAggs;
aggName: AggName;
dropDownName: string;
/** Indicates if aggregation supports sub-aggregations */
isSubAggsSupported?: boolean;
/** Dictionary of the sub-aggregations */
subAggs?: PivotAggsConfigDict;
/** Reference to the parent aggregation */
parentAgg?: PivotAggsConfig;
}

/**
* Resolves agg UI config from provided ES agg definition
*/
export function getAggConfigFromEsAgg(esAggDefinition: Record<string, any>, aggName: string) {
export function getAggConfigFromEsAgg(
esAggDefinition: Record<string, any>,
aggName: string,
parentRef?: PivotAggsConfig
) {
const aggKeys = Object.keys(esAggDefinition);

// Find the main aggregation key
Expand All @@ -108,12 +123,21 @@ export function getAggConfigFromEsAgg(esAggDefinition: Record<string, any>, aggN

const config = getAggFormConfig(agg, commonConfig);

if (parentRef) {
config.parentAgg = parentRef;
}

if (isPivotAggsWithExtendedForm(config)) {
config.setUiConfigFromEs(esAggDefinition[agg]);
}

if (aggKeys.includes('aggs')) {
// TODO process sub-aggregation
config.subAggs = {};
for (const [subAggName, subAggConfigs] of Object.entries(
esAggDefinition.aggs as Record<string, object>
)) {
config.subAggs[subAggName] = getAggConfigFromEsAgg(subAggConfigs, subAggName, config);
}
}

return config;
Expand Down Expand Up @@ -199,6 +223,7 @@ export function getEsAggFromAggConfig(
delete esAgg.agg;
delete esAgg.aggName;
delete esAgg.dropDownName;
delete esAgg.parentAgg;

if (isPivotAggsWithExtendedForm(pivotAggsConfig)) {
esAgg = pivotAggsConfig.getEsAggConfig();
Expand All @@ -208,7 +233,20 @@ export function getEsAggFromAggConfig(
}
}

return {
const result = {
[pivotAggsConfig.agg]: esAgg,
};

if (
isPivotAggsConfigWithUiSupport(pivotAggsConfig) &&
pivotAggsConfig.subAggs !== undefined &&
Object.keys(pivotAggsConfig.subAggs).length > 0
) {
result.aggs = {};
for (const subAggConfig of Object.values(pivotAggsConfig.subAggs)) {
result.aggs[subAggConfig.aggName] = getEsAggFromAggConfig(subAggConfig);
}
}

return result;
}
23 changes: 16 additions & 7 deletions x-pack/plugins/transform/public/app/hooks/use_pivot_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,25 @@ import {
PivotGroupByConfig,
PivotQuery,
PreviewMappings,
PivotAggsConfig,
} from '../common';

import { SearchItems } from './use_search_items';
import { useApi } from './use_api';
import { isPivotAggsWithExtendedForm } from '../common/pivot_aggs';

/**
* Checks if the aggregations collection is invalid.
*/
function isConfigInvalid(aggsArray: PivotAggsConfig[]): boolean {
return aggsArray.some((agg) => {
return (
(isPivotAggsWithExtendedForm(agg) && !agg.isValid()) ||
(agg.subAggs && isConfigInvalid(Object.values(agg.subAggs)))
);
});
}

function sortColumns(groupByArr: PivotGroupByConfig[]) {
return (a: string, b: string) => {
// make sure groupBy fields are always most left columns
Expand All @@ -62,7 +75,7 @@ export const usePivotData = (
const [previewMappings, setPreviewMappings] = useState<PreviewMappings>({ properties: {} });
const api = useApi();

const aggsArr = dictionaryToArray(aggs);
const aggsArr = useMemo(() => dictionaryToArray(aggs), [aggs]);
const groupByArr = dictionaryToArray(groupBy);

// Filters mapping properties of type `object`, which get returned for nested field parents.
Expand Down Expand Up @@ -136,11 +149,7 @@ export const usePivotData = (
return;
}

const isConfigInvalid = aggsArr.some(
(agg) => isPivotAggsWithExtendedForm(agg) && !agg.isValid()
);

if (isConfigInvalid) {
if (isConfigInvalid(aggsArr)) {
return;
}

Expand Down Expand Up @@ -185,7 +194,7 @@ export const usePivotData = (
/* eslint-disable react-hooks/exhaustive-deps */
}, [
indexPatternTitle,
JSON.stringify(aggsArr),
aggsArr,
JSON.stringify(groupByArr),
JSON.stringify(query),
/* eslint-enable react-hooks/exhaustive-deps */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ interface Props {
placeholder?: string;
changeHandler(d: EuiComboBoxOptionOption[]): void;
testSubj?: string;
isDisabled?: boolean;
}

export const DropDown: React.FC<Props> = ({
changeHandler,
options,
placeholder = 'Search ...',
testSubj,
isDisabled,
}) => {
return (
<EuiComboBox
Expand All @@ -31,6 +33,7 @@ export const DropDown: React.FC<Props> = ({
onChange={changeHandler}
isClearable={false}
data-test-subj={testSubj}
isDisabled={isDisabled}
/>
);
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1c0000b

Please sign in to comment.