Skip to content

Commit

Permalink
[Lens] Supports include and exclude terms (#136179)
Browse files Browse the repository at this point in the history
* [Lens] Supports include and exclude terms

* Change type

* Fix pattern logic

* Adds unit tests

* Implement it with 2 extra properties on the expression

* Distinguish the regex and exact match bejhavior

* Enables transferring of include/exclude from TSVB

* Fix tests

* Fix tests

* Update all snapshots

* Update texts

* Revers screenshots

* Use debounce value instead

* Placeholder change

Co-authored-by: Joe Reuter <[email protected]>
  • Loading branch information
stratoula and flash1293 authored Jul 19, 2022
1 parent d4f549c commit 004369d
Show file tree
Hide file tree
Showing 51 changed files with 846 additions and 43 deletions.
12 changes: 12 additions & 0 deletions src/plugins/data/common/search/aggs/agg_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,18 @@ describe('AggConfig', () => {
"enabled": Array [
true,
],
"excludeIsRegex": Array [
true,
],
"field": Array [
"machine.os.keyword",
],
"id": Array [
"1",
],
"includeIsRegex": Array [
true,
],
"missingBucket": Array [
false,
],
Expand Down Expand Up @@ -629,12 +635,18 @@ describe('AggConfig', () => {
"enabled": Array [
true,
],
"excludeIsRegex": Array [
true,
],
"field": Array [
"bytes",
],
"id": Array [
"1-orderAgg",
],
"includeIsRegex": Array [
true,
],
"missingBucket": Array [
false,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ export const migrateIncludeExcludeFormat = {
if (parsedValue.length) {
output.params[this.name] = parsedValue;
}
} else if (Array.isArray(value) && value.length > 0 && isStringType(aggConfig)) {
// check if is regex
const filtered = value.filter((val) => val !== '');
if (filtered.length) {
const isRegularExpression = aggConfig.getParam(`${this.name}IsRegex`);
output.params[this.name] = isRegularExpression ? filtered[0] : filtered;
}
} else if (isObject(value)) {
output.params[this.name] = (value as any).pattern;
} else if (value && isStringType(aggConfig)) {
Expand Down
70 changes: 70 additions & 0 deletions src/plugins/data/common/search/aggs/buckets/terms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,18 @@ describe('Terms Agg', () => {
"enabled": Array [
true,
],
"excludeIsRegex": Array [
true,
],
"field": Array [
"field",
],
"id": Array [
"test",
],
"includeIsRegex": Array [
true,
],
"missingBucket": Array [
false,
],
Expand Down Expand Up @@ -196,6 +202,70 @@ describe('Terms Agg', () => {
expect(params.exclude).toBe('exclude value');
});

test('accepts array of strings from string field type and writes this value', () => {
const aggConfigs = getAggConfigs({
include: ['include1', 'include2'],
exclude: ['exclude1'],
includeIsRegex: false,
excludeIsRegex: false,
field: {
name: 'string_field',
type: 'string',
},
orderAgg: {
type: 'count',
},
});

const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl();

expect(params.field).toBe('string_field');
expect(params.include).toStrictEqual(['include1', 'include2']);
expect(params.exclude).toStrictEqual(['exclude1']);
});

test('accepts array of string with regex and returns the pattern', () => {
const aggConfigs = getAggConfigs({
include: ['include.*'],
exclude: ['exclude.*'],
includeIsRegex: true,
excludeIsRegex: true,
field: {
name: 'string_field',
type: 'string',
},
orderAgg: {
type: 'count',
},
});

const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl();

expect(params.field).toBe('string_field');
expect(params.include).toBe('include.*');
expect(params.exclude).toBe('exclude.*');
});

test('accepts array of empty strings and does not write a value', () => {
const aggConfigs = getAggConfigs({
include: [''],
exclude: [''],
field: {
name: 'string_field',
type: 'string',
},
orderAgg: {
type: 'count',
},
});

const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl();

expect(params.field).toBe('string_field');
expect(params.include).toBe(undefined);
expect(params.exclude).toBe(undefined);
});

test('accepts empty array from number field type and does not write a value', () => {
const aggConfigs = getAggConfigs({
include: [],
Expand Down
16 changes: 14 additions & 2 deletions src/plugins/data/common/search/aggs/buckets/terms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ export interface AggParamsTerms extends BaseAggParams {
otherBucket?: boolean;
otherBucketLabel?: string;
// advanced
exclude?: string;
include?: string;
exclude?: string[] | number[];
include?: string[] | number[];
includeIsRegex?: boolean;
excludeIsRegex?: boolean;
}

export const getTermsBucketAgg = () =>
Expand Down Expand Up @@ -178,5 +180,15 @@ export const getTermsBucketAgg = () =>
shouldShow: isStringOrNumberType,
...migrateIncludeExcludeFormat,
},
{
name: 'includeIsRegex',
default: true,
write: noop,
},
{
name: 'excludeIsRegex',
default: true,
write: noop,
},
],
});
20 changes: 16 additions & 4 deletions src/plugins/data/common/search/aggs/buckets/terms_fn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ describe('agg_expression_functions', () => {
"params": Object {
"customLabel": undefined,
"exclude": undefined,
"excludeIsRegex": undefined,
"field": "machine.os.keyword",
"include": undefined,
"includeIsRegex": undefined,
"json": undefined,
"missingBucket": undefined,
"missingBucketLabel": undefined,
Expand Down Expand Up @@ -61,8 +63,8 @@ describe('agg_expression_functions', () => {
missingBucketLabel: 'missing',
otherBucket: true,
otherBucketLabel: 'other',
include: 'win',
exclude: 'ios',
include: ['win'],
exclude: ['ios'],
});

expect(actual.value).toMatchInlineSnapshot(`
Expand All @@ -71,9 +73,15 @@ describe('agg_expression_functions', () => {
"id": "1",
"params": Object {
"customLabel": undefined,
"exclude": "ios",
"exclude": Array [
"ios",
],
"excludeIsRegex": undefined,
"field": "machine.os.keyword",
"include": "win",
"include": Array [
"win",
],
"includeIsRegex": undefined,
"json": undefined,
"missingBucket": true,
"missingBucketLabel": "missing",
Expand Down Expand Up @@ -103,8 +111,10 @@ describe('agg_expression_functions', () => {
Object {
"customLabel": undefined,
"exclude": undefined,
"excludeIsRegex": undefined,
"field": "machine.os.keyword",
"include": undefined,
"includeIsRegex": undefined,
"json": undefined,
"missingBucket": undefined,
"missingBucketLabel": undefined,
Expand All @@ -115,8 +125,10 @@ describe('agg_expression_functions', () => {
"params": Object {
"customLabel": undefined,
"exclude": undefined,
"excludeIsRegex": undefined,
"field": "name",
"include": undefined,
"includeIsRegex": undefined,
"json": undefined,
"missingBucket": undefined,
"missingBucketLabel": undefined,
Expand Down
18 changes: 16 additions & 2 deletions src/plugins/data/common/search/aggs/buckets/terms_fn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,30 @@ export const aggTerms = (): FunctionDefinition => ({
}),
},
exclude: {
types: ['string'],
types: ['string', 'number'],
help: i18n.translate('data.search.aggs.buckets.terms.exclude.help', {
defaultMessage: 'Specific bucket values to exclude from results',
}),
multi: true,
},
include: {
types: ['string'],
types: ['string', 'number'],
help: i18n.translate('data.search.aggs.buckets.terms.include.help', {
defaultMessage: 'Specific bucket values to include in results',
}),
multi: true,
},
includeIsRegex: {
types: ['boolean'],
help: i18n.translate('data.search.aggs.buckets.terms.includeIsRegex.help', {
defaultMessage: 'When set to true, the include property is handled as regex',
}),
},
excludeIsRegex: {
types: ['boolean'],
help: i18n.translate('data.search.aggs.buckets.terms.excludeIsRegex.help', {
defaultMessage: 'When set to true, the exclude property is handled as regex',
}),
},
json: {
types: ['string'],
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/data/common/search/tabify/response_writer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ describe('TabbedAggResponseWriter class', () => {
order: 'desc',
otherBucket: false,
otherBucketLabel: 'Other',
includeIsRegex: true,
excludeIsRegex: true,
size: 5,
},
type: 'terms',
Expand Down Expand Up @@ -245,6 +247,8 @@ describe('TabbedAggResponseWriter class', () => {
otherBucket: false,
otherBucketLabel: 'Other',
size: 5,
includeIsRegex: true,
excludeIsRegex: true,
},
type: 'terms',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,37 @@ describe('triggerTSVBtoLensConfiguration', () => {
otherBucket: false,
orderDirection: 'desc',
orderBy: { type: 'alphabetical' },
includeIsRegex: false,
excludeIsRegex: false,
parentFormat: {
id: 'terms',
},
});
});

test('should return include exclude information if the chart is broken down by terms', async () => {
const modelWithTerms = {
...model,
series: [
{
...model.series[0],
split_mode: 'terms',
terms_size: 6,
terms_direction: 'desc',
terms_order_by: '_key',
terms_include: 't.*',
},
] as unknown as Series[],
};
const triggerOptions = await triggerTSVBtoLensConfiguration(modelWithTerms);
expect(triggerOptions?.layers[0]?.termsParams).toStrictEqual({
size: 6,
otherBucket: false,
orderDirection: 'desc',
orderBy: { type: 'alphabetical' },
includeIsRegex: true,
include: ['t.*'],
excludeIsRegex: false,
parentFormat: {
id: 'terms',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ export const triggerTSVBtoLensConfiguration = async (
...(layer.split_mode === 'terms' && {
termsParams: {
size: layer.terms_size ?? 10,
...(layer.terms_include && { include: [layer.terms_include] }),
includeIsRegex: Boolean(layer.terms_include),
...(layer.terms_exclude && { exclude: [layer.terms_exclude] }),
excludeIsRegex: Boolean(layer.terms_exclude),
otherBucket: false,
orderDirection: layer.terms_direction ?? 'desc',
orderBy: layer.terms_order_by === '_key' ? { type: 'alphabetical' } : { type: 'column' },
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
Loading

0 comments on commit 004369d

Please sign in to comment.