1. введение
Elasticsearch наиболее известен своими возможностями полнотекстового поиска, но он также имеет полную геопространственную поддержку.
Мы можем узнать больше о настройке Elasticsearch и начале работы в этом предыдущая статья .
Давайте рассмотрим, как мы можем сохранять геоданные в Elasticsearch и как мы можем искать эти данные с помощью гео-запросов.
2. Тип Гео Данных
Чтобы включить гео-запросы, нам нужно вручную создать сопоставление индекса и явно задать сопоставление полей.
Динамическое сопоставление не будет работать при настройке сопоставления для типов гео.
Elasticsearch предлагает два способа представления геоданных:
- Пары Широта-долгота с использованием гео-точки типа поля
- Сложная форма, определенная в GeoJSON с использованием geo-shape тип поля
Давайте более подробно рассмотрим каждую из вышеперечисленных категорий:
2.1. Тип данных Гео-Точки
Тип поля географической точки принимает пары широта-долгота, которые можно использовать для:
- Найти точки на определенном расстоянии от центральной точки
- Найдите точки внутри прямоугольника или многоугольника
- Агрегировать документы географически или по расстоянию от центральной точки
- Сортировка документов по расстоянию
Ниже приведен пример отображения поля для сохранения данных гео-точек:
PUT /index_name { "mappings": { "TYPE_NAME": { "properties": { "location": { "type": "geo_point" } } } } }
Как мы можем видеть из приведенного выше примера, тип для местоположение поле geo_point . Таким образом, теперь мы можем указать пару широта-долгота в поле местоположение в поле местоположение.
2.2. Тип данных Геоформы
В отличие от географическая точка , геоформа предоставляет функциональность для сохранения и поиска сложных фигур, таких как многоугольник и прямоугольник. Геометрическая форма тип данных должен использоваться, когда мы хотим искать документы, содержащие фигуры, отличные от геопунктов.
Давайте рассмотрим сопоставление для типа данных геоформы:
PUT /index_name { "mappings": { "TYPE_NAME": { "properties": { "location": { "type": "geo_shape" } } } } }
Последние версии Elasticsearch разбивают предоставленную геоформу на треугольную сетку . Согласно официальной документации , это обеспечивает почти идеальное пространственное разрешение.
3. Различные способы сохранения данных о географических точках
3.1. Объект Широты и долготы
PUT index_name/index_type/1 { "location": { "lat": 23.02, "lon": 72.57 } }
Здесь гео-точка местоположение сохраняется как объект с широтой и долготой в качестве ключей.
3.2. Пара Широта-Долгота
{ "location": "23.02,72.57" }
Здесь location выражается в виде пары широта-долгота в простом строковом формате. Обратите внимание, последовательность широты и долготы в строковом формате.
3.3. Геохаш
{ "location": "tsj4bys" }
Мы также можем предоставить данные о географических точках в виде геохэша, как показано в примере выше. Мы можем использовать онлайн-инструмент для преобразования широты-долготы в геохаш.
3.4. Массив Широты И Долготы
{ "location": [72.57, 23.02] }
Последовательность широта-долгота меняется на противоположную, когда широта и долгота предоставляются в виде массива. Первоначально пара широта-долгота использовалась как в строке, так и в массиве, но позже она была изменена, чтобы соответствовать формату, используемому ГеоЙСОН .
4. Различные способы сохранения данных о географической форме
4.1. Пункт
POST /index/type { "location" : { "type" : "point", "coordinates" : [72.57, 23.02] } }
Здесь тип формы гео, который мы пытаемся вставить, – это точка . Пожалуйста, взгляните на поле местоположение , у нас есть вложенный объект, состоящий из полей тип и координаты . Эти мета-поля помогают Elasticsearch идентифицировать географическую форму и ее фактические данные.
4.2. Построение строк
POST /index/type { "location" : { "type" : "linestring", "coordinates" : [[77.57, 23.02], [77.59, 23.05]] } }
Здесь мы вставляем linestring геоформу. Координаты для linestring состоят из двух точек, т. е. начала и конечной точки. LineString геометрическая форма очень полезна для случаев использования навигации.
4.3. Полигон
POST /index/type { "location" : { "type" : "polygon", "coordinates" : [ [ [10.0, 0.0], [11.0, 0.0], [11.0, 1.0], [10.0, 1.0], [10.0, 0.0] ] ] } }
Здесь мы вставляем polygon geo shape. Пожалуйста, взгляните на координаты в приведенном выше примере, первые и последние координаты в полигоне всегда должны совпадать, т. е. закрытый полигон.
Elasticsearch также поддерживает другие структуры GeoJSON. Полный список других поддерживаемых форматов приведен ниже:
- Многоточечный
- Многострочный
- Мультиполигон
- Геометрическая коллекция
- Конверт
- Круг
Примеры поддерживаемых форматов можно найти на официальном сайте ES .
Для всех структур внутренние тип и координаты являются обязательными полями. Кроме того, сортировка и извлечение полей геоформы в настоящее время невозможны в Elasticsearch из-за их сложной структуры. Таким образом, единственный способ получить географические поля-это получить их из исходного поля.
5. Гео-запрос ElasticSearch
Теперь, когда мы знаем, как вставлять документы, содержащие геоформы, давайте погрузимся в извлечение этих записей с помощью запросов геоформы. Но прежде чем мы начнем использовать гео-запросы, нам понадобятся следующие зависимости maven для поддержки Java API для гео-запросов:
org.locationtech.spatial4j spatial4j 0.7 com.vividsolutions jts 1.13 xerces xercesImpl
Мы также можем искать вышеуказанные зависимости в Центральном репозитории Maven .
Elasticsearch поддерживает различные типы гео-запросов, и они следующие:
5.1. Запрос формы Гео
Для этого требуется отображение geo_shape .
Аналогично типу geo_shape , geo_shape использует структуру GeoJSON для запроса документов.
Ниже приведен пример запроса для извлечения всех документов, которые попадают в с заданными верхними левыми и нижними правыми координатами:
{ "query":{ "bool": { "must": { "match_all": {} }, "filter": { "geo_shape": { "region": { "shape": { "type": "envelope", "coordinates" : [[75.00, 25.0], [80.1, 30.2]] }, "relation": "within" } } } } } }
Здесь отношение определяет операторы пространственных отношений , используемые во время поиска.
Ниже приведен список поддерживаемых операторов:
- ПЕРЕСЕКАЕТСЯ – (по умолчанию) возвращает все документы, поле geo_shape которых пересекает геометрию запроса
- DISJOINT – извлекает все документы, поле geo_shape которых не имеет ничего общего с геометрией запроса
- В – получает все документы, поле geo_shape которых находится в геометрии запроса
- СОДЕРЖИТ – возвращает все документы, в поле geo_shape которых содержится геометрия запроса
Аналогично, мы можем запрашивать, используя различные формы GeoJSON.
Код Java для вышеуказанного запроса выглядит следующим образом:
Coordinate topLeft = new Coordinate(74, 31.2); Coordinate bottomRight = new Coordinate(81.1, 24); GeoShapeQueryBuilder qb = QueryBuilders.geoShapeQuery("region", new EnvelopeBuilder(topLeft, bottomRight).buildGeometry()); qb.relation(ShapeRelation.INTERSECTS);
5.2. Запрос гео-ограничительной рамки
Запрос Гео-ограничительной рамки используется для извлечения всех документов на основе местоположения точки. Ниже приведен пример запроса ограничительной рамки:
{ "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_bounding_box" : { "location" : { "bottom_left" : [28.3, 30.5], "top_right" : [31.8, 32.12] } } } } } }
Код Java для приведенного выше запроса ограничительной рамки выглядит следующим образом:
QueryBuilders .geoBoundingBoxQuery("location").setCorners(31.8, 30.5, 28.3, 32.12);
Запрос на гео-ограничивающую рамку поддерживает аналогичные форматы, которые мы имеем в geo_point типе данных. Примеры запросов для поддерживаемых форматов можно найти на официальном сайте .
5.3. Запрос о географическом расстоянии
Запрос географического расстояния используется для фильтрации всех документов, которые поставляются с указанным диапазоном точки.
Вот пример geo_distance запрос:
{ "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_distance" : { "distance" : "10miles", "location" : [31.131,29.976] } } } } }
А вот код Java для приведенного выше запроса:
QueryBuilders .geoDistanceQuery("location") .point(29.976, 31.131) .distance(10, DistanceUnit.MILES);
Аналогично geo_point, запрос гео-расстояния также поддерживает несколько форматов для передачи координат местоположения. Более подробную информацию о поддерживаемых форматах можно найти на официальном сайте .
5.4. Запрос геополигонов
Запрос для фильтрации всех записей, содержащих точки, попадающие в заданный многоугольник точек.
Давайте быстро рассмотрим пример запроса:
{ "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_polygon" : { "location" : { "points" : [ {"lat" : 22.733, "lon" : 68.859}, {"lat" : 24.733, "lon" : 68.859}, {"lat" : 23, "lon" : 70.859} ] } } } } } }
И на Java-код для этого запроса:
ListallPoints = new ArrayList (); allPoints.add(new GeoPoint(22.733, 68.859)); allPoints.add(new GeoPoint(24.733, 68.859)); allPoints.add(new GeoPoint(23, 70.859)); QueryBuilders.geoPolygonQuery("location", allPoints);
Запрос геополигонов также поддерживает форматы, указанные ниже:
- lat-длина массива: [lon, lat]
- лат-длинный, как струна: “лат, лон”
- геохаш
тип данных geo_point является обязательным для использования этого запроса.
6. Заключение
В этой статье мы обсудили различные варианты отображения для индексирования геоданных, т. е. geo_point и geo_shape .
Мы также рассмотрели различные способы хранения геоданных и, наконец, мы наблюдали гео-запросы и Java API для фильтрации результатов с помощью гео-запросов.
Как всегда, код доступен в этом проекте GitHub .