Skip to content

Commit ae62b56

Browse files
authored
[ML] Data Frames: Fix to avoid queries for indices with more than 1024 fields. (#37183) (#37227)
- 7.0 introduced indices.query.bool.max_clause_count which defaults to 1024. This can break certain queries (e.g. simple_query) for indices which have more than 1024 fields (e.g. certain beats indices). The optional data frames query uses simple_query and could therefor break the source index preview as well the pivot preview and pivot job itself given these conditions. - Originally the default query (* used for simple_query) was always applied for source index previews and pivot previews. A new check isDefaultQuery() will now allow a) the source index preview to use a more efficient match_all query and b) avoid adding the query to the pivot config. This avoids triggering the max_clause_count when no optional query is set. - If an index has more than 1024 fields, the input form for an optional query will be hidden. A helper text explains the reasoning. This avoids triggering max_clause_count related errors from within the UI. A user can still copy a UI created config to the clipboard and add an optional query in Kibana dev console. - Additionally, this PR adds a fix to format date fields in the source index preview table using moment-timezone and formatHumanReadableDateTimeSeconds to display dates with the correct timezone.
1 parent 4406bf3 commit ae62b56

File tree

6 files changed

+91
-32
lines changed

6 files changed

+91
-32
lines changed

x-pack/plugins/ml/public/data_frame/common/request.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,32 @@ import { DefinePivotExposedState } from '../components/define_pivot/define_pivot
1111

1212
import { PIVOT_SUPPORTED_GROUP_BY_AGGS } from './pivot_group_by';
1313
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from './pivot_aggs';
14-
import { getDataFramePreviewRequest, getDataFrameRequest, getPivotQuery } from './request';
14+
import {
15+
getDataFramePreviewRequest,
16+
getDataFrameRequest,
17+
getPivotQuery,
18+
isDefaultQuery,
19+
isSimpleQuery,
20+
PivotQuery,
21+
} from './request';
22+
23+
const defaultQuery: PivotQuery = { query_string: { query: '*' } };
24+
const matchAllQuery: PivotQuery = { match_all: {} };
25+
const simpleQuery: PivotQuery = { query_string: { query: 'airline:AAL' } };
1526

1627
describe('Data Frame: Common', () => {
28+
test('isSimpleQuery()', () => {
29+
expect(isSimpleQuery(defaultQuery)).toBe(true);
30+
expect(isSimpleQuery(matchAllQuery)).toBe(false);
31+
expect(isSimpleQuery(simpleQuery)).toBe(true);
32+
});
33+
34+
test('isDefaultQuery()', () => {
35+
expect(isDefaultQuery(defaultQuery)).toBe(true);
36+
expect(isDefaultQuery(matchAllQuery)).toBe(false);
37+
expect(isDefaultQuery(simpleQuery)).toBe(false);
38+
});
39+
1740
test('getPivotQuery()', () => {
1841
const query = getPivotQuery('the-query');
1942

x-pack/plugins/ml/public/data_frame/common/request.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ export function getPivotQuery(search: string | SavedSearchQuery): PivotQuery {
6868
return search;
6969
}
7070

71+
export function isSimpleQuery(arg: any): arg is SimpleQuery {
72+
return arg.query_string !== undefined;
73+
}
74+
75+
export function isDefaultQuery(query: PivotQuery): boolean {
76+
return isSimpleQuery(query) && query.query_string.query === '*';
77+
}
78+
7179
export function getDataFramePreviewRequest(
7280
indexPatternTitle: IndexPattern['title'],
7381
query: PivotQuery,
@@ -77,14 +85,17 @@ export function getDataFramePreviewRequest(
7785
const request: DataFramePreviewRequest = {
7886
source: {
7987
index: indexPatternTitle,
80-
query,
8188
},
8289
pivot: {
8390
group_by: {},
8491
aggregations: {},
8592
},
8693
};
8794

95+
if (!isDefaultQuery(query)) {
96+
request.source.query = query;
97+
}
98+
8899
groupBy.forEach(g => {
89100
if (g.agg === PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS) {
90101
const termsAgg: TermsAgg = {

x-pack/plugins/ml/public/data_frame/components/define_pivot/common.test.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,7 @@ describe('Data Frame: Define Pivot Common', () => {
128128
expect(pivotPreviewDevConsoleStatement).toBe(`POST _data_frame/transforms/_preview
129129
{
130130
"source": {
131-
"index": "the-index-pattern-title",
132-
"query": {
133-
"query_string": {
134-
"query": "*",
135-
"default_operator": "AND"
136-
}
137-
}
131+
"index": "the-index-pattern-title"
138132
},
139133
"pivot": {
140134
"group_by": {

x-pack/plugins/ml/public/data_frame/components/define_pivot/define_pivot_form.tsx

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
191191
]
192192
);
193193

194+
// TODO This should use the actual value of `indices.query.bool.max_clause_count`
195+
const maxIndexFields = 1024;
196+
const numIndexFields = indexPattern.fields.length;
197+
const disabledQuery = numIndexFields > maxIndexFields;
198+
194199
return (
195200
<EuiFlexGroup>
196201
<EuiFlexItem grow={false} style={{ minWidth: '420px' }}>
@@ -201,28 +206,42 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
201206
label={i18n.translate('xpack.ml.dataframe.definePivotForm.indexPatternLabel', {
202207
defaultMessage: 'Index pattern',
203208
})}
209+
helpText={
210+
disabledQuery
211+
? i18n.translate('xpack.ml.dataframe.definePivotForm.indexPatternHelpText', {
212+
defaultMessage:
213+
'An optional query for this index pattern is not supported. The number of supported index fields is {maxIndexFields} whereas this index has {numIndexFields} fields.',
214+
values: {
215+
maxIndexFields,
216+
numIndexFields,
217+
},
218+
})
219+
: ''
220+
}
204221
>
205222
<span>{kibanaContext.currentIndexPattern.title}</span>
206223
</EuiFormRow>
207-
<EuiFormRow
208-
label={i18n.translate('xpack.ml.dataframe.definePivotForm.queryLabel', {
209-
defaultMessage: 'Query',
210-
})}
211-
helpText={i18n.translate('xpack.ml.dataframe.definePivotForm.queryHelpText', {
212-
defaultMessage: 'Use a query string to filter the source data (optional).',
213-
})}
214-
>
215-
<EuiFieldSearch
216-
placeholder={i18n.translate(
217-
'xpack.ml.dataframe.definePivotForm.queryPlaceholder',
218-
{
219-
defaultMessage: 'Search...',
220-
}
221-
)}
222-
onChange={searchHandler}
223-
value={search === defaultSearch ? emptySearch : search}
224-
/>
225-
</EuiFormRow>
224+
{!disabledQuery && (
225+
<EuiFormRow
226+
label={i18n.translate('xpack.ml.dataframe.definePivotForm.queryLabel', {
227+
defaultMessage: 'Query',
228+
})}
229+
helpText={i18n.translate('xpack.ml.dataframe.definePivotForm.queryHelpText', {
230+
defaultMessage: 'Use a query string to filter the source data (optional).',
231+
})}
232+
>
233+
<EuiFieldSearch
234+
placeholder={i18n.translate(
235+
'xpack.ml.dataframe.definePivotForm.queryPlaceholder',
236+
{
237+
defaultMessage: 'Search...',
238+
}
239+
)}
240+
onChange={searchHandler}
241+
value={search === defaultSearch ? emptySearch : search}
242+
/>
243+
</EuiFormRow>
244+
)}
226245
</Fragment>
227246
)}
228247

x-pack/plugins/ml/public/data_frame/components/source_index_preview/source_index_preview.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import React, { FunctionComponent, useContext, useState } from 'react';
8+
import moment from 'moment-timezone';
89

910
import { i18n } from '@kbn/i18n';
1011

@@ -36,7 +37,9 @@ interface ExpandableTableProps extends EuiInMemoryTableProps {
3637

3738
const ExpandableTable = (EuiInMemoryTable as any) as FunctionComponent<ExpandableTableProps>;
3839

40+
import { KBN_FIELD_TYPES } from '../../../../common/constants/field_types';
3941
import { Dictionary } from '../../../../common/types/common';
42+
import { formatHumanReadableDateTimeSeconds } from '../../../util/date_utils';
4043

4144
import { isKibanaContext, KibanaContext, PivotQuery } from '../../common';
4245

@@ -208,15 +211,23 @@ export const SourceIndexPreview: React.SFC<Props> = React.memo(({ cellClick, que
208211
const column = {
209212
field: `_source.${k}`,
210213
name: k,
211-
render: undefined,
212214
sortable: true,
213215
truncateText: true,
214216
} as Dictionary<any>;
215217

218+
const field = indexPattern.fields.find(f => f.name === k);
219+
const render = (d: string) => {
220+
return field !== undefined && field.type === KBN_FIELD_TYPES.DATE
221+
? formatHumanReadableDateTimeSeconds(moment(d).unix() * 1000)
222+
: d;
223+
};
224+
225+
column.render = render;
226+
216227
if (CELL_CLICK_ENABLED && cellClick) {
217228
column.render = (d: string) => (
218229
<EuiButtonEmpty size="xs" onClick={() => cellClick(`${k}:(${d})`)}>
219-
{d}
230+
{render(d)}
220231
</EuiButtonEmpty>
221232
);
222233
}

x-pack/plugins/ml/public/data_frame/components/source_index_preview/use_source_index_data.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { IndexPattern } from 'ui/index_patterns';
1212

1313
import { ml } from '../../../services/ml_api_service';
1414

15-
import { PivotQuery } from '../../common';
15+
import { isDefaultQuery, PivotQuery } from '../../common';
1616
import { EsDoc, EsFieldName, getDefaultSelectableFields } from './common';
1717

1818
const SEARCH_SIZE = 1000;
@@ -48,7 +48,8 @@ export const useSourceIndexData = (
4848
const resp: SearchResponse<any> = await ml.esSearch({
4949
index: indexPattern.title,
5050
size: SEARCH_SIZE,
51-
body: { query },
51+
// Instead of using the default query (`*`), fall back to a more efficient `match_all` query.
52+
body: { query: isDefaultQuery(query) ? { match_all: {} } : query },
5253
});
5354

5455
const docs = resp.hits.hits;

0 commit comments

Comments
 (0)