Skip to content

Commit

Permalink
[Lens] Show field stats for IP fields and scripted fields (#76457) (#…
Browse files Browse the repository at this point in the history
…76987)

Co-authored-by: Elastic Machine <[email protected]>

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
Wylie Conlon and elasticmachine authored Sep 8, 2020
1 parent 8be4ad6 commit 78e2ed1
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,7 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) {
);

function fetchData() {
if (
state.isLoading ||
(field.type !== 'number' &&
field.type !== 'string' &&
field.type !== 'date' &&
field.type !== 'boolean' &&
field.type !== 'ip')
) {
if (state.isLoading) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ const indexPattern1 = ({
searchable: true,
esTypes: ['keyword'],
},
{
name: 'scripted',
displayName: 'Scripted',
type: 'string',
searchable: true,
aggregatable: true,
scripted: true,
lang: 'painless',
script: '1234',
},
documentField,
],
} as unknown) as IndexPattern;
Expand Down Expand Up @@ -156,12 +166,13 @@ const indexPattern2 = ({
aggregatable: true,
searchable: true,
scripted: true,
lang: 'painless',
script: '1234',
aggregationRestrictions: {
terms: {
agg: 'terms',
},
},
esTypes: ['keyword'],
},
documentField,
],
Expand Down
30 changes: 21 additions & 9 deletions x-pack/plugins/lens/public/indexpattern_datasource/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,27 @@ export async function loadIndexPatterns({
!indexPatternsUtils.isNestedField(field) && (!!field.aggregatable || !!field.scripted)
)
.map(
(field): IndexPatternField => ({
name: field.name,
displayName: field.displayName,
type: field.type,
aggregatable: field.aggregatable,
searchable: field.searchable,
scripted: field.scripted,
esTypes: field.esTypes,
})
(field): IndexPatternField => {
// Convert the getters on the index pattern service into plain JSON
const base = {
name: field.name,
displayName: field.displayName,
type: field.type,
aggregatable: field.aggregatable,
searchable: field.searchable,
esTypes: field.esTypes,
scripted: field.scripted,
};

// Simplifies tests by hiding optional properties instead of undefined
return base.scripted
? {
...base,
lang: field.lang,
script: field.script,
}
: base;
}
)
.concat(documentField);

Expand Down
12 changes: 12 additions & 0 deletions x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ export const createMockedIndexPattern = (): IndexPattern => ({
searchable: true,
esTypes: ['keyword'],
},
{
name: 'scripted',
displayName: 'Scripted',
type: 'string',
searchable: true,
aggregatable: true,
scripted: true,
lang: 'painless',
script: '1234',
},
],
});

Expand Down Expand Up @@ -95,6 +105,8 @@ export const createMockedRestrictedIndexPattern = () => ({
searchable: true,
scripted: true,
esTypes: ['keyword'],
lang: 'painless',
script: '1234',
},
],
typeMeta: {
Expand Down
11 changes: 3 additions & 8 deletions x-pack/plugins/lens/public/indexpattern_datasource/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { IFieldType } from 'src/plugins/data/common';
import { IndexPatternColumn } from './operations';
import { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/public';

Expand All @@ -22,16 +23,10 @@ export interface IndexPattern {
hasRestrictions: boolean;
}

export interface IndexPatternField {
name: string;
export type IndexPatternField = IFieldType & {
displayName: string;
type: string;
esTypes?: string[];
aggregatable: boolean;
scripted?: boolean;
searchable: boolean;
aggregationRestrictions?: Partial<IndexPatternAggRestrictions>;
}
};

export interface IndexPatternLayer {
columnOrder: string[];
Expand Down
50 changes: 33 additions & 17 deletions x-pack/plugins/lens/server/routes/field_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Boom from 'boom';
import DateMath from '@elastic/datemath';
import { schema } from '@kbn/config-schema';
import { CoreSetup } from 'src/core/server';
import { IFieldType } from 'src/plugins/data/common';
import { ESSearchResponse } from '../../../apm/typings/elasticsearch';
import { FieldStatsResponse, BASE_API_URL } from '../../common';

Expand All @@ -33,6 +34,9 @@ export async function initFieldsRoute(setup: CoreSetup) {
name: schema.string(),
type: schema.string(),
esTypes: schema.maybe(schema.arrayOf(schema.string())),
scripted: schema.maybe(schema.boolean()),
lang: schema.maybe(schema.string()),
script: schema.maybe(schema.string()),
},
{ unknowns: 'allow' }
),
Expand Down Expand Up @@ -83,21 +87,15 @@ export async function initFieldsRoute(setup: CoreSetup) {
return res.ok({
body: await getNumberHistogram(search, field),
});
} else if (field.type === 'string') {
return res.ok({
body: await getStringSamples(search, field),
});
} else if (field.type === 'date') {
return res.ok({
body: await getDateHistogram(search, field, { fromDate, toDate }),
});
} else if (field.type === 'boolean') {
return res.ok({
body: await getStringSamples(search, field),
});
}

return res.ok({});
return res.ok({
body: await getStringSamples(search, field),
});
} catch (e) {
if (e.status === 404) {
return res.notFound();
Expand All @@ -119,8 +117,10 @@ export async function initFieldsRoute(setup: CoreSetup) {

export async function getNumberHistogram(
aggSearchWithBody: (body: unknown) => Promise<unknown>,
field: { name: string; type: string; esTypes?: string[] }
field: IFieldType
): Promise<FieldStatsResponse> {
const fieldRef = getFieldRef(field);

const searchBody = {
sample: {
sampler: { shard_size: SHARD_SIZE },
Expand All @@ -131,9 +131,9 @@ export async function getNumberHistogram(
max_value: {
max: { field: field.name },
},
sample_count: { value_count: { field: field.name } },
sample_count: { value_count: { ...fieldRef } },
top_values: {
terms: { field: field.name, size: 10 },
terms: { ...fieldRef, size: 10 },
},
},
},
Expand Down Expand Up @@ -206,15 +206,20 @@ export async function getNumberHistogram(

export async function getStringSamples(
aggSearchWithBody: (body: unknown) => unknown,
field: { name: string; type: string }
field: IFieldType
): Promise<FieldStatsResponse> {
const fieldRef = getFieldRef(field);

const topValuesBody = {
sample: {
sampler: { shard_size: SHARD_SIZE },
aggs: {
sample_count: { value_count: { field: field.name } },
sample_count: { value_count: { ...fieldRef } },
top_values: {
terms: { field: field.name, size: 10 },
terms: {
...fieldRef,
size: 10,
},
},
},
},
Expand All @@ -241,7 +246,7 @@ export async function getStringSamples(
// This one is not sampled so that it returns the full date range
export async function getDateHistogram(
aggSearchWithBody: (body: unknown) => unknown,
field: { name: string; type: string },
field: IFieldType,
range: { fromDate: string; toDate: string }
): Promise<FieldStatsResponse> {
const fromDate = DateMath.parse(range.fromDate);
Expand All @@ -265,7 +270,7 @@ export async function getDateHistogram(
const fixedInterval = `${interval}ms`;

const histogramBody = {
histo: { date_histogram: { field: field.name, fixed_interval: fixedInterval } },
histo: { date_histogram: { ...getFieldRef(field), fixed_interval: fixedInterval } },
};
const results = (await aggSearchWithBody(histogramBody)) as ESSearchResponse<
unknown,
Expand All @@ -283,3 +288,14 @@ export async function getDateHistogram(
},
};
}

function getFieldRef(field: IFieldType) {
return field.scripted
? {
script: {
lang: field.lang as string,
source: field.script as string,
},
}
: { field: field.name };
}
Loading

0 comments on commit 78e2ed1

Please sign in to comment.