# Геопоиск

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

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



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

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

Если для атрибутов широты и долготы созданы вторичные индексы, они могут автоматически использоваться для ускорения геопоиска, если [Стоимостной оптимизатор](../Searching/Cost_based_optimizer.md) решит их использовать.

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

Чтобы узнать расстояние между двумя точками, можно использовать функцию [GEODIST()](../Functions/Geo_spatial_functions.md#GEODIST%28%29). `GEODIST` требует две пары координат в качестве первых четырех параметров.

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

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

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

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

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

```sql
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()](../Functions/Geo_spatial_functions.md#GEOPOLY2D%28%29) - создает полигон, учитывающий кривизну Земли
*   [POLY2D()](../Functions/Geo_spatial_functions.md#POLY2D%28%29) - создает простой полигон в плоском пространстве

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

[CONTAINS()](../Functions/Arrays_and_conditions_functions.md#CONTAINS%28%29) принимает полигон и набор координат на вход и возвращает `1`, если точка находится внутри полигона, или `0` в противном случае.

```sql
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;
```
<!-- proofread -->

