почтовый индекс по координатам
Как найти почтовый индекс по координатам GPS?
Скажем, у меня есть API веб-службы, который принимает почтовый индекс в качестве параметра, но у меня есть доступ только к координате GPS (широта, долгота). Как я могу динамически искать почтовый индекс, которому принадлежит координата?
Я делаю эту работу на iPhone, поэтому, надеюсь, есть простой способ сделать это с помощью API CoreLocation, который я упускал из виду в документации.
5 ответов
На вашем месте я бы попробовал проверить документацию по обратному геокодеру в 3.0 SDK. Я не могу сказать, что там, но вы можете, скажем, обнаружить, что обратный геокод возвращает placeMark, а затем, если вы посмотрите эту placeMark в SDK, вы можете обнаружить, что у него есть свойство почтового индекса. Кто знает?
На этой странице представлена база данных (в формате CSV) всех почтовых индексов США с указанием их широты и долготы. http://zips.sourceforge.net/
Файл 500к в распакованном виде. Вот несколько первых строк данных:
Выгрузите эти данные в локальную базу данных. Используйте формулу Хаверсина, чтобы сравнить свои координаты с координатами в базе данных, чтобы найти ближайшую точку. В CoreLocation есть функция getDistanceFrom, которую вы тоже можете использовать.
На этой странице есть функция Haversine в c и информация о базе данных почтовых индексов.
Изменить: Вот отличное объяснение от Google о вычислении расстояний. Он использует MySQL и PHP, но здесь также полезен SQL для поиска ближайших точек. Вероятно, было бы быстрее запросить с помощью SQL, а не с помощью функции getDistanceFrom.
Чтобы искать по километрам, а не по милям, замените 3959 на 6371.
Такой поиск называется «Обратное геолокация».
Готов поспорить, если вы искали Почтовый индекс тигра, вы можете что-то найти. см., например, здесь. Похоже, что на CPAN есть модуль Perl, который делает это, так что это не должно быть невозможным.
Google предлагает бесплатную услугу обратного геокодирования. Вы можете использовать его напрямую или попробовать Temboo SDK, который предлагает удобный доступ на нескольких языках, включая Objective C (с примерами кода).
Как наладить поиск адреса по координатам (и где взять нужный справочник)
Весной мы добавили в API DaData.ru фичу «Обратное геокодирование», она же «Адрес по координатам». Название намекает: метод принимает геокоординаты и отдает данные об адресе.
Солидный продукт с той же функциональностью предлагает «Яндекс» — он называется «Геокодер». Но сервис «Яндекса» бесплатен только для открытых некоммерческих проектов. Стандартный же тариф — от 120 000 ₽ в год — подходит не всем.
Мы подумали — если сделать бесплатную или недорогую альтернативу «Геокодеру», разработчики наверняка скажут спасибо. И сделали. В статье расскажу, как устроен «Адрес по координатам»: как мы наладили поиск, собрали справочник и упаковали в готовый метод.
Где берем данные и чем ищем адрес
Подступаясь к задаче, мы изучили готовые решения: где взять справочник координат с адресами и как потом искать по этому справочнику географические объекты. Оказалось, за нужными инструментами даже не придется далеко ходить.
Адресные объекты берем в ФИАС — Федеральной информационной адресной системе. Это самый полный из открытых и официальных адресных справочников. Подробно о нем мы уже писали на «Хабре», а сейчас важны четыре факта:
Координаты загружаем из OpenStreetMap (OSM). OSM — проект со свободной лицензией: энтузиасты собирают координаты всевозможных объектов и выкладывают для всех желающих.
Если по-простому, OSM — это набор точек, линий и полигонов на карте. У каждого объекта свое описание, тип и набор координат. Данные OSM для России лежат по адресам needgeo.com, osm.sbin.ru/osm_dump/ и osmosis.svimik.com/latest/.
Список источников публикуют на специальной странице в «Вики» проекта
Выгрузки состоят из PBF-файлов — этот формат используют вместо XML как более компактный. Превратить PBF в OSM XML ничего не стоит, с этим справится куча одобренных сообществом утилит.
Для собственного справочника мы берем адресные объекты из ФИАС, а затем ищем их координаты в OSM. Если нашли, сохраняем объединенные данные. Получается такое пересечение ФИАС и OSM.
И все это замечательно, но есть одна проблема: с качеством данных в OSM дела обстоят непросто. Координаты объектов часто не соответствуют реальности. Например, полигоны для регионов и районов адекватны. А для городов и ниже — уже не очень.
Полигоны — это многоугольники, ограничивающие площади на карте. Они состоят из связанного набора точек с координатами. Полигонами обозначают границы регионов, районов, городов и даже зданий
Основная работа, и с большим отрывом — собрать из OSM адекватные данные и отсеять брак. Задача настолько объемная, что я отвел под нее в статье отдельный раздел.
Дома, которых нет в ФИАС, загружаем тоже из OSM. Выше я уже говорил, что в ФИАС отсутствуют десятки тысяч домов. Это даже не проблема, а просто реальность, фон. Поэтому мы пополняем свой справочник домами из OSM. Но только теми, для которых в ФИАС существует улица. У пришедших из OSM зданий нет ФИАС ID, поэтому мы идентифицируем их как ФИАС-код родителя + номер дома.
По справочнику ищем с помощью прекрасного Lucene — нашего многолетнего помощника. За наводку спасибо сведущему индийцу, написавшему пост Indexing Geographical Data With Lucene (хорошее дополнение — материал A dive into spatial search algorithms — о k-d-деревьях, на которых построен алгоритм поиска).
Как только мы узнали об у́дали Lucene, проблема с поиском решилась почти сама. Делов осталось — пройтись наждачкой.
Как собрали базу координат и адресов
Для начала выложу багаж: прочитав статью, быстро сделать подобный справочник не получится. Мы собираем его с 2014 года, постоянно дополняя. Об этом чертовски длинном пути я и расскажу.
Самое сложное при составлении справочника — перебрать кординаты, которые пришли из OSM. На старте мы выверяли их как могли, в том числе руками. Главная цель тогда — получить опорные точки в крупных городах и сделать из них эталонный справочник. Теперь, когда таких точек много, проверять новые данные вручную почти не приходится. За раз мы добавляем в эталонный справочник 200 000–300 000 адресов с координатами, и вот как это делаем.
Формируем из OSM-тегов полные адреса́. В OSM-выгрузках составные части адресов разбросаны по разным тегам:
Прогоняем каждый новый адрес через API стандартизации «Дадаты». Сервис приводит адреса к единому формату «Как в ФИАС»:
142718, Московская обл, Ленинский р-н, с Булатниково, ул Центральная, д 103.
Адрес | ФИАС ID | Широта | Долгота |
---|---|---|---|
142718, Московская обл, Ленинский р-н, с Булатниково, ул Центральная, д 103 | a8b6a52f-e96d-4ec3-a0ff-641013ab0445 | 55.558773 | 37.667103 |
119034, г Москва, пер Турчанинов, д 6 стр 2 | 8c925e61-9173-48b3-999e-dc85c86d89e7 | 55.737096 | 37.597190 |
Разбираем адреса, которые «Дадата» не стандартизовала. Адреса́, которые не получилось сопоставить с ФИАС, сервис помечает флажком. Их проверяем вручную, вариантов здесь несколько.
Проверяем, насколько адекватны загруженные координаты. Для этого специальной утилитой смотрим, попадают ли координаты нового объекта в полигон родительского региона или района. Если адрес сообщает, что объект находится в Омской области, будь добр по координатам попадать в ее полигон. Вхождения в город не требуем — не все города точно освещены в OSM, для многих данные не обновляют.
Эталонные полигоны мы загружаем из OSM и храним как есть — в формате GeoJSON. Чтобы выбрать, к какому полигону примерить точку, смотрим в отдельную таблицу. В ней мы сопоставили префиксы КЛАДР-кодов и ID полигонов: находишь для адреса КЛАДР-код и видишь, какой полигон выбрать.
КЛАДР-код — это уникальный идентификатор, который использовали еще до появления ФИАС. Находить этот код для адреса умеет миллион сервисов
Утилита разрешает объекту отстоять от положенного полигона на 1 700 метров. Это правило добавили из-за шоссе, которые часто выходят за границы региона. Но расстояние больше 1 700 метров — признак ошибки, так говорит статистика.
На этом для городов и улиц проверка заканчивается.
Еще раз, построже, проверяем загруженные координаты домов. В дело снова вступает упомянутая утилита, и вот что она делает.
Проверку проходят только дома, которые удалены от надежных коллег не более чем на 150 метров. Причем каждый новый одобренный дом мы учитываем при разборе следующих. Вот как это работает.
Допустим, в эталонном справочнике хранятся дома № 1, 2 и 3 по улице Коммунаров. В новых данных пришли дома № 5, 6 и 7 по той же улице. Судя по координатам, новые дома стоят рядом. Утилита видит, что дом № 5 находится рядом с домами № 1, 2 и 3 и добавляет его в эталонный справочник. Значит, дома № 6 и 7 тоже проходят проверку.
А дальше решается судьба пришедших из OSM данных:
В первой таблице — все объекты c ФИАС ID до домов: регионы, населенные пункты, улицы. Во второй — дома́ и ссылка на родителя из первой таблицы
Две таблицы нужны, чтобы назначить ключи отсутствующим в ФИАС домам. У них нет собственного ФИАС-кода, поэтому делаем вот как:
Справочник готов, осталось протестировать. За ночь прогоняем сервис по функциональным тестам и тестируем производительность. Скорость проверяем на Москве, запрашивая все дома в радиусе трех километров. Чтобы уж наверняка. Конечно, обложили все автотестами.
Главное после обновления — чтобы не стало хуже.
Обратное геокодирование глазами пользователя
На вход метод принимает три параметра: координаты, количество результатов и радиус поиска. Радиус по умолчанию — 100 метров, максимальный — километр. Точное значение задают в настройках.
Обратно метод возвращает найденные объекты: дома, улицы и населенные пункты. При этом сортирует их по убыванию точности.
После всех этих рокировок метод наконец-то возвращает объекты, которые нашел.
Внутри — много разного о найденных объектах: строки с полным и сокращенным адресом, актуальное и устаревшие названия, почтовый индекс, ФИАС-код родительского объекта и так далее.
Все данные, которые отдает метод — в документации
Покрытие по координатам для разных регионов разное, вот так с домами:
Уже думаем, что добавить к методу: разрешить фильтрацию по типам объектов, возвращать расстояния до заданной точки, еще что-нибудь. Следим за спросом и решаем, вкладывать ли силы.
А в остальном все уже на проде. До 10 000 запросов в сутки — бесплатно, больше — по подписке от 5 000 ₽ в год. Если нужны адреса по координатам для коммерческого проекта, а «Геокодер» слишком дорог — попробуйте API «Дадаты».
Оригинал статьи опубликован в блоге HFLabs.
Используем почтовые индексы в своём приложении во благо
Я думаю, что на многих сайтах пользователя спросят его физический адрес. Для доставки ли, для отсылки бумажного
спама уведомлений ли. И, в общем-то — это мелочь. Вбил индекс, Москва, область, район, село, улица, дом, квартира. Казалось бы, что тут упрощать, каждый вроде помнит свой адрес, трудно ли его вбить? Но дьявол, как всегда, кроется в мелочах: пользователь опечатывается в адресе, посылка уходит не туда, лучи «добра» идут вам в обратную связь и вообще жизнь плохеет.
И она есть! Всамделишняя, электронная и, главное, официальная база индексов от Почты России.
Встречайте: vinfo.russianpost.ru/database/ops.html
База доступна в уже диковинном для молодых разработчиков формате DBF и регулярно (два раза в месяц) обновляется.
Конечно, по подробности эта база до ФИАС недотягивает, но, стоит отдать должное, она гораздо проще (всего одна таблица!), поэтому, если вам не нужна точность до улицы и дома, а хватит только населённого пункта — вам сюда.
Прикручиваем счастье к… ну, давайте к сайту.
Итак, радостно качаем базу и думаем, как же её впихнуть в используемый нами КакойТамУНасСовременныйSQL (а то и НеSQL).
Ищем в гугле, ищем в яндексе, ищем в apt-cache, последний нам радостно и выдаёт:
Здорово-то как! Я использую Postgres и конвертировать буду в него. В базе используется ещё досовская кодировка, так что призовём на помощь iconv. Кстати, самые свежие версии pgdbf (>= 0.6.2) сами шаманством владеют и iconv призывают, но до убунтовского репозитория они ещё не добрались.
Что же, теперь надо заставить это работать.
Я использую Ruby on Rails, на её примере и покажу. Кто рельсы не понимает, может пролистать.
Cоздаём модель, которая будет нашу информацию из базы данных и представлять в приложении
В миграцию вдумчиво копируем структуру таблицы из оригинальной базы, делаем индекс первичным ключом:
Слегка настраиваем модель:
Делаем простенький контроллер, который нам почтовый индекс в json-формате отдаст:
Прописываем в config/routes.rb маршрут, по которому приложение нам отдаст желанные индексы:
И, главное: html и javascript, которые и сделают всю магию для пользователя.
Javascript-код (очень подробный, с уведомлением пользователя, отловом ошибок и исправлением индекса)
И, вуаля, при вводе индекса нам автоматом подставляется область, город и так далее. Заодно, бонусом, мы можем исправлять устаревшие индексы на актуальные (очень часто у людей записаны адреса родственников с уже безнадёжно устаревшими индексами).
Резюме
Плюсы: простота внедрения, использования и поддержания в актуальном состоянии, малый вес
Минусы: невысокая подробность (только до населённого пункта), ВСЕ ГОРОДА КАПСОМ, ПОЧТА РОССИИ, ЗАЧЕМ?
API стандартизации адресов
✔️ Разбивает адрес по отдельным полям (регион, город, улица, дом, квартира).
✔️ Рассчитывает корректный индекс по данным Почты России.
✔️ Определяет координаты.
✔️ Показывает округ и район города, ближайшее метро, площадь и стоимость квартиры.
✔️ Достает коды КЛАДР, ФИАС, ОКАТО, ОКТМО и ИФНС.
Как вызвать
Чтобы вызвать метод, зарегистрируйтесь и подтвердите почту.
Укажите при вызове:
Что в ответе
Пример ответа
Название | Длина | Описание |
---|---|---|
source | 250 | Исходный адрес одной строкой |
result | 500 | Стандартизованный адрес одной строкой |
postal_code | 6 | Индекс |
country | 120 | Страна |
country_iso_code | 2 | ISO-код страны |
federal_district | 20 | Федеральный округ |
region_fias_id | 36 | ФИАС-код региона |
region_kladr_id | 19 | КЛАДР-код региона |
region_iso_code | 6 | ISO-код региона |
region_with_type | 131 | Регион с типом |
region_type | 10 | Тип региона (сокращенный) |
region_type_full | 50 | Тип региона |
region | 120 | Регион |
area_fias_id | 36 | ФИАС-код района |
area_kladr_id | 19 | КЛАДР-код района |
area_with_type | 131 | Район в регионе с типом |
area_type | 10 | Тип района в регионе (сокращенный) |
area_type_full | 50 | Тип района в регионе |
area | 120 | Район в регионе |
city_fias_id | 36 | ФИАС-код города |
city_kladr_id | 19 | КЛАДР-код города |
city_with_type | 131 | Город с типом |
city_type | 10 | Тип города (сокращенный) |
city_type_full | 50 | Тип города |
city | 120 | Город |
city_area | 120 | Административный округ (только для Москвы) |
city_district_fias_id | 36 | ФИАС-код района города (заполняется, только если район есть в ФИАС) |
city_district_kladr_id | 19 | КЛАДР-код района города (не заполняется) |
city_district_with_type | 131 | Район города с типом |
city_district_type | 10 | Тип района города (сокращенный) |
city_district_type_full | 50 | Тип района города |
city_district | 120 | Район города |
settlement_fias_id | 36 | ФИАС-код населенного пункта |
settlement_kladr_id | 19 | КЛАДР-код населенного пункта |
settlement_with_type | 131 | Населенный пункт с типом |
settlement_type | 10 | Тип населенного пункта (сокращенный) |
settlement_type_full | 50 | Тип населенного пункта |
settlement | 120 | Населенный пункт |
street_fias_id | 36 | ФИАС-код улицы |
street_kladr_id | 19 | КЛАДР-код улицы |
street_with_type | 131 | Улица с типом |
street_type | 10 | Тип улицы (сокращенный) |
street_type_full | 50 | Тип улицы |
street | 120 | Улица |
house_fias_id | 36 | ФИАС-код дома |
house_kladr_id | 19 | КЛАДР-код дома |
house_type | 10 | Тип дома (сокращенный) |
house_type_full | 50 | Тип дома |
house | 50 | Дом |
block_type | 10 | Тип корпуса/строения (сокращенный) |
block_type_full | 50 | Тип корпуса/строения |
block | 50 | Корпус/строение |
entrance | 10 | Подъезд |
floor | 10 | Этаж |
flat_fias_id | 36 | ФИАС-код квартиры |
flat_type | 10 | Тип квартиры (сокращенный) |
flat_type_full | 50 | Тип квартиры |
flat | 50 | Квартира |
flat_area | 50 | Площадь квартиры |
square_meter_price | 50 | Рыночная стоимость м² |
flat_price | 50 | Рыночная стоимость квартиры |
postal_box | 50 | Абонентский ящик |
fias_id | 36 | ФИАС-код адреса (идентификатор ФИАС) |
fias_code | Иерархический код адреса в ФИАС (СС+РРР+ГГГ+ППП+СССС+УУУУ+ДДДД) | |
fias_level | 2 | Уровень детализации, до которого адрес найден в ФИАС |
fias_actuality_state | Признак актуальности адреса в ФИАС | |
kladr_id | 19 | КЛАДР-код адреса |
capital_marker | 1 | Признак центра района или региона |
okato | 11 | Код ОКАТО |
oktmo | 11 | Код ОКТМО |
tax_office | 4 | Код ИФНС для физических лиц |
tax_office_legal | 4 | Код ИФНС для организаций |
timezone | 50 | Часовой пояс города для России, часовой пояс страны — для иностранных адресов. Если у страны несколько поясов, вернёт минимальный и максимальный через слеш: UTC+5/UTC+6 |
geo_lat | 12 | Координаты: широта |
geo_lon | 12 | Координаты: долгота |
beltway_hit | 8 | Внутри кольцевой? |
beltway_distance | 3 | Расстояние от кольцевой в км. Заполнено, только если beltway_hit = OUT_MKAD или OUT_KAD, иначе пустое |
qc_geo | 5 | Код точности координат |
qc_complete | 5 | Код пригодности к рассылке |
qc_house | 5 | Признак наличия дома в ФИАС |
qc | 5 | Код проверки адреса |
unparsed_parts | 250 | Нераспознанная часть адреса. Для адреса «Москва, Митинская улица, 40, вход с торца» вернет «ВХОД, С, ТОРЦА» |
metro | Список ближайших станций метро (до трёх штук) |
Координаты есть у 97% домов в Москве, 91% в Санкт-Петербурге, 69% в других городах-миллиониках и 47% по остальной России.
Площадь и стоимость есть у 70% квартир в России.
Коды качества
Код проверки qc
Нужно ли вручную проверить распознанный адрес:
Код qc | Описание | Нужно проверить вручную? |
---|---|---|
0 | Адрес распознан уверенно | Нет |
2 | Адрес пустой или заведомо «мусорный» | Нет |
1 | Да | |
3 | Есть альтернативные варианты. Пример: «Москва Тверская-Ямская» — в Москве четыре Тверских-Ямских улицы. | Да |
Код пригодности к рассылке qc_complete
Годится ли адрес для доставки корреспонденции:
Код qc_complete | Подходит для рассылки? | Описание |
---|---|---|
0 | Да | Пригоден для почтовой рассылки |
10 | Под вопросом | Дома нет в ФИАС |
5 | Под вопросом | Нет квартиры. Подходит для юридических лиц или частных владений |
8 | Под вопросом | До почтового отделения — абонентский ящик или адрес до востребования. Подходит для писем, но не для курьерской доставки. |
9 | Под вопросом | Сначала проверьте, правильно ли Дадата разобрала исходный адрес |
1 | Нет | Нет региона |
2 | Нет | Нет города |
3 | Нет | Нет улицы |
4 | Нет | Нет дома |
6 | Нет | Адрес неполный |
7 | Нет | Иностранный адрес |
Признак наличия дома в ФИАС qc_house и код точности координат qc_geo
Уточняют вероятность успешной доставки письма:
Код qc_house | Код qc_geo | Вероятность доставки | Описание |
---|---|---|---|
2 | любой | Высокая | Дом найден в ФИАС |
10 | 0 | Высокая | Дом не найден в ФИАС, но есть на картах |
10 | 1 | Средняя | Дом не найден в ФИАС, но есть похожий на картах |
10 | ≥ 2 | Низкая | Дом не найден в ФИАС и на картах |
Код точности координат qc_geo
Точность координат адреса для курьерской доставки:
Код qc_geo | Описание |
---|---|
0 | Точные координаты |
1 | Ближайший дом |
2 | Улица |
3 | Населенный пункт |
4 | Город |
5 | Координаты не определены |
Коды ответа на запрос
HTTP-код ответа | Описание |
---|---|
200 | Запрос успешно обработан |
400 | Некорректный запрос |
401 | В запросе отсутствует API-ключ или секретный ключ Или в запросе указан несуществующий ключ |
403 | Не подтверждена почта Или недостаточно средств для обработки запроса, пополните баланс |
405 | Запрос сделан с методом, отличным от POST |
429 | Слишком много запросов в секунду или новых соединений в минуту |
5xx | Произошла внутренняя ошибка сервиса |
Примеры и интеграции
Ограничения
Максимальная частота запросов — 10 в секунду с одного IP-адреса.
Максимальная частота создания новых соединений — 60 в минуту с одного IP-адреса.
Дадата не поддерживает вызов этого метода из браузерного JavaScript. Иначе злоумышленник мог бы похитить секретный ключ и использовать API за ваш счет.