- PVSM.RU - https://www.pvsm.ru -
Не так давно передо мной встала задача выгрузки данных одного моего заказчика в очередной около-государственный формат. Помимо прочего, в выгрузке требовалось структурированно предоставлять почтовые адреса клиентов-физлиц, включая индекс, область, район и так далее до номера квартиры.
Все бы хорошо, только засада в том, что исходные адреса клиентов были забиты в виде простой строки типа «Китежград, ул.Волшебная 22 дом кв.15». То есть, с одной стороны, о почтовых индексах никто слыхом не слыхивал, с другой же, текстовое поле ввода предлагает широкий простор для самовыражения и народно-прикладного творчества.
Ничтоже сумняшеся я полез искать решение сей проблемы в сети, рассудив, что подобная ситуация должна быть весьма распространенной и кем-то однозначно побежденной. Так и оказалось, правда, вместо исходников или просто скомпиленных либ на меня жадно пялились онлайн-сервисы, предлагающие с использованием их API парсить почтовые адреса за вполне реальную мзду (минимальный прайс, который мне удалось найти, составлял 10 копеек за адрес).
Так как отдавать добровольно доходы какой-то сторонней организации мне не нравилось, да и к тому времени появился некий азарт, захотелось сколхозить решение самостоятельно, по возможности минимальными усилиями. Облегчало задачу то, что заказчику не требовалась высокая точность парсинга – наличие ошибок любого рода не приводило бы к фатальным проблемам.
Для начала посмотрел в сторону Томита-парсера, но после знакомства с многостраничным конфигом примера, позволяющего по тексту определить, в каком городе кто живет (http://api.yandex.ru/tomita/doc/dg/concept/example.xml [1]), оптимизма несколько поубавилось, но укрепилось желание написать какой-нибудь свой велосипед.
Естественно, с достаточно жесткими ограничениями на входные данные, при которых будем продолжать изыскания:
Далее я озадачился поиском источника данных, из которого смог бы черпать сведения по почтовым индексам. Как оказалось, на сей день КЛАДР – это уже вчерашний день, ФИАС рулит (http://fias.nalog.ru [2]). Загрузив оффлайновую копию этой базы, я принялся изучать предоставляемые ею возможности.
Особо заинтересовали меня там две таблицы: ADDROBJ – в ней хранится древовидный список всех адресных объектов, начиная с субъекта РФ и заканчивая улицей, и HOUSE<номер региона> – где хранятся номера домов с привязкой к записям в ADDROBJ вместе с их индексами. Хранящейся в этих двух таблицах информации достаточно для достижения обеих целей: проверки правильности парсинга адреса (если удалось найти адрес в базе данных, значит, мы его распознали верно), а так же для определения почтового индекса.
В голове начал вырисовываться алгоритм:
Алгоритм получился эмпирическим, наивным, предусматривающим не все возможные ситуации… Но для ограничений по скорости реализации и обширным правам на ошибку – он выглядел вполне удовлетворительным. Сочинить и реализовать его удалось примерно за 1 вечер.
Для привычки и удобства работы перегнал таблицы ADDROBJ и HOUSEXX из DBF в MS SQL (как их можно легко отконвертировать, прочел здесь: http://blogs.technet.com/b/isv_team/archive/2012/05/14/3497825.aspx [3]).
В результате получился класс AddressParser, забирающий на входе строку адреса и выдающий в ответ экземпляр класса Address. В конструктор AddressParser можно подавать собственную реализацию IKnwonAddressComparator, если текущая реализация, заточенная на MS SQL чем-то не устраивает.
По скорости парсинга получилось что-то около 2-5 адресов в секунду. Плохо, но все лучше, чем ручками. Основная проблема: серьезное количество вариантов для проверки, генерируемое пунктом 1.3. По-хорошему, этот момент стоит полностью переписать, используя базу адресов уже на этом этапе для проверки существования адресных элементов. В качестве промежуточного варианта можно ограничить количество вариантов неким значением.
По случайной выборке качество парсинга составило 62% на реальных данных. Для оценки считалось, что адрес может либо быть полностью распознан (вплоть до квартиры), либо нет. Никаких полутонов.
Распределение по ошибкам получилось следующее:
Каике выводы можно сделать?
Если нужно, как и мне, невысокое качество парсинга и низкая скорость – можно использовать.
Коли требуется существенно поднять точность распознавания, можно попробовать внедрить нечеткий поиск. Кроме того, добавив список популярных сокращений, можно так же подтянуть процент успешно распознанных адресов.
Производительность – это отдельная песня, которой, учитывая элементарную и неоптимальную реализацию – так же можно заняться. Первый кандидат здесь – умное разбиение по пробелам.
Но все это – уже совсем другая история.
Исходные коды можно загрузить отсюда: https://yadi.sk/d/muzi9b6qZ8DWh [4]
Тестовую MS SQL базу с домами по 38 и 78 регионам можно взять здесь: https://yadi.sk/d/ERXyDXv7Z8Dab [5]
Автор: t13s
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/66826
Ссылки в тексте:
[1] http://api.yandex.ru/tomita/doc/dg/concept/example.xml: http://api.yandex.ru/tomita/doc/dg/concept/example.xml
[2] http://fias.nalog.ru: http://fias.nalog.ru
[3] http://blogs.technet.com/b/isv_team/archive/2012/05/14/3497825.aspx: http://blogs.technet.com/b/isv_team/archive/2012/05/14/3497825.aspx
[4] https://yadi.sk/d/muzi9b6qZ8DWh: https://yadi.sk/d/muzi9b6qZ8DWh
[5] https://yadi.sk/d/ERXyDXv7Z8Dab: https://yadi.sk/d/ERXyDXv7Z8Dab
[6] Источник: http://habrahabr.ru/post/232347/
Нажмите здесь для печати.