diff --git a/x-pack/plugins/ml/public/application/components/field_stats_flyout/field_stats_flyout_provider.tsx b/x-pack/plugins/ml/public/application/components/field_stats_flyout/field_stats_flyout_provider.tsx index f72fb8d00f173..02c1a2c70aa92 100644 --- a/x-pack/plugins/ml/public/application/components/field_stats_flyout/field_stats_flyout_provider.tsx +++ b/x-pack/plugins/ml/public/application/components/field_stats_flyout/field_stats_flyout_provider.tsx @@ -76,7 +76,7 @@ export const FieldStatsFlyoutProvider: FC<{ fields: ['*'], _source: false, ...queryAndRunTimeMappings, - size: 1000, + size: 500, }, }; const cacheKey = stringHash(JSON.stringify(esSearchRequestParams)).toString(); diff --git a/x-pack/plugins/ml/public/shared.ts b/x-pack/plugins/ml/public/shared.ts index 73688aebc94f8..57db3c66a7c3b 100644 --- a/x-pack/plugins/ml/public/shared.ts +++ b/x-pack/plugins/ml/public/shared.ts @@ -16,3 +16,5 @@ export * from '../common/util/validators'; export * from './application/formatters/metric_change_description'; export * from './application/components/field_stats_flyout'; export * from './application/data_frame_analytics/common'; + +export { useFieldStatsFlyoutContext } from './application/components/field_stats_flyout/use_field_stats_flytout_context'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index 7b6911636c600..3a6781615b70b 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -51,7 +51,8 @@ export const useIndexData = ( dataView: SearchItems['dataView'], query: TransformConfigQuery, combinedRuntimeMappings?: StepDefineExposedState['runtimeMappings'], - timeRangeMs?: TimeRangeMs + timeRangeMs?: TimeRangeMs, + populatedFields?: Set | null ): UseIndexDataReturnType => { const { analytics } = useAppDependencies(); @@ -96,47 +97,53 @@ export const useIndexData = ( // (for example, as part of filebeat/metricbeat/ECS based indices) // to the data grid component which would significantly slow down the page. const fetchDataGridSampleDocuments = async function () { - setErrorMessage(''); - setStatus(INDEX_STATUS.LOADING); - - const esSearchRequest = { - index: indexPattern, - body: { - fields: ['*'], - _source: false, - query: { - function_score: { - query: defaultQuery, - random_score: {}, + let populatedDataViewFields = populatedFields ? [...populatedFields] : []; + let isMissingFields = populatedDataViewFields.length === 0; + + // If populatedFields are not provided, make own request to calculate + if (populatedFields === undefined) { + setErrorMessage(''); + setStatus(INDEX_STATUS.LOADING); + + const esSearchRequest = { + index: indexPattern, + body: { + fields: ['*'], + _source: false, + query: { + function_score: { + query: defaultQuery, + random_score: {}, + }, }, + size: 500, }, - size: 500, - }, - }; + }; - const resp = await dataSearch(esSearchRequest, abortController.signal); + const resp = await dataSearch(esSearchRequest, abortController.signal); - if (!isEsSearchResponse(resp)) { - setErrorMessage(getErrorMessage(resp)); - setStatus(INDEX_STATUS.ERROR); - return; - } + if (!isEsSearchResponse(resp)) { + setErrorMessage(getErrorMessage(resp)); + setStatus(INDEX_STATUS.ERROR); + return; + } + const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); + populatedDataViewFields = [...new Set(docs.map(Object.keys).flat(1))]; + } const isCrossClusterSearch = indexPattern.includes(':'); - const isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); - - const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); // Get all field names for each returned doc and flatten it // to a list of unique field names used across all docs. const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); - const populatedFields = [...new Set(docs.map(Object.keys).flat(1))] + const filteredDataViewFields = populatedDataViewFields .filter((d) => allDataViewFields.includes(d)) .sort(); setCcsWarning(isCrossClusterSearch && isMissingFields); setStatus(INDEX_STATUS.LOADED); - setDataViewFields(populatedFields); + setDataViewFields(filteredDataViewFields); }; fetchDataGridSampleDocuments(); @@ -145,7 +152,7 @@ export const useIndexData = ( abortController.abort(); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [timeRangeMs]); + }, [timeRangeMs, populatedFields?.size]); const columns: EuiDataGridColumn[] = useMemo(() => { if (typeof dataViewFields === 'undefined') { diff --git a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts index c4ccff9944dd4..f2a59e0cb1a61 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts @@ -39,7 +39,10 @@ export const useSearchItems = (defaultSavedObjectId: string | undefined) => { } try { - fetchedSavedSearch = await appDeps.savedSearch.get(id); + // If data view already found, no need to get saved search + if (!fetchedDataView) { + fetchedSavedSearch = await appDeps.savedSearch.get(id); + } } catch (e) { // Just let fetchedSavedSearch stay undefined in case it doesn't exist. } diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 9796d9f01de65..81bdb47735a37 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -58,7 +58,7 @@ import { import { useDocumentationLinks } from '../../../../hooks/use_documentation_links'; import { useIndexData } from '../../../../hooks/use_index_data'; import { useTransformConfigData } from '../../../../hooks/use_transform_config_data'; -import { useToastNotifications } from '../../../../app_dependencies'; +import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { SearchItems } from '../../../../hooks/use_search_items'; import { getAggConfigFromEsAgg } from '../../../../common/pivot_aggs'; @@ -120,8 +120,20 @@ export const StepDefineForm: FC = React.memo((props) => { const { transformConfigQuery } = stepDefineForm.searchBar.state; const { runtimeMappings } = stepDefineForm.runtimeMappingsEditor.state; + const appDependencies = useAppDependencies(); + const { + ml: { useFieldStatsFlyoutContext }, + } = appDependencies; + + const fieldStatsContext = useFieldStatsFlyoutContext(); const indexPreviewProps = { - ...useIndexData(dataView, transformConfigQuery, runtimeMappings, timeRangeMs), + ...useIndexData( + dataView, + transformConfigQuery, + runtimeMappings, + timeRangeMs, + fieldStatsContext?.populatedFields ?? null + ), dataTestSubj: 'transformIndexPreview', toastNotifications, };