[Из песочницы] Telegram bot и PostGIS

О реализации ботов для месседжера Telegram на сайте было уже довольно много постов. Но есть одна тема, которая, на мой взгляд, еще не была затронута. Это реализация работы с геолокацией внутри бота. В данном посте я приведу пример того, как можно обрабатывать ботом информацию о геолокации, посылаемую пользователями, опираясь на собственный опыт реализации бота aroundus_bot.

6da25b96b67049238eb3f5c3ea0e087d.jpg

Дело в том, что месседжер Telegram предоставляет довольно удобные возможности по работе с геолокацией. Пользователь может прислать свое текущее положение, отправить какую-либо иную точку на карте (для мобильных устройств, прикрепление Location), либо прислать адрес и местоположение какого-либо места (рестораны, парки, скверы…) при помощи бота foursquare.

38247a1465ca4b518efb0ab629c12764.jpg

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

b4253101abd7466898371284b6d9c1ae.jpg

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

Проблема


Но широта и долгота — это географические координаты точки, определяющие местоположение объекта на земной поверхности. А как известно, земля имеет форму эллипсоида. И нет возможности просто прибавить к этим координатам, допустим, 100 метров, и сказать, что это край области, в которой нужно искать истории. Необходимо вычислять окрестность точки в сферических координатах.

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

PostGIS


В своих поисках я набрел на пост, опубликованный на текущем сайте. И осознал, что сделал абсолютно правильный выбор СУБД, которую использую для хранения информации необходимой боту — PostgreSQL. Коротко, расширение PostGIS, которое можно поставить для этой СУБД, позволяет эффективно работать с географическими координатами, используя вызов специальных функций в обычном SQL запросе. Подробнее про PostGIS можно прочитать по ссылке.

Таким образом, выборка всех историй из окрестности какой-либо точки (или поиск ближайшего чего-либо относительно заданной точки) сводится к реализации SQL запроса, который благодаря использованию индексов GiST для работы с координатами, будет выполняться очень быстро. Но необходимо отметить, что для эффективного использования расширения, данные о местоположении необходимо хранить в колонке со специальным типом geometry, на которую потом необходимо повесить индекс. В своей реализации для простоты использования я храню данные как отдельно для широты и долготы в формате double, так и колонку в формате geometry.

Пример sql запроса по поиску чего-либо в заданной окрестности (например, в радиусе 100 метров), может быть таким:

ST_Distance(ST_Transform(coordinates, 26986), ST_Transform(ST_SetSRID(ST_MakePoint(x, y), 4326), 26986)) < 100

где:

ST_Distance, ST_Transform, ST_SetSRID, ST_MakePoint — специальные функции для работы с географическими координатами,
coordinates — колонка типа geometry
x, y — широта и долгота точки, окрестность которой нас интересует.

Следует сказать, что я также знаю про реализацию данного расширения для СУБД MySQL, но в процессе поиска информации у меня сложилось стойкое мнение, что реализация расширения для PostgreSQL работает лучше и с меньшим количеством ошибок, хотя могу ошибаться.

Вывод


Если существует необходимость реализации бота для Telegram, который должен работать с географическими координатами, то неплохим выходом будет использование СУБД PostgreSQL для хранения информации. Все, что необходимо сделать — это сохранить полученные от пользователя данные о широте и долготе в колонке типа geometry, и далее можно эффективно работать с этой информацией, оперируя SQL запросами.

Комментарии (2)

  • 28 июня 2016 в 19:14

    0

    Отправка местоположения в Телеграме тормозит из-за того, что сперва надо прокачать карты. Есть какие-то другие способы быстро послать примерное местоположение?
    Чуть не решилась моя задумка с ботом для медленных интернетов.
  • 28 июня 2016 в 22:07

    0

    Это может быть как реализация квестов (бот будет присылать следующие точки, куда необходимо следовать пользователям…)
    TQuestsBot и команда /location:)

© Habrahabr.ru