Skip to content

Commit

Permalink
significant text agg wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Dosant committed Dec 30, 2021
1 parent 828321c commit aae5f28
Show file tree
Hide file tree
Showing 13 changed files with 513 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/plugins/data/common/search/aggs/agg_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const getAggTypes = () => ({
{ name: BUCKET_TYPES.FILTER, fn: buckets.getFilterBucketAgg },
{ name: BUCKET_TYPES.FILTERS, fn: buckets.getFiltersBucketAgg },
{ name: BUCKET_TYPES.SIGNIFICANT_TERMS, fn: buckets.getSignificantTermsBucketAgg },
{ name: BUCKET_TYPES.SIGNIFICANT_TEXT, fn: buckets.getSignificantTextBucketAgg },
{ name: BUCKET_TYPES.GEOHASH_GRID, fn: buckets.getGeoHashBucketAgg },
{ name: BUCKET_TYPES.GEOTILE_GRID, fn: buckets.getGeoTitleBucketAgg },
{ name: BUCKET_TYPES.SAMPLER, fn: buckets.getSamplerBucketAgg },
Expand All @@ -71,6 +72,7 @@ export const getAggTypesFunctions = () => [
buckets.aggFilter,
buckets.aggFilters,
buckets.aggSignificantTerms,
buckets.aggSignificantText,
buckets.aggIpRange,
buckets.aggDateRange,
buckets.aggRange,
Expand Down
12 changes: 10 additions & 2 deletions src/plugins/data/common/search/aggs/buckets/bucket_agg_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

import moment from 'moment';
import { IAggConfig } from '../agg_config';
import { GenericBucket, IAggConfigs, KBN_FIELD_TYPES } from '../../../../common';
import { FilterFieldFn, GenericBucket, IAggConfigs } from '../../../../common';
import { AggType, AggTypeConfig } from '../agg_type';
import { AggParamType } from '../param_types/agg';
import type { FieldTypes } from '../param_types/field';

export interface IBucketAggConfig extends IAggConfig {
type: InstanceType<typeof BucketAggType>;
Expand All @@ -19,7 +20,14 @@ export interface IBucketAggConfig extends IAggConfig {
export interface BucketAggParam<TBucketAggConfig extends IAggConfig>
extends AggParamType<TBucketAggConfig> {
scriptable?: boolean;
filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*';
filterFieldTypes?: FieldTypes;
onlyAggregatable?: boolean;

/**
* Filter available fields by passing filter fn on a {@link DataViewField}
* If used, takes precedence over filterFieldTypes and other filter params
*/
filterField?: FilterFieldFn;
}

const bucketType = 'buckets';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum BUCKET_TYPES {
TERMS = 'terms',
MULTI_TERMS = 'multi_terms',
SIGNIFICANT_TERMS = 'significant_terms',
SIGNIFICANT_TEXT = 'significant_text',
GEOHASH_GRID = 'geohash_grid',
GEOTILE_GRID = 'geotile_grid',
DATE_HISTOGRAM = 'date_histogram',
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/common/search/aggs/buckets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export * from './range_fn';
export * from './range';
export * from './significant_terms_fn';
export * from './significant_terms';
export * from './significant_text_fn';
export * from './significant_text';
export * from './terms_fn';
export * from './terms';
export * from './multi_terms_fn';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';

describe('Significant Text Agg', () => {
const getAggConfigs = (params: Record<string, any> = {}) => {
const indexPattern = {
id: '1234',
title: 'logstash-*',
fields: {
getByName: () => field,
filter: () => [field],
},
} as any;

const field = {
name: 'field',
indexPattern,
};

return new AggConfigs(
indexPattern,
[
{
id: 'test',
type: BUCKET_TYPES.SIGNIFICANT_TEXT,
params,
},
],
{
typesRegistry: mockAggTypesRegistry(),
}
);
};

test('produces the expected expression ast', () => {
const aggConfigs = getAggConfigs({
size: 'SIZE',
field: {
name: 'FIELD',
},
});
expect(aggConfigs.aggs[0].toExpressionAst()).toMatchInlineSnapshot(`
Object {
"chain": Array [
Object {
"arguments": Object {
"enabled": Array [
true,
],
"field": Array [
"FIELD",
],
"id": Array [
"test",
],
"size": Array [
"SIZE",
],
},
"function": "aggSignificantText",
"type": "function",
},
],
"type": "expression",
}
`);
});

test('should generate correct label', () => {
const aggConfigs = getAggConfigs({
size: 'SIZE',
field: {
name: 'FIELD',
},
});
const label = aggConfigs.aggs[0].makeLabel();

expect(label).toBe('Top SIZE unusual terms from "FIELD" text');
});
});
90 changes: 90 additions & 0 deletions src/plugins/data/common/search/aggs/buckets/significant_text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { i18n } from '@kbn/i18n';
import { BucketAggType } from './bucket_agg_type';
import { migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
import { BUCKET_TYPES } from './bucket_agg_types';
import { aggSignificantTextFnName } from './significant_text_fn';
import { KBN_FIELD_TYPES, ES_FIELD_TYPES } from '../../../../common';
import { BaseAggParams } from '../types';
import { createFilterTerms } from './create_filter/terms';

const significantTextTitle = i18n.translate('data.search.aggs.buckets.significantTextTitle', {
defaultMessage: 'Significant Text',
});

export interface AggParamsSignificantText extends BaseAggParams {
field: string;
size?: number;
min_doc_count?: number;
filter_duplicate_text?: boolean;
exclude?: string;
include?: string;
}

export const getSignificantTextBucketAgg = () =>
new BucketAggType({
name: BUCKET_TYPES.SIGNIFICANT_TEXT,
expressionName: aggSignificantTextFnName,
title: significantTextTitle,
makeLabel(aggConfig) {
return i18n.translate('data.search.aggs.buckets.significantTextLabel', {
defaultMessage: 'Top {size} unusual terms from "{fieldName}" text',
values: {
size: aggConfig.params.size,
fieldName: aggConfig.getFieldDisplayName(),
},
});
},
createFilter: createFilterTerms,
params: [
{
name: 'field',
type: 'field',
/**
* Significant text is available only for ES_FIELD_TYPES.TEXT,
* This information is not available from field.type, so we have to check this using underlying esTypes
*/
filterField: (field) =>
Boolean(
field.type === KBN_FIELD_TYPES.STRING && field.esTypes?.includes(ES_FIELD_TYPES.TEXT)
),
},
{
name: 'size',
type: 'number',
},
{
name: 'min_doc_count',
type: 'number',
},
{
name: 'filter_duplicate_text',
type: 'boolean',
},
{
name: 'exclude',
displayName: i18n.translate('data.search.aggs.buckets.significantText.excludeLabel', {
defaultMessage: 'Exclude',
}),
type: 'string',
advanced: true,
...migrateIncludeExcludeFormat,
},
{
name: 'include',
displayName: i18n.translate('data.search.aggs.buckets.significantText.includeLabel', {
defaultMessage: 'Include',
}),
type: 'string',
advanced: true,
...migrateIncludeExcludeFormat,
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { functionWrapper } from '../test_helpers';
import { aggSignificantText } from './significant_text_fn';

describe('agg_expression_functions', () => {
describe('aggSignificantText', () => {
const fn = functionWrapper(aggSignificantText());

test('fills in defaults when only required args are provided', () => {
const actual = fn({
field: 'machine.os',
});
expect(actual).toMatchInlineSnapshot(`
Object {
"type": "agg_type",
"value": Object {
"enabled": true,
"id": undefined,
"params": Object {
"customLabel": undefined,
"exclude": undefined,
"field": "machine.os",
"filter_duplicate_text": undefined,
"include": undefined,
"json": undefined,
"min_doc_count": undefined,
"size": undefined,
},
"schema": undefined,
"type": "significant_text",
},
}
`);
});

test('includes optional params when they are provided', () => {
const actual = fn({
id: '1',
enabled: false,
schema: 'whatever',
field: 'machine.os',
size: 6,
include: 'win',
exclude: 'ios',
filter_duplicate_text: true,
min_doc_count: 10,
});

expect(actual.value).toMatchInlineSnapshot(`
Object {
"enabled": false,
"id": "1",
"params": Object {
"customLabel": undefined,
"exclude": "ios",
"field": "machine.os",
"filter_duplicate_text": true,
"include": "win",
"json": undefined,
"min_doc_count": 10,
"size": 6,
},
"schema": "whatever",
"type": "significant_text",
}
`);
});

test('correctly parses json string argument', () => {
const actual = fn({
field: 'machine.os',
json: '{ "foo": true }',
});

expect(actual.value.params.json).toEqual('{ "foo": true }');
});
});
});
Loading

0 comments on commit aae5f28

Please sign in to comment.