Геопоиск

Одной из самых мощных функций Manticore Search является возможность комбинировать полнотекстовый поиск с геолокацией. Например, ритейлер может предложить поиск, где пользователь ищет товар, а результаты могут указывать на ближайший магазин, где этот товар есть в наличии, чтобы пользователь мог прийти в магазин и забрать его. Туристический сайт может предоставлять результаты поиска, ограниченные определенной областью, и сортировать их по расстоянию от точки (например, 'поиск музеев рядом с отелем').

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

table myrt
{
    ...
    rt_attr_float = lat
    rt_attr_float = lon
    ...
}

Координаты могут храниться в градусах или радианах.

Если для атрибутов широты и долготы созданы вторичные индексы, они могут автоматически использоваться для ускорения геопоиска, если Стоимостной оптимизатор решит их использовать.

Вычисление расстояния

Чтобы узнать расстояние между двумя точками, можно использовать функцию GEODIST(). GEODIST требует две пары координат в качестве первых четырех параметров.

5-й параметр в упрощенном формате JSON может настраивать определенные аспекты функции. По умолчанию GEODIST ожидает координаты в радианах, но добавление in=degrees позволяет использовать градусы на входе. Координаты, для которых мы вычисляем гео-расстояние, должны быть того же типа (градусы или радианы), что и хранящиеся в таблице; в противном случае результаты будут неверными.

Вычисленное расстояние по умолчанию указывается в метрах, но с помощью опции out его можно преобразовать в километры, футы или мили. Наконец, по умолчанию используется метод вычисления adaptive. Доступен альтернативный метод на основе алгоритма haversine; однако он медленнее и менее точен.

Результат функции - расстояние - может использоваться в предложении ORDER BY для сортировки результатов:

SELECT *, GEODIST(40.7643929, -73.9997683, lat, lon, {in=degrees, out=miles}) AS distance FROM myindex WHERE MATCH('...') ORDER BY distance ASC, WEIGHT() DESC;

Или для ограничения результатов радиальной областью вокруг точки:

SELECT *,GEODIST(40.7643929, -73.9997683, lat,lon, {in=degrees, out=miles}) AS distance FROM myindex WHERE MATCH('...') AND distance <1000 ORDER BY WEIGHT(), DISTANCE ASC;

Поиск внутри полигонов

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

Для создания полигона доступны две функции:

  • GEOPOLY2D() - создает полигон, учитывающий кривизну Земли
  • POLY2D() - создает простой полигон в плоском пространстве

POLY2D подходит для геопоиска, когда стороны области короче 500 км (для полигонов с 3-4 сторонами; для полигонов с большим количеством сторон следует рассматривать меньшие значения). Для областей с более длинными сторонами требуется использование GEOPOLY2D для сохранения точности результатов. GEOPOLY2D ожидает координаты в виде пар широта/долгота в градусах; использование радианов даст результаты в плоском пространстве (аналогично POLY2D).

CONTAINS() принимает полигон и набор координат на вход и возвращает 1, если точка находится внутри полигона, или 0 в противном случае.

SELECT *,CONTAINS(GEOPOLY2D(40.76439, -73.9997, 42.21211, -73.999,  42.21211, -76.123, 40.76439, -76.123), 41.5445, -74.973) AS inside FROM myindex WHERE MATCH('...') AND inside=1;
Last modified: August 28, 2025