Skip to content

Commit 137a720

Browse files
[Maps] spatially filter by all geo fields (#100735) (#101153)
* [Maps] spatial filter by all geo fields * replace geoFields with geoFieldNames * update mapSpatialFilter to be able to reconize multi field filters * add check for geoFieldNames * i18n fixes and fix GeometryFilterForm jest test * tslint * tslint Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Nathan Reese <reese.nathan@gmail.com>
1 parent 54b8d28 commit 137a720

File tree

32 files changed

+942
-1091
lines changed

32 files changed

+942
-1091
lines changed

src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,61 @@ describe('mapSpatialFilter()', () => {
5454
expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER);
5555
});
5656

57+
test('should return the key for matching multi field filter', async () => {
58+
const filter = {
59+
meta: {
60+
alias: 'my spatial filter',
61+
isMultiIndex: true,
62+
type: FILTERS.SPATIAL_FILTER,
63+
} as FilterMeta,
64+
query: {
65+
bool: {
66+
should: [
67+
{
68+
bool: {
69+
must: [
70+
{
71+
exists: {
72+
field: 'geo.coordinates',
73+
},
74+
},
75+
{
76+
geo_distance: {
77+
distance: '1000km',
78+
'geo.coordinates': [120, 30],
79+
},
80+
},
81+
],
82+
},
83+
},
84+
{
85+
bool: {
86+
must: [
87+
{
88+
exists: {
89+
field: 'location',
90+
},
91+
},
92+
{
93+
geo_distance: {
94+
distance: '1000km',
95+
location: [120, 30],
96+
},
97+
},
98+
],
99+
},
100+
},
101+
],
102+
},
103+
},
104+
} as Filter;
105+
const result = mapSpatialFilter(filter);
106+
107+
expect(result).toHaveProperty('key', 'query');
108+
expect(result).toHaveProperty('value', '');
109+
expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER);
110+
});
111+
57112
test('should return undefined for none matching', async (done) => {
58113
const filter = {
59114
meta: {

src/plugins/data/public/query/filter_manager/lib/mappers/map_spatial_filter.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,18 @@ export const mapSpatialFilter = (filter: Filter) => {
2222
value: '',
2323
};
2424
}
25+
26+
if (
27+
filter.meta &&
28+
filter.meta.type === FILTERS.SPATIAL_FILTER &&
29+
filter.meta.isMultiIndex &&
30+
filter.query?.bool?.should
31+
) {
32+
return {
33+
key: 'query',
34+
type: filter.meta.type,
35+
value: '',
36+
};
37+
}
2538
throw filter;
2639
};

x-pack/plugins/maps/common/descriptor_types/map_descriptor.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ReactNode } from 'react';
1111
import { GeoJsonProperties } from 'geojson';
1212
import { Geometry } from 'geojson';
1313
import { Query } from '../../../../../src/plugins/data/common';
14-
import { DRAW_TYPE, ES_GEO_FIELD_TYPE, ES_SPATIAL_RELATIONS } from '../constants';
14+
import { DRAW_TYPE, ES_SPATIAL_RELATIONS } from '../constants';
1515

1616
export type MapExtent = {
1717
minLon: number;
@@ -70,9 +70,6 @@ export type DrawState = {
7070
actionId: string;
7171
drawType: DRAW_TYPE;
7272
filterLabel?: string; // point radius filter alias
73-
geoFieldName?: string;
74-
geoFieldType?: ES_GEO_FIELD_TYPE;
7573
geometryLabel?: string;
76-
indexPatternId?: string;
7774
relation?: ES_SPATIAL_RELATIONS;
7875
};

x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js

Lines changed: 0 additions & 218 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import {
99
hitsToGeoJson,
1010
geoPointToGeometry,
1111
geoShapeToGeometry,
12-
createExtentFilter,
1312
roundCoordinates,
14-
extractFeaturesFromFilters,
1513
makeESBbox,
1614
scaleBounds,
1715
} from './elasticsearch_geo_utils';
@@ -388,94 +386,6 @@ describe('geoShapeToGeometry', () => {
388386
});
389387
});
390388

391-
describe('createExtentFilter', () => {
392-
it('should return elasticsearch geo_bounding_box filter', () => {
393-
const mapExtent = {
394-
maxLat: 39,
395-
maxLon: -83,
396-
minLat: 35,
397-
minLon: -89,
398-
};
399-
const filter = createExtentFilter(mapExtent, [geoFieldName]);
400-
expect(filter.geo_bounding_box).toEqual({
401-
location: {
402-
top_left: [-89, 39],
403-
bottom_right: [-83, 35],
404-
},
405-
});
406-
});
407-
408-
it('should clamp longitudes to -180 to 180 and latitudes to -90 to 90', () => {
409-
const mapExtent = {
410-
maxLat: 120,
411-
maxLon: 200,
412-
minLat: -100,
413-
minLon: -190,
414-
};
415-
const filter = createExtentFilter(mapExtent, [geoFieldName]);
416-
expect(filter.geo_bounding_box).toEqual({
417-
location: {
418-
top_left: [-180, 89],
419-
bottom_right: [180, -89],
420-
},
421-
});
422-
});
423-
424-
it('should make left longitude greater than right longitude when area crosses 180 meridian east to west', () => {
425-
const mapExtent = {
426-
maxLat: 39,
427-
maxLon: 200,
428-
minLat: 35,
429-
minLon: 100,
430-
};
431-
const filter = createExtentFilter(mapExtent, [geoFieldName]);
432-
const leftLon = filter.geo_bounding_box.location.top_left[0];
433-
const rightLon = filter.geo_bounding_box.location.bottom_right[0];
434-
expect(leftLon).toBeGreaterThan(rightLon);
435-
expect(filter.geo_bounding_box).toEqual({
436-
location: {
437-
top_left: [100, 39],
438-
bottom_right: [-160, 35],
439-
},
440-
});
441-
});
442-
443-
it('should make left longitude greater than right longitude when area crosses 180 meridian west to east', () => {
444-
const mapExtent = {
445-
maxLat: 39,
446-
maxLon: -100,
447-
minLat: 35,
448-
minLon: -200,
449-
};
450-
const filter = createExtentFilter(mapExtent, [geoFieldName]);
451-
const leftLon = filter.geo_bounding_box.location.top_left[0];
452-
const rightLon = filter.geo_bounding_box.location.bottom_right[0];
453-
expect(leftLon).toBeGreaterThan(rightLon);
454-
expect(filter.geo_bounding_box).toEqual({
455-
location: {
456-
top_left: [160, 39],
457-
bottom_right: [-100, 35],
458-
},
459-
});
460-
});
461-
462-
it('should clamp longitudes to -180 to 180 when longitude wraps globe', () => {
463-
const mapExtent = {
464-
maxLat: 39,
465-
maxLon: 209,
466-
minLat: 35,
467-
minLon: -191,
468-
};
469-
const filter = createExtentFilter(mapExtent, [geoFieldName]);
470-
expect(filter.geo_bounding_box).toEqual({
471-
location: {
472-
top_left: [-180, 39],
473-
bottom_right: [180, 35],
474-
},
475-
});
476-
});
477-
});
478-
479389
describe('roundCoordinates', () => {
480390
it('should set coordinates precision', () => {
481391
const coordinates = [
@@ -492,134 +402,6 @@ describe('roundCoordinates', () => {
492402
});
493403
});
494404

495-
describe('extractFeaturesFromFilters', () => {
496-
it('should ignore non-spatial filers', () => {
497-
const phraseFilter = {
498-
meta: {
499-
alias: null,
500-
disabled: false,
501-
index: '90943e30-9a47-11e8-b64d-95841ca0b247',
502-
key: 'machine.os',
503-
negate: false,
504-
params: {
505-
query: 'ios',
506-
},
507-
type: 'phrase',
508-
},
509-
query: {
510-
match_phrase: {
511-
'machine.os': 'ios',
512-
},
513-
},
514-
};
515-
expect(extractFeaturesFromFilters([phraseFilter])).toEqual([]);
516-
});
517-
518-
it('should convert geo_distance filter to feature', () => {
519-
const spatialFilter = {
520-
geo_distance: {
521-
distance: '1096km',
522-
'geo.coordinates': [-89.87125, 53.49454],
523-
},
524-
meta: {
525-
alias: 'geo.coordinates within 1096km of -89.87125,53.49454',
526-
disabled: false,
527-
index: '90943e30-9a47-11e8-b64d-95841ca0b247',
528-
key: 'geo.coordinates',
529-
negate: false,
530-
type: 'spatial_filter',
531-
value: '',
532-
},
533-
};
534-
535-
const features = extractFeaturesFromFilters([spatialFilter]);
536-
expect(features[0].geometry.coordinates[0][0]).toEqual([-89.87125, 63.35109118642093]);
537-
expect(features[0].properties).toEqual({
538-
filter: 'geo.coordinates within 1096km of -89.87125,53.49454',
539-
});
540-
});
541-
542-
it('should convert geo_shape filter to feature', () => {
543-
const spatialFilter = {
544-
geo_shape: {
545-
'geo.coordinates': {
546-
relation: 'INTERSECTS',
547-
shape: {
548-
coordinates: [
549-
[
550-
[-101.21639, 48.1413],
551-
[-101.21639, 41.84905],
552-
[-90.95149, 41.84905],
553-
[-90.95149, 48.1413],
554-
[-101.21639, 48.1413],
555-
],
556-
],
557-
type: 'Polygon',
558-
},
559-
},
560-
ignore_unmapped: true,
561-
},
562-
meta: {
563-
alias: 'geo.coordinates in bounds',
564-
disabled: false,
565-
index: '90943e30-9a47-11e8-b64d-95841ca0b247',
566-
key: 'geo.coordinates',
567-
negate: false,
568-
type: 'spatial_filter',
569-
value: '',
570-
},
571-
};
572-
573-
expect(extractFeaturesFromFilters([spatialFilter])).toEqual([
574-
{
575-
type: 'Feature',
576-
geometry: {
577-
type: 'Polygon',
578-
coordinates: [
579-
[
580-
[-101.21639, 48.1413],
581-
[-101.21639, 41.84905],
582-
[-90.95149, 41.84905],
583-
[-90.95149, 48.1413],
584-
[-101.21639, 48.1413],
585-
],
586-
],
587-
},
588-
properties: {
589-
filter: 'geo.coordinates in bounds',
590-
},
591-
},
592-
]);
593-
});
594-
595-
it('should ignore geo_shape filter with pre-index shape', () => {
596-
const spatialFilter = {
597-
geo_shape: {
598-
'geo.coordinates': {
599-
indexed_shape: {
600-
id: 's5gldXEBkTB2HMwpC8y0',
601-
index: 'world_countries_v1',
602-
path: 'coordinates',
603-
},
604-
relation: 'INTERSECTS',
605-
},
606-
ignore_unmapped: true,
607-
},
608-
meta: {
609-
alias: 'geo.coordinates in multipolygon',
610-
disabled: false,
611-
index: '90943e30-9a47-11e8-b64d-95841ca0b247',
612-
key: 'geo.coordinates',
613-
negate: false,
614-
type: 'spatial_filter',
615-
value: '',
616-
},
617-
};
618-
619-
expect(extractFeaturesFromFilters([spatialFilter])).toEqual([]);
620-
});
621-
});
622-
623405
describe('makeESBbox', () => {
624406
it('Should invert Y-axis', () => {
625407
const bbox = makeESBbox({

0 commit comments

Comments
 (0)