Статьи

Примеры использования Elasticsearch: геопространственный поиск

В предыдущих статьях мы видели, что Elasticsearch можно использовать для хранения документов в формате JSON и распределения данных между несколькими узлами в виде сегментов и реплик . Lucene, базовая библиотека, обеспечивает реализацию инвертированного индекса, который можно использовать для поиска документов . Анализ является важным шагом для создания хорошего поискового приложения.

file2331343883319

В этом посте мы рассмотрим другую функцию, которую можно использовать для приложений, с которыми вы не сразу связали бы Elasticsearch. Мы рассмотрим гео-функции, которые можно использовать для создания приложений, которые могут фильтровать и сортировать документы в зависимости от местоположения пользователя.

Расположение в приложениях

Функции на основе местоположения могут быть полезны для широкого спектра применений. Для продавцов веб-сайт может представить ближайшую точку обслуживания для текущего пользователя. Или есть средство поиска для нахождения точек обслуживания в соответствии с местоположением, часто интегрированное с чем-то вроде Google Maps. Для объявлений может иметь смысл сортировать их по расстоянию от поиска пользователя, то же самое относится и к любому поиску таких мест, как рестораны и тому подобное. Иногда также имеет смысл показывать только результаты, которые находятся в определенной области вокруг меня, в этом случае нам нужно фильтровать по расстоянию. Возможно, пользователь ищет новую квартиру и не заинтересован в результатах, которые находятся слишком далеко от его рабочего места. Наконец, места могут также представлять интерес при выполнении аналитики. Данные социальных сетей могут рассказать вам, где происходит что-то интересное, просто посмотрев на количество сообщений о состоянии, отправленных из определенной области.

Большинство временных местоположений хранятся в виде пары широты и долготы, которая обозначает точку. Например, комбинация 48.779506 и 9.170045 указывает на Liederhalle Stuttgart, который является местом для Java Forum Stuttgart. Геошаши являются альтернативным средством кодирования широты и долготы. Они могут храниться с произвольной точностью, поэтому они также могут ссылаться на большую область вместо точки.

При расчете геохеша карта делится на несколько блоков или ячеек. Каждый сегмент идентифицируется с помощью кодированного значения 32. Затем полный геохэш состоит из последовательности символов. Каждый следующий символ помечает ведро в предыдущем ведре, поэтому вы приближаетесь к месту. Чем длиннее строка геохеша, тем точнее местоположение. Например, u0wt88j3jwcp — это геохеш для Liederhalle Штутгарта. С другой стороны, префикс u0wt — это район Штутгарта и некоторых близлежащих городов.

Иерархическая природа геохэшей и возможность выражать их в виде строк делает их хорошим выбором для хранения их в инвертированном индексе. Вы можете создавать геохэш, используя оригинальный сервис геохэш или более визуально привлекательный, используя хороший GeohashExplorer .

Места в Elasticsearch

Elasticsearch принимает значения lat и lon для указания широты и долготы. Это два документа для конференции в Штутгарте и один в Нюрнберге.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
    "title" : "Anwendungsfälle für Elasticsearch",
    "speaker" : "Florian Hopf",
    "date" : "2014-07-17T15:35:00.000Z",
    "tags" : ["Java", "Lucene"],
    "conference" : {
        "name" : "Java Forum Stuttgart",
        "city" : "Stuttgart",
            "coordinates": {
                "lon": "9.170045",
                "lat": "48.779506"
            }
    }
}
{
    "title" : "Anwendungsfälle für Elasticsearch",
    "speaker" : "Florian Hopf",
    "date" : "2014-07-15T16:30:00.000Z",
    "tags" : ["Java", "Lucene"],
    "conference" : {
        "name" : "Developer Week",
        "city" : "Nürnberg",
            "coordinates": {
                "lon": "11.115358",
                "lat": "49.417175"
            }
    }
}

В качестве альтернативы вы можете использовать формат GeoJSON , принимая массив долготы и широты. Если вы похожи на меня, будьте готовы выяснить, почему запросы не работают, просто чтобы заметить, что вы испортили порядок в массиве.

Поле должно быть отображено с типом поля geo_point .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
{
    "properties": {
          […],
       "conference": {
            "type": "object",
            "properties": {
                "coordinates": {
                    "type": "geo_point",
                    "geohash": "true",
                    "geohash_prefix": "true"
                }
            }
       }
    }
}'

geohash необязательный атрибут geohash автоматически сохранит геохэш для вас. В зависимости от вашего варианта использования вы также можете сохранить все родительские ячейки геохеша, используя параметр geohash_prefix . Поскольку значения являются просто строками, это нормальная операция индекса ngram, которая хранит различные подстроки для термина, например, u, u0, u0w и u0wt для u0wt.

Теперь, когда у нас есть документы, мы можем использовать геоинформацию для сортировки, фильтрации и агрегирования результатов.

Сортировка по расстоянию

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
{
    "sort" : [
        {
            "_geo_distance" : {
                "conference.coordinates" : {
                    "lon": 8.403697,
                    "lat": 49.006616
                },
                "order" : "asc",
                "unit" : "km"
            }
        }
    ]
}'

Мы просим сортировать по _geo_distance и переходим в другое место, на этот раз в Карлсруэ, где я живу. Результаты должны быть отсортированы по возрастанию, поэтому более близкие результаты на первом месте. Поскольку Штутгарт находится недалеко от Карлсруэ, он будет первым в списке результатов.

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

Фильтрация по расстоянию

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

01
02
03
04
05
06
07
08
09
10
11
12
13
{
   "filter": {
      "geo_distance": {
         "conference.coordinates": {
            "lon": 8.403697,
            "lat": 49.006616
         },
         "distance": "200km",
         "distance_type": "arc"
      }
   }
}'

Мы снова проходим местоположение Карлсруэ. Мы просим, ​​чтобы только документы на расстоянии 200 км были возвращены и чтобы для определения distance_type использовалась arc distance_type. Это будет учитывать, что мы живем на земном шаре.

Полученный список будет содержать только один документ, Штутгарт, так как Нюрнберг находится чуть более чем в 200 км. Если мы используем расстояние 210 км, оба документа будут возвращены.

Гео Агрегации

Elasticsearch предоставляет несколько полезных географических агрегаций, которые позволяют вам получать больше информации о расположении ваших документов, например, для фасетирования. С другой стороны, поскольку у нас есть геохэш, а также включен префикс, мы можем извлечь все ячейки, в которых находятся наши результаты, используя простое объединение терминов . Таким образом, вы можете позволить пользователю детализировать результаты путем фильтрации в ячейке.

01
02
03
04
05
06
07
08
09
10
{
    "aggregations" : {
        "conference-hashes" : {
            "terms" : {
                "field" : "conference.coordinates.geohash"
            }
        }
    }
}'

В зависимости от точности, которую мы выбрали при индексировании, это вернет длинный список префиксов для хэшей, но самая важная часть находится в начале.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
[...]
   "aggregations": {
      "conference-hashes": {
         "buckets": [
            {
               "key": "u",
               "doc_count": 2
            },
            {
               "key": "u0",
               "doc_count": 2
            },
            {
               "key": "u0w",
               "doc_count": 1
            },
            [...]
        }
    }

Штутгарт и Нюрнберг оба имеют общие родительские ячейки u и u0.

В качестве альтернативы терминам агрегации можно также использовать специализированные географические агрегации, например, агрегацию географических расстояний для формирования групп расстояний.

Вывод

Помимо функций, которые мы видели здесь, Elasticsearch предлагает широкий спектр гео-функций. Вы можете индексировать фигуры и выполнять запросы по произвольным многоугольникам , передавая их или передавая ссылку на проиндексированный многоугольник. Когда префиксы геохеша включены, вы также можете фильтровать по ячейке геохеша.

С новыми возможностями определения местоположения в HTML 5 поиск и доставка контента станут более важными. Elasticsearch хорошо подходит для создания такого рода приложений.

Два пользователя в геопространстве — Foursquare, очень ранний пользователь Elasticsearch , и Gild, кадровое агентство, которое творит чудеса с локациями .