войти зарегистрироваться

Business Development Group

Business Development Group
хабраиндекс
6,33

Где эта улица, где этот дом… Или как определить район, в котором находится предприятие

image

В процессе разработки нового сервиса у нас появилась интересная задачка. Необходимо определить принадлежность предприятия какому-либо административно-территориальному или муниципальному образованию и закрепить за предприятием район либо округ, в котором оно находится. Представлением для конечного пользователя должен быть фильтр в поисковой форме, который позволял бы найти организации только в заданном районе или округе города. И сделать это нужно для компаний по всей России.

Вводные данные: у нас была некоторая наработанная база, насчитывающая достаточно большое количество организаций по всей России. База включала адреса предприятий, которые представляли собой обыкновенную строку. Соответственно, каких-то очевидных способов сделать территориальную привязку не было.

Для реализации такой, казалось бы, несложной задачи, пришлось изрядно поломать голову. Поначалу была идея использовать Google-maps для того, чтобы через пользовательские карты очертить контуры районов, а координаты организаций получить через геокодер Яндекса. Но данная идея оказалась утопична – нарисовать карты районов для всей России осилит не каждый.

Подходящее решение пришло в голову внезапно – использовать уже готовые базы административно-территориальных делений КЛАДР. Данная база содержит полный список населенных пунктов, улиц и домов России. Так же база КЛАДР содержит для каждой территориальной единицы код ОКАТО (Общероссийский классификатор объектов административно-территориального деления). Стоит отметить, что сама база ОКАТО не входит в состав КЛАДР и должна быть загружена отдельно.

Итак, база, по которой можно определить округ или район имеется. Осталось разобраться, как сопоставить ей имеющиеся адреса. Данные о домах в КЛАДР хранятся довольно специфичным образом: информация о доме может содержать множество различных обозначений, таких как корпус, строение, четность, что так же должно учитываться при определении района. А значит нам необходимо проанализировать имеющиеся адреса. Сделать это можно двумя способами:

Первый – самый простой и не надежный: скормить адрес имеющихся фирм геокодеру Яндекса, который и разберет адрес на кусочки. Но есть и большой минус этого способа – если в базе геокодера такого адреса по какой то причине не окажется, то он вернет ближайшее к указанному месту строение. А может и вообще ничего не вернуть…
Второй способ – путь джедая. Реализовать парсер адреса собственноручно. Так как для нашего сервиса точность определения адреса была критичной, было решено реализовать парсер собственными силами и средствами. Простейший пример реализации здесь. В примере строка адреса разбирается на массив, ключами которого являются типы территориальных единиц. В приведенном примере есть одно «но»: адрес должен быть уже в «правильном» формате. То есть, к примеру, дом в адресе должен идти обязательно после улицы, а не перед ней.

Теперь, когда адрес представляет более понятную структуру, его можно сопоставить с имеющейся базой КЛАДР и получить код ОКАТО. Сама по себе база КЛАДР не дает представления о принадлежности территории какому-то району или округу. При помощи нее можно определить максимум сам код ОКАТО ну и еще почтовый индекс. А Нужное представление может дать сама база ОКАТО. Именно в ней располагается информация по внутригородским районам, округам городов республиканского, краевого, областного подчинения.

Итак, скрипты написаны, коды сопоставлены. В результате на свет появился вот такой функционал:

image

Реализовано и описано by zdanchik

комментарии (15)

  • НЛО прилетело и опубликовало эту надпись здесь.
    • Пока проект находится в закрытом тестировании. Здесь описан лишь алгоритм.
  • Не понял смысл статьи.
    «У нас был файл, мы написали парсер, он распарсился».
    Ну я каждый день такое делаю, так и шо?
    • Распарсить файл — практически всегда дело плевое… Однако в данном случае акцент нужно сместить в сторону: «как реализовать верный алгоритм». Ведь, впервые столкнувшись с подобной задачей, не мудрено наломать дров…
  • позволите, у меня небольшое замечание по коду. все-же, это не очень элегантное решение:
    elseif (
       
    mb_strpos(mb_strtolower($addrItem'UTF-8'), 'просп. ')
    || 
    mb_strpos(mb_strtolower($addrItem'UTF-8'), ' просп.')
    || 
    mb_strpos(mb_strtolower($addrItem'UTF-8'), 'пр-т')
    || 
    mb_strpos(mb_strtolower($addrItem'UTF-8'), 'проспект')
    )

    Достаточно объявить всего две ф-ции:
    function contains ($in$str) {
        return 
    mb_strpos(mb_strtolower($in'UTF-8'), $str);
    }
    function 
    containsOne ($in, array $array) {
        foreach (
    $array as $str) {
            if (
    contains($in$str)) {
                return 
    true;
            }
        }
        return 
    false;
    }

    и мы получаем намного более изящный результат, код уменьшается в раз 5 и становится намного более читаемым и расширяемым:
    elseif (containsOne($addrItem, array('просп. '' просп.''пр-т''проспект')))


    • но рефакторить код есть куда. очень много мест. сейчас он вообще плох.
      • еще непонятно, что будет, если ищущийся итем стоит в начале строки. например «г. Такой-то, просп. Другой-то». Корректно проверять как
        • *корректно проверять так:
          • та блин. вот так, то есть сравнивая c false:
            mb_strpos(mb_strtolower($in'UTF-8'), $str) === false;

    • Да, согласен. Код писался на скорую руку и очень сыр. Пусть не будет звучать как оправдание, но целью данного кода был разовый разбор имеющихся данных. Цель оправдывает средства.
      • я бы постеснялся выкладывать столь сырой код, да еще и сообщая, что это библиотека.
        да и ведь неудобно так разрабатывать то было. задолбаться ведь можно
  • Первый – самый простой и не надежный: скормить адрес имеющихся фирм геокодеру Яндекса, который и разберет адрес на кусочки. Но есть и большой минус этого способа – если в базе геокодера такого адреса по какой то причине не окажется, то он вернет ближайшее к указанному месту строение…

    а в чём тут проблема? он же сообщает с какой точностью найден объект: api.yandex.ru/maps/jsapi/doc/ref/reference/geocoderresult.xml#precision
    • Дело в том, что случаются моменты, когда дома, находящиеся по одной улице, могут находится в совершенно разных районах. Был такой случай, что геокодер определял дом, который находится не в соответствующем районе
  • нарисовать карты районов для всей России осилит не каждый
    Они все уже нарисованы и храняться в wikimapia. Можно подключить слой от WikiMapia в Google Earth и сохранять полигоны в kml-файлы.

    Я такое безобразие делал для сервиса частных объявлений о недвижимости. Способ, может быть и не совсем прямой, но для Нижнего его таки можно осилить =)
  • Спасибо, ваша статья очень помогла, а то я уже мозг взорвала над тем где мне все таки получить внутригородские р-ны в кладаре, а их так и нет вовсе
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.