В предыдущих статьях мы видели, что Elasticsearch можно использовать для хранения документов в формате JSON и распределения данных между несколькими узлами в виде сегментов и реплик . Lucene, базовая библиотека, обеспечивает реализацию инвертированного индекса, который можно использовать для поиска документов . Анализ является важным шагом для создания хорошего поискового приложения.
В этом посте мы рассмотрим другую функцию, которую можно использовать для приложений, с которыми вы не сразу связали бы 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, кадровое агентство, которое творит чудеса с локациями .
| Ссылка: | Примеры использования Elasticsearch: геопространственный поиск от нашего партнера JCG Флориана Хопфа в блоге Dev Time . | 
