diff --git a/CHANGELOG.md b/CHANGELOG.md index 99422af8d86e..3b42f0db8ae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Vis Builder] Add metric to metric, bucket to bucket aggregation persistence ([#3495](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3495)) - Use mirrors to download Node.js binaries to escape sporadic 404 errors ([#3619](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3619)) - [Multiple DataSource] Refactor dev tool console to use opensearch-js client to send requests ([#3544](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3544)) +- [Data] Add geo shape filter field ([#3605](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3605)) ### 🐛 Bug Fixes diff --git a/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.test.ts b/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.test.ts new file mode 100644 index 000000000000..18a642fdbb4f --- /dev/null +++ b/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GeoShapeFilter, getGeoShapeFilterField, Polygon, ShapeFilter } from './geo_shape_filter'; +import { GeoShapeRelation } from '@opensearch-project/opensearch/api/types'; + +describe('geo shape filter', function () { + describe('getGeoShapeFilterField', function () { + it('should return the name of the field a geo_shape query is targeting', () => { + const polygon: Polygon = { + coordinates: [ + [ + [74.006, 40.7128], + [71.0589, 42.3601], + [73.7562, 42.6526], + [74.006, 40.7128], + ], + [ + [72.6734, 41.7658], + [72.6506, 41.5623], + [73.0515, 41.5582], + [72.6734, 41.7658], + ], + ], + type: 'Polygon', + }; + const geoShapeQuery: { + shape: ShapeFilter; + relation: GeoShapeRelation; + } = { + shape: polygon, + relation: 'intersects', + }; + const filter: GeoShapeFilter = { + geo_shape: { + geoPointField: geoShapeQuery, + ignore_unmapped: true, + }, + meta: { + disabled: false, + negate: false, + alias: null, + params: geoShapeQuery, + }, + }; + const result = getGeoShapeFilterField(filter); + expect(result).toBe('geoPointField'); + }); + it('should return undefined if filter.geo_shape is undefined', () => { + const filter: GeoShapeFilter = { + geo_shape: undefined, + meta: { + disabled: false, + negate: false, + alias: null, + params: { + shape: undefined, + }, + }, + }; + const result = getGeoShapeFilterField(filter); + expect(result).toBeUndefined(); + }); + }); +}); diff --git a/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.ts b/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.ts new file mode 100644 index 000000000000..007a42e31362 --- /dev/null +++ b/src/plugins/data/common/opensearch_query/filters/geo_shape_filter.ts @@ -0,0 +1,53 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GeoShapeRelation } from '@opensearch-project/opensearch/api/types'; +import { Filter, FilterMeta } from './meta_filter'; + +export type Position = number[]; + +export interface PreIndexedShapeFilter { + index: string; + id: string; + path: string; + routing?: string; +} + +export interface Polygon { + type: 'Polygon'; + coordinates: Position[][]; +} + +export interface MultiPolygon { + type: 'MultiPolygon'; + coordinates: Position[][][]; +} + +// TODO: support other geometries too. +export type ShapeFilter = Polygon | MultiPolygon; + +export type GeoShapeFilterMeta = FilterMeta & { + params: { + shape?: ShapeFilter; + indexed_shape?: PreIndexedShapeFilter; + relation?: GeoShapeRelation; + }; +}; + +export type GeoShapeFilter = Filter & { + meta: GeoShapeFilterMeta; + geo_shape: any; +}; + +export const isGeoShapeFilter = (filter: any): filter is GeoShapeFilter => filter?.geo_shape; + +export const getGeoShapeFilterField = (filter: GeoShapeFilter): string | undefined => { + if (filter?.geo_shape === undefined) { + return undefined; + } + return ( + filter?.geo_shape && Object.keys(filter.geo_shape).find((key) => key !== 'ignore_unmapped') + ); +}; diff --git a/src/plugins/data/common/opensearch_query/filters/get_filter_field.ts b/src/plugins/data/common/opensearch_query/filters/get_filter_field.ts index dff6866b4917..9f44e658c80f 100644 --- a/src/plugins/data/common/opensearch_query/filters/get_filter_field.ts +++ b/src/plugins/data/common/opensearch_query/filters/get_filter_field.ts @@ -36,6 +36,7 @@ import { getPhraseFilterField, isPhraseFilter } from './phrase_filter'; import { getPhrasesFilterField, isPhrasesFilter } from './phrases_filter'; import { getRangeFilterField, isRangeFilter } from './range_filter'; import { getMissingFilterField, isMissingFilter } from './missing_filter'; +import { getGeoShapeFilterField, isGeoShapeFilter } from './geo_shape_filter'; export const getFilterField = (filter: Filter) => { if (isExistsFilter(filter)) { @@ -59,6 +60,9 @@ export const getFilterField = (filter: Filter) => { if (isMissingFilter(filter)) { return getMissingFilterField(filter); } + if (isGeoShapeFilter(filter)) { + return getGeoShapeFilterField(filter); + } return; }; diff --git a/src/plugins/data/common/opensearch_query/filters/index.ts b/src/plugins/data/common/opensearch_query/filters/index.ts index ac11b067c3cb..f098767540d6 100644 --- a/src/plugins/data/common/opensearch_query/filters/index.ts +++ b/src/plugins/data/common/opensearch_query/filters/index.ts @@ -35,6 +35,7 @@ export * from './build_filters'; export * from './custom_filter'; export * from './exists_filter'; export * from './geo_bounding_box_filter'; +export * from './geo_shape_filter'; export * from './geo_polygon_filter'; export * from './get_display_value'; export * from './get_filter_field'; diff --git a/src/plugins/data/common/opensearch_query/filters/types.ts b/src/plugins/data/common/opensearch_query/filters/types.ts index e467cb2d87e2..c0afd31134b1 100644 --- a/src/plugins/data/common/opensearch_query/filters/types.ts +++ b/src/plugins/data/common/opensearch_query/filters/types.ts @@ -59,5 +59,6 @@ export enum FILTERS { RANGE = 'range', GEO_BOUNDING_BOX = 'geo_bounding_box', GEO_POLYGON = 'geo_polygon', + GEO_SHAPE = 'geo_shape', SPATIAL_FILTER = 'spatial_filter', }