[maps] ignore indices without geometry field in vector tile requests (#171472)

Closes https://github.com/elastic/kibana/issues/170656

PR adds exists filter to ensure geo field exists 

### Test instructions
1. In console, run:
    ```
    PUT geo1
    {}

    PUT geo1/_mapping
    {
      "properties": {
        "location": {
          "type": "geo_point"
        }
      }
    }

    PUT geo1/_doc/1
    {
      "location": "25,25"
    }

    PUT geo2
    {}

    PUT geo2/_doc/1
    {}
    ```
2. Create `geo*` data view
3. create new map
4. add documents layer from `geo*` data view.
5. Add heatmap layer from `geo*` data view.
6. Verify geo1 data is displayed and warning is not displayed fro geo2
shard failures

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-11-22 12:37:52 -07:00 committed by GitHub
parent e402684c2f
commit 76f6dc3d13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 31 additions and 5 deletions

View file

@ -27,6 +27,13 @@ import { LICENSED_FEATURES } from '../../../licensed_features';
jest.mock('../../../kibana_services');
export class MockSearchSource {
getField(fieldName: string) {
if (fieldName === 'filter') {
return [];
}
throw new Error(`Unsupported search source field: ${fieldName}`);
}
setField = jest.fn();
setParent() {}
getSearchRequestBody() {
@ -324,7 +331,7 @@ describe('ESGeoGridSource', () => {
index: 'foo-*',
renderAs: 'heatmap',
requestBody:
"(fields:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':())))",
"(fields:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':()),'7':('0':filter,'1':!((meta:(),query:(exists:(field:bar)))))))",
token: '1234',
});
});

View file

@ -21,6 +21,7 @@ import { DataView } from '@kbn/data-plugin/common';
import { Adapters } from '@kbn/inspector-plugin/common/adapters';
import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public';
import { getTileUrlParams } from '@kbn/maps-vector-tile-utils';
import { type Filter, buildExistsFilter } from '@kbn/es-query';
import { makeESBbox } from '../../../../common/elasticsearch_util';
import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson';
import { UpdateSourceEditor } from './update_source_editor';
@ -553,6 +554,11 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo
const dataView = await this.getIndexPattern();
const searchSource = await this.makeSearchSource(requestMeta, 0);
searchSource.setField('aggs', this.getValueAggsDsl(dataView));
// Filter out documents without geo fields for broad index-pattern support
searchSource.setField('filter', [
...(searchSource.getField('filter') as Filter[]),
buildExistsFilter({ name: this._descriptor.geoField, type: 'geo_point' }, dataView),
]);
const mvtUrlServicePath = getHttp().basePath.prepend(
`${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`

View file

@ -53,6 +53,13 @@ describe('ESSearchSource', () => {
beforeEach(async () => {
const mockSearchSource = {
getField: (fieldName: string) => {
if (fieldName === 'filter') {
return [];
}
throw new Error(`Unsupported search source field: ${fieldName}`);
},
setField: jest.fn(),
getSearchRequestBody() {
return {
@ -131,7 +138,7 @@ describe('ESSearchSource', () => {
hasLabels: 'false',
index: 'foobar-title-*',
requestBody:
"(fields:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(_id)),'7':('0':source,'1':!f),'8':('0':fields,'1':!(tooltipField,styleField))))",
"(fields:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(_id)),'7':('0':source,'1':!f),'8':('0':fields,'1':!(tooltipField,styleField)),'9':('0':filter,'1':!((meta:(),query:(exists:(field:bar)))))))",
token: '1234',
});
});

View file

@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n';
import type { SearchResponseWarning } from '@kbn/search-response-warnings';
import { GeoJsonProperties, Geometry, Position } from 'geojson';
import type { KibanaExecutionContext } from '@kbn/core/public';
import { type Filter, buildPhraseFilter, type TimeRange } from '@kbn/es-query';
import { type Filter, buildExistsFilter, buildPhraseFilter, type TimeRange } from '@kbn/es-query';
import type { DataViewField, DataView } from '@kbn/data-plugin/common';
import { lastValueFrom } from 'rxjs';
import { Adapters } from '@kbn/inspector-plugin/common/adapters';
@ -923,6 +923,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
})
);
// Filter out documents without geo fields to avoid shard failures for indices without geo fields
searchSource.setField('filter', [
...(searchSource.getField('filter') as Filter[]),
buildExistsFilter({ name: this._descriptor.geoField, type: 'geo_point' }, dataView),
]);
const mvtUrlServicePath = getHttp().basePath.prepend(`${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`);
const tileUrlParams = getTileUrlParams({