[maps] fix sort not applied to vector tile search request (#134607)

* [maps] fix sort not applied to vector tile search request

* clean up

* clean comment

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* fix jest, integration, and functional test

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2022-06-20 13:52:28 -06:00 committed by GitHub
parent 7cbd0bf15d
commit b7c8ff5d7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 70 deletions

View file

@ -82,47 +82,11 @@ export function getHitsTileRequest({
exact_bounds: true,
extent: 4096, // full resolution,
query: requestBody.query,
fields: mergeFields(
[
requestBody.docvalue_fields as Field[] | undefined,
requestBody.stored_fields as Field[] | undefined,
],
[geometryFieldName]
),
fields: requestBody.fields ? requestBody.fields : [],
runtime_mappings: requestBody.runtime_mappings,
sort: requestBody.sort ? requestBody.sort : [],
track_total_hits: typeof requestBody.size === 'number' ? requestBody.size + 1 : false,
with_labels: hasLabels,
},
};
}
// can not use "import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey"
// SearchRequest is incorrectly typed and does not support Field as object
// https://github.com/elastic/elasticsearch-js/issues/1615
type Field =
| string
| {
field: string;
format: string;
};
function mergeFields(fieldsList: Array<Field[] | undefined>, excludeNames: string[]): Field[] {
const fieldNames: string[] = [];
const mergedFields: Field[] = [];
fieldsList.forEach((fields) => {
if (!fields) {
return;
}
fields.forEach((field) => {
const fieldName = typeof field === 'string' ? field : field.field;
if (!excludeNames.includes(fieldName) && !fieldNames.includes(fieldName)) {
fieldNames.push(fieldName);
mergedFields.push(field);
}
});
});
return mergedFields;
}

View file

@ -116,7 +116,7 @@ describe('ESSearchSource', () => {
});
const tileUrl = await esSearchSource.getTileUrl(searchFilters, '1234', false);
expect(tileUrl).toBe(
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&hasLabels=false&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'1'%3A('0'%3Asize%2C'1'%3A1000)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A'tooltipField%3A%20foobar'))%2C'6'%3A('0'%3AfieldsFromSource%2C'1'%3A!(tooltipField%2CstyleField))%2C'7'%3A('0'%3Asource%2C'1'%3A!(tooltipField%2CstyleField))))&token=1234`
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&hasLabels=false&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'1'%3A('0'%3Asize%2C'1'%3A1000)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A'tooltipField%3A%20foobar'))%2C'6'%3A('0'%3AfieldsFromSource%2C'1'%3A!(_id))%2C'7'%3A('0'%3Asource%2C'1'%3A!f)%2C'8'%3A('0'%3Afields%2C'1'%3A!(tooltipField%2CstyleField))))&token=1234`
);
});
});

View file

@ -827,41 +827,50 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
const indexPattern = await this.getIndexPattern();
const indexSettings = await loadIndexSettings(indexPattern.title);
const fieldNames = searchFilters.fieldNames.filter(
(fieldName) => fieldName !== this._descriptor.geoField
);
const { docValueFields, sourceOnlyFields } = getDocValueAndSourceFields(
indexPattern,
fieldNames,
'epoch_millis'
);
const initialSearchContext = { docvalue_fields: docValueFields }; // Request fields in docvalue_fields insted of _source
const searchSource = await this.makeSearchSource(
searchFilters,
indexSettings.maxResultWindow,
initialSearchContext
);
searchSource.setField('fieldsFromSource', searchFilters.fieldNames); // Setting "fields" filters out unused scripted fields
if (sourceOnlyFields.length === 0) {
searchSource.setField('source', false); // do not need anything from _source
} else {
searchSource.setField('source', sourceOnlyFields);
}
const searchSource = await this.makeSearchSource(searchFilters, indexSettings.maxResultWindow);
// searchSource calls dataView.getComputedFields to seed docvalueFields
// dataView.getComputedFields adds each date field in the dataView to docvalueFields to ensure standardized date format across kibana
// we don't need these as they request unneeded fields and bloat responses
// setting fieldsFromSource notifies searchSource to filterout unused docvalueFields
// '_id' is used since the value of 'fieldsFromSource' is irreverent because '_source: false'.
searchSource.setField('fieldsFromSource', ['_id']);
searchSource.setField('source', false);
if (this._hasSort()) {
searchSource.setField('sort', this._buildEsSort());
}
// use fields API
searchSource.setField(
'fields',
searchFilters.fieldNames
.filter((fieldName) => {
return fieldName !== this._descriptor.geoField;
})
.map((fieldName) => {
const field = indexPattern.fields.getByName(fieldName);
return field && field.type === 'date'
? {
field: fieldName,
format: 'epoch_millis',
}
: fieldName;
})
);
const mvtUrlServicePath = getHttp().basePath.prepend(
`/${GIS_API_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`
);
const requestBody = searchSource.getSearchRequestBody();
// Remove keys not supported by elasticsearch vector tile search API
delete requestBody.script_fields;
delete requestBody.stored_fields;
return `${mvtUrlServicePath}\
?geometryFieldName=${this._descriptor.geoField}\
&index=${indexPattern.title}\
&hasLabels=${hasLabels}\
&requestBody=${encodeMvtResponseBody(searchSource.getSearchRequestBody())}\
&requestBody=${encodeMvtResponseBody(requestBody)}\
&token=${refreshToken}`;
}

View file

@ -80,7 +80,7 @@ test('Should return elasticsearch vector tile request for hits tiles', () => {
expect(
getTileRequest({
layerId: '1',
tileUrl: `http://localhost:5601/pof/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=geo.coordinates&hasLabels=true&index=kibana_sample_data_logs&requestBody=(_source%3A!f%2Cdocvalue_fields%3A!()%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-04-22T16%3A46%3A00.744Z%27%2Clte%3A%272022-04-29T16%3A46%3A05.345Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Cscript_fields%3A()%2Csize%3A10000%2Cstored_fields%3A!(geo.coordinates))&token=415049b6-bb0a-444a-a7b9-89717db5183c`,
tileUrl: `http://localhost:5601/zuv/api/maps/mvt/getTile/4/2/6.pbf?geometryFieldName=geo.coordinates&index=kibana_sample_data_logs&hasLabels=true&requestBody=(_source%3A!f%2Cfields%3A!((field%3A%27%40timestamp%27%2Cformat%3Aepoch_millis)%2Cbytes)%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-06-15T20%3A00%3A00.000Z%27%2Clte%3A%272022-06-16T20%3A48%3A02.517Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Csize%3A10000%2Csort%3A!((%27%40timestamp%27%3A(order%3Adesc%2Cunmapped_type%3Aboolean))))&token=7afe7c2d-c96b-4bdb-9b5e-819aceac80a1`,
x: 0,
y: 0,
z: 2,
@ -98,8 +98,8 @@ test('Should return elasticsearch vector tile request for hits tiles', () => {
range: {
timestamp: {
format: 'strict_date_optional_time',
gte: '2022-04-22T16:46:00.744Z',
lte: '2022-04-29T16:46:05.345Z',
gte: '2022-06-15T20:00:00.000Z',
lte: '2022-06-16T20:48:02.517Z',
},
},
},
@ -109,7 +109,13 @@ test('Should return elasticsearch vector tile request for hits tiles', () => {
should: [],
},
},
fields: [],
fields: [
{
field: '@timestamp',
format: 'epoch_millis',
},
'bytes',
],
runtime_mappings: {
hour_of_day: {
script: {
@ -118,6 +124,14 @@ test('Should return elasticsearch vector tile request for hits tiles', () => {
type: 'long',
},
},
sort: [
{
'@timestamp': {
order: 'desc',
unmapped_type: 'boolean',
},
},
],
track_total_hits: 10001,
with_labels: true,
},

View file

@ -29,7 +29,7 @@ export default function ({ getService }) {
?geometryFieldName=geo.coordinates\
&hasLabels=false\
&index=logstash-*\
&requestBody=(_source:!f,docvalue_fields:!(bytes,geo.coordinates,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10000,stored_fields:!(bytes,geo.coordinates,machine.os.raw,'@timestamp'))`
&requestBody=(_source:!f,fields:!(bytes,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10000)`
)
.set('kbn-xsrf', 'kibana')
.responseType('blob')
@ -93,7 +93,7 @@ export default function ({ getService }) {
?geometryFieldName=geo.coordinates\
&hasLabels=true\
&index=logstash-*\
&requestBody=(_source:!f,docvalue_fields:!(bytes,geo.coordinates,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10000,stored_fields:!(bytes,geo.coordinates,machine.os.raw,'@timestamp'))`
&requestBody=(_source:!f,fields:!(bytes,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10000)`
)
.set('kbn-xsrf', 'kibana')
.responseType('blob')
@ -138,7 +138,7 @@ export default function ({ getService }) {
?geometryFieldName=geo.coordinates\
&hasLabels=false\
&index=notRealIndex\
&requestBody=(_source:!f,docvalue_fields:!(bytes,geo.coordinates,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10000,stored_fields:!(bytes,geo.coordinates,machine.os.raw,'@timestamp'))`
&requestBody=(_source:!f,fields:!(bytes,machine.os.raw,(field:'@timestamp',format:epoch_millis)),query:(bool:(filter:!((match_all:()),(range:(%27@timestamp%27:(format:strict_date_optional_time,gte:%272015-09-20T00:00:00.000Z%27,lte:%272015-09-20T01:00:00.000Z%27)))),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10000)`
)
.set('kbn-xsrf', 'kibana')
.responseType('blob')

View file

@ -53,7 +53,7 @@ export default function ({ getPageObjects, getService }) {
hasLabels: 'false',
index: 'geo_shapes*',
requestBody:
'(_source:!f,docvalue_fields:!(prop1),query:(bool:(filter:!(),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10001,stored_fields:!(geometry,prop1))',
'(_source:!f,fields:!(prop1),query:(bool:(filter:!(),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10001)',
});
});