Рубрики
Без рубрики

Геопространственная поддержка в ElasticSearch

Узнайте, как сохранить геоданные в Elasticsearch и запросить их с помощью гео-запросов.

Автор оригинала: baeldung.

1. введение

Elasticsearch наиболее известен своими возможностями полнотекстового поиска, но он также имеет полную геопространственную поддержку.

Мы можем узнать больше о настройке Elasticsearch и начале работы в этом предыдущая статья .

Давайте рассмотрим, как мы можем сохранять геоданные в Elasticsearch и как мы можем искать эти данные с помощью гео-запросов.

2. Тип Гео Данных

Чтобы включить гео-запросы, нам нужно вручную создать сопоставление индекса и явно задать сопоставление полей.

Динамическое сопоставление не будет работать при настройке сопоставления для типов гео.

Elasticsearch предлагает два способа представления геоданных:

  1. Пары Широта-долгота с использованием гео-точки типа поля
  2. Сложная форма, определенная в 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-код для этого запроса:

List allPoints = 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 .