[Maps] Support query-time runtime fields (#95701)

This commit is contained in:
Thomas Neirynck 2021-04-07 15:00:55 -04:00 committed by GitHub
parent 88847b9845
commit 324c6c05a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 52 deletions

View file

@ -61,54 +61,12 @@ import { DataRequest } from '../../util/data_request';
import { SortDirection, SortDirectionNumeric } from '../../../../../../../src/plugins/data/common';
import { isValidStringConfig } from '../../util/valid_string_config';
import { TopHitsUpdateSourceEditor } from './top_hits';
import { getDocValueAndSourceFields, ScriptField } from './get_docvalue_source_fields';
export const sourceTitle = i18n.translate('xpack.maps.source.esSearchTitle', {
defaultMessage: 'Documents',
});
export interface ScriptField {
source: string;
lang: string;
}
function getDocValueAndSourceFields(
indexPattern: IndexPattern,
fieldNames: string[],
dateFormat: string
): {
docValueFields: Array<string | { format: string; field: string }>;
sourceOnlyFields: string[];
scriptFields: Record<string, { script: ScriptField }>;
} {
const docValueFields: Array<string | { format: string; field: string }> = [];
const sourceOnlyFields: string[] = [];
const scriptFields: Record<string, { script: ScriptField }> = {};
fieldNames.forEach((fieldName) => {
const field = getField(indexPattern, fieldName);
if (field.scripted) {
scriptFields[field.name] = {
script: {
source: field.script || '',
lang: field.lang || '',
},
};
} else if (field.readFromDocValues) {
const docValueField =
field.type === 'date'
? {
field: fieldName,
format: dateFormat,
}
: fieldName;
docValueFields.push(docValueField);
} else {
sourceOnlyFields.push(fieldName);
}
});
return { docValueFields, sourceOnlyFields, scriptFields };
}
export class ESSearchSource extends AbstractESSource implements ITiledSingleLayerVectorSource {
readonly _descriptor: ESSearchSourceDescriptor;
protected readonly _tooltipFields: ESDocField[];

View file

@ -0,0 +1,42 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getDocValueAndSourceFields } from './get_docvalue_source_fields';
import { IndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import { IFieldType } from '../../../../../../../src/plugins/data/common/index_patterns/fields';
function createMockIndexPattern(fields: IFieldType[]): IndexPattern {
const indexPattern = {
get fields() {
return {
getByName(fieldname: string) {
return fields.find((f) => f.name === fieldname);
},
};
},
};
return (indexPattern as unknown) as IndexPattern;
}
describe('getDocValueAndSourceFields', () => {
it('should add runtime fields to docvalue fields', () => {
const { docValueFields } = getDocValueAndSourceFields(
createMockIndexPattern([
{
name: 'foobar',
// @ts-expect-error runtimeField not added yet to IFieldType. API tbd
runtimeField: {},
},
]),
['foobar'],
'epoch_millis'
);
expect(docValueFields).toEqual(['foobar']);
});
});

View file

@ -0,0 +1,54 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { IndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import { getField } from '../../../../common/elasticsearch_util';
export interface ScriptField {
source: string;
lang: string;
}
export function getDocValueAndSourceFields(
indexPattern: IndexPattern,
fieldNames: string[],
dateFormat: string
): {
docValueFields: Array<string | { format: string; field: string }>;
sourceOnlyFields: string[];
scriptFields: Record<string, { script: ScriptField }>;
} {
const docValueFields: Array<string | { format: string; field: string }> = [];
const sourceOnlyFields: string[] = [];
const scriptFields: Record<string, { script: ScriptField }> = {};
fieldNames.forEach((fieldName) => {
const field = getField(indexPattern, fieldName);
if (field.scripted) {
scriptFields[field.name] = {
script: {
source: field.script || '',
lang: field.lang || '',
},
};
}
// @ts-expect-error runtimeField has not been added to public API yet. exact shape of type TBD.
else if (field.readFromDocValues || field.runtimeField) {
const docValueField =
field.type === 'date'
? {
field: fieldName,
format: dateFormat,
}
: fieldName;
docValueFields.push(docValueField);
} else {
sourceOnlyFields.push(fieldName);
}
});
return { docValueFields, sourceOnlyFields, scriptFields };
}

View file

@ -69,7 +69,9 @@ export default function ({ getPageObjects, getService }) {
await dashboardPanelActions.openInspectorByTitle('join example');
await retry.try(async () => {
const joinExampleRequestNames = await inspector.getRequestNames();
expect(joinExampleRequestNames).to.equal('geo_shapes*,meta_for_geo_shapes*.shape_name');
expect(joinExampleRequestNames).to.equal(
'geo_shapes*,meta_for_geo_shapes*.runtime_shape_name'
);
});
await inspector.close();
@ -90,7 +92,7 @@ export default function ({ getPageObjects, getService }) {
await filterBar.selectIndexPattern('logstash-*');
await filterBar.addFilter('machine.os', 'is', 'win 8');
await filterBar.selectIndexPattern('meta_for_geo_shapes*');
await filterBar.addFilter('shape_name', 'is', 'alpha');
await filterBar.addFilter('shape_name', 'is', 'alpha'); // runtime fields do not have autocomplete
const gridResponse = await PageObjects.maps.getResponseFromDashboardPanel(
'geo grid vector grid example'
@ -99,7 +101,7 @@ export default function ({ getPageObjects, getService }) {
const joinResponse = await PageObjects.maps.getResponseFromDashboardPanel(
'join example',
'meta_for_geo_shapes*.shape_name'
'meta_for_geo_shapes*.runtime_shape_name'
);
expect(joinResponse.aggregations.join.buckets.length).to.equal(1);
});

View file

@ -59,7 +59,7 @@ export default function ({ getPageObjects, getService }) {
// const hasSourceFilter = await filterBar.hasFilter('name', 'charlie');
// expect(hasSourceFilter).to.be(true);
const hasJoinFilter = await filterBar.hasFilter('shape_name', 'charlie');
const hasJoinFilter = await filterBar.hasFilter('runtime_shape_name', 'charlie');
expect(hasJoinFilter).to.be(true);
});
});
@ -78,7 +78,7 @@ export default function ({ getPageObjects, getService }) {
const panelCount = await PageObjects.dashboard.getPanelCount();
expect(panelCount).to.equal(2);
const hasJoinFilter = await filterBar.hasFilter('shape_name', 'charlie');
const hasJoinFilter = await filterBar.hasFilter('runtime_shape_name', 'charlie');
expect(hasJoinFilter).to.be(true);
});

View file

@ -39,7 +39,7 @@ export default function ({ getPageObjects, getService }) {
it('should re-fetch join with refresh timer', async () => {
async function getRequestTimestamp() {
await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.shape_name');
await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.runtime_shape_name');
const requestStats = await inspector.getTableData();
const requestTimestamp = PageObjects.maps.getInspectorStatRowHit(
requestStats,
@ -121,7 +121,9 @@ export default function ({ getPageObjects, getService }) {
});
it('should not apply query to source and apply query to join', async () => {
const joinResponse = await PageObjects.maps.getResponse('meta_for_geo_shapes*.shape_name');
const joinResponse = await PageObjects.maps.getResponse(
'meta_for_geo_shapes*.runtime_shape_name'
);
expect(joinResponse.aggregations.join.buckets.length).to.equal(2);
});
});
@ -136,7 +138,9 @@ export default function ({ getPageObjects, getService }) {
});
it('should apply query to join request', async () => {
const joinResponse = await PageObjects.maps.getResponse('meta_for_geo_shapes*.shape_name');
const joinResponse = await PageObjects.maps.getResponse(
'meta_for_geo_shapes*.runtime_shape_name'
);
expect(joinResponse.aggregations.join.buckets.length).to.equal(1);
});

View file

@ -51,6 +51,7 @@
"index": ".kibana",
"source": {
"index-pattern": {
"runtimeFieldMap" : "{\"runtime_shape_name\":{\"type\":\"keyword\",\"script\":{\"source\":\"emit(doc['shape_name'].value)\"}}}",
"fields" : "[]",
"title": "meta_for_geo_shapes*"
},
@ -498,7 +499,7 @@
"type": "envelope"
},
"description": "",
"layerListJSON" : "[{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"applyGlobalQuery\":false,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3},\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"applyGlobalQuery\":true,\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]",
"layerListJSON" : "[{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"applyGlobalQuery\":false,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3},\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.runtime_shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.runtime_shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"runtime_shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"applyGlobalQuery\":true,\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]",
"mapStateJSON": "{\"zoom\":3.02,\"center\":{\"lon\":77.33426,\"lat\":-0.04647},\"timeFilters\":{\"from\":\"now-17m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}",
"title": "join example",
"uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"n1t6f\"]}"

View file

@ -136,6 +136,9 @@
"fieldFormatMap": {
"type": "text"
},
"runtimeFieldMap": {
"type": "text"
},
"fields": {
"type": "text"
},