Создание справочника адресной информации с блекджеком и API

в 8:10, , рубрики: laravel, php, postgresql

Часть 1. Трагическая. “За что мне все это?!”

Столкнулись мы как-то с необходимостью ввода корректной информации о местонахождении (прописке, регистрации) пользователей, и с тем, что проблема эта решается не совсем так легко и просто, как бы нам хотелось. Сначала мы попробовали КЛАДР, в его бесплатной ипостаси. Не то чтобы нам прямо-таки решительно все не понравилось, но было как минимум одно весьма раздражающее обстоятельство — некоторые адреса отсутствовали в справочнике. Например, дом 10 есть, а 10к1 — извините, не завезли. Вообще КЛАДР был привлекателен тем, что у него есть простой API и плагины (jQuery в частности), которые можно легко встроить в приложение, но отталкивал наполнением. Мы задумались — если нет такого ресурса, содержащего полную и наиболее актуальную адресную информацию, с API и плагинами, то единственный выход — создать такой ресурс самим.

Часть 2. Искательская. “Где собака зарыта?!”

И прослышали мы про ФИАС. О том как он бесконечно полон и прекрасен. А это выход! На сайте ФИАС есть базы, и все что нужно молодой растущей информационной системе! Правда, размер базы составляет более 4 Gb, ну да ладно, это же вся Россия! Обновляется база регулярно, так что есть где разгуляться. Дело за малым — развернуть базу, прикрутить API и плагины. Надо оговориться, что существует несколько релевантных и важных статей. К примеру, цикл вот этих статей, которые изначально очень помогли.

Часть 3. «Как это работает»

Проблемы начались с того, что база данных ФИАС поставляется в формате .dbf, данные из которого надо было как-то перенести в PostgreSQL, который было решено использовать в качестве БД.

Нужно отметить, что кроме формата .dbf, база представлена в формате xml. Как известно, человеку хочется всего и сразу. Чтобы включил и работает. Но разобраться сразу с тем, что же дает ФИАС довольно проблематично.

Итак, по адресу fias.nalog.ru в разделе обнлвлений имеется следующее:

  • Информация про обновления: по официальным данным — выходят не менее раза в неделю. Специфика следующая. Иногда выходят битые обновления. Их размер примерно 1,2 Mb и при скачивании дается битый архив, поэтому торопиться настраиваться только на последнее обновление — вызывает вопросы.
  • Обновления в виде fias_delta_. — в форматах .dbf и .xml.
  • Собственно база данных fias_. — в форматах .dbf и .xml.
  • База данных в формате КЛАДР. Наименование файлов “Base.*” arj или 7z Отличается тем, что отсутствуют многие поля (касательно налоговых данных и т.д.), поиск осуществляется по КЛАДРовскому id. Изначально присутствует соблазн использовать именно данный формат, так как он более легок для понимания и последующего внедрения. Но при более внимательном изучении портала, обнаружится, что данная версия будет поддерживаться только до конца 2017 года, а затем будет deprecated.

Примечание: для работы с .dbf файлами необходимо установить стороннее расширение для php_dbase.dll.

Так какую же все таки выбрать версию для скачивания .xml или .dbf? Отличия следующие:

  • xml — каждый файл в архиве — отдельная таблица. В чем состоит проблема. К примеру, размер файла “HOUSEXX” где хранятся дома, составляет более 20 Gb в разархивированном виде. Как его парсить? С одной стороны, если у вас более 30 Gb RAM, то это не составит проблемы. Также, если вы знаток грамотных библиотек, таких как SAX Parser для Java, которые не загружают файл целиком в память, а парсят частями, то может быть что-то и получится.
  • dbf — файлы не только разделяются как таблицы, но и подразделяются по регионам. Окажется более приемлемым вариантом, если вам не нужны адреса необъятной Родины, а только одного региона (как в нашем конкретном случае).

Итак, распаковали файлы. Какая информация нам нужна? Видим следующий набор файлов:

  • ADDROBХХ.DBF, где ХХ — номер региона — содержит данные непосредственно о регионе, автономных округах, городах и прочих населенных пунктах, улицах.
  • HOUSEХХ.DBF, где ХХ — номер региона — содержит информацию о номерах домов.
  • NORDOCХХ.DBF, где ХХ — номер региона — содержит информацию о причинах изменений в различных записях.
  • ROOMХХ.DBF, где ХХ — номер региона — содержит информацию о помещениях.
  • STEADХХ.DBF, где ХХ — номер региона — содержит информацию о земельных участках.
  • SOCRBASE.DBF — содержит информацию о сокращениях.
  • STRSTAT.DBF — содержит информацию о типе строения.

Кроме данных таблиц существует еще ряд других — служебных таблиц, которые содержат информацию о сокращениях в других таблицах.

В большинстве случаев достаточно сформировать адрес вплоть до дома. Хотя, если кому надо, то можно углубиться и дальше.

Таким образом, создадим 2 таблицы в БД postgresql.

Таблица с адресами:

CREATE TABLE addrs
(
    "ACTSTATUS" integer,
    "AOGUID" character varying(36) COLLATE pg_catalog."default",
    "AOID" character varying(36) COLLATE pg_catalog."default",
    "AOLEVEL" integer,
    "AREACODE" integer,
	"AUTOCODE" integer,
    "CENTSTATUS" integer,
    "CITYCODE" integer,
	"CODE" character varying(20) COLLATE pg_catalog."default",
	"CURRSTATUS" integer,
	"ENDDATE" timestamp,
    "FORMALNAME" character varying(120) COLLATE pg_catalog."default",
	"IFNSFL" integer,
	"IFNSUL" integer,
	"NEXTID" character varying(36) COLLATE pg_catalog."default",
    "OFFNAME" character varying(120) COLLATE pg_catalog."default",
	"OKATO" VARCHAR(11),
	"OKTMO" VARCHAR(11),
	"OPERSTATUS" integer,
	"PARENTGUID" character varying(36) COLLATE pg_catalog."default",
	"PLACECODE" integer,
	"PLAINCODE" character varying(20) COLLATE pg_catalog."default",
    "POSTALCODE" integer,
	"PREVID" character varying(36) COLLATE pg_catalog."default",
	"REGIONCODE" integer,
    "SHORTNAME" character varying(15) COLLATE pg_catalog."default",
	"STARTDATE" timestamp,
	"STREETCODE" integer,
	"TERRIFNSFL" integer,
	"TERRIFNSUL" integer,
	"UPDATEDATE" timestamp,
	"CTARCODE" integer,
	"EXTRCODE" integer,
	"SEXTCODE" integer,
	"LIVESTATUS" integer,
    "NORMDOC" character varying(36) COLLATE pg_catalog."default",
	"PLANCODE" integer,
	"CADNUM" integer,
	"DIVTYPE" integer
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE address
    OWNER to postgres;

Таблица с номерами домов:

CREATE TABLE hous
(
    "AOGUID" character varying(36) COLLATE pg_catalog."default",
    "BUILDNUM" character varying(10) COLLATE pg_catalog."default",
	"ENDDATE" timestamp,
	"ESTSTATUS" integer,
    "HOUSEGUID" character varying(36) COLLATE pg_catalog."default",
    "HOUSEID" character varying(36) COLLATE pg_catalog."default",
    "HOUSENUM" character varying(15) COLLATE pg_catalog."default",
	"STATSTATUS" integer,
	"IFNSFL" integer,
	"IFNSUL" integer,
	"OKATO" VARCHAR(11),
	"OKTMO" VARCHAR(11),
	"POSTALCODE" integer,
	"STARTDATE" timestamp,
	"STRUCNUM" VARCHAR(15),
	"STRSTATUS" integer,
	"TERRIFNSFL" integer,
	"TERRIFNSUL" integer,
	"UPDATEDATE" timestamp,
	"NORMDOC" character varying(36) COLLATE pg_catalog."default",
	"COUNTER" integer,
	"CADNUM" VARCHAR(50),
	"DIVTYPE" integer
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

Импорт данных осуществляется простым способом. Открываем файлы в Excel и сохраняем их как csv. Дополнительно рекомендуется изменить кодировку, так как в отличии от xml файлов, которые представлены в кодировке utf-8, dbf файлы — в кодировке win-866. Открываем файлы в редакторе (для данной цели подойдет notepad++) и преобразуем в utf-8.

Импорт таблицы с адресами:

COPY addrs FROM 'PathToTheFileADDROB01.csv' DELIMITER ';' CSV;

Импорт таблицы с домами:

COPY addrs FROM 'PathToTheFileHOUSE30.csv' DELIMITER ';' CSV;

Из чего сделана таблица ADDROBXX?

Несмотря на обилие полей, понадобятся только некоторые из них.

  • ACTSTATUS — поле содержит значения 0 и 1. При внимательном просмотре обнаружится, что в таблице множество улиц с одним и тем же названием. Дело в том, что налоговая база содержит историю объектов, т.е. изменения, которые происходили с каким-либо элементов адреса. К примеру, улиц Ленина может быть 10 штук. Из них 9 — будут неактуальными. Они могли быть переименованы или изменены другим образом. ACTSTATUS — 0 — неактуальные адреса, а 1 — будет единственным актуальным.
  • AOGUID — ID записи. Для разных исторических записей будет один и тот же AOGUID. Различаться они будут по полю AOID.
  • AOLEVEL — уровень объекта. Под номером 1 — субъект федерации, 4 — город, 7 — улица и т.д.
  • CENTSTATUS — статус центра. Например, города в областном центре.
  • FORMALNAME — название объекта.
  • PARENTGUID — ID родительского элемента. При поиске города к которому принадлежит улица. PARENTGUID улицы будет совпадать с AOGUID улицы.
  • POSTALCODE — почтовый индекс.
  • REGIONCODE — код субъекта федерации.

Примечание: на fias-nalog.ru можно найти полное описание всех полей.

Важное в таблице HOUSEXX:

  • AOGUID — ID улицы в ADDROBXX, в которой находится дом.
  • HOUSEGUID — ID дома.
  • Сложность заключается в наименовании дома. Оно состоит из 4 полей:
  • BUILDNUM — номер корпуса.
  • HOUSENUM — номер дома.
  • STRUCNUM — номер строения.
  • STRSTATUS — признак строения (от 0 до 4, где 0 — никакого, 1 — строение, 2 — сооружение, 3 — литера).

Поля могут содержать схожую или идентичную информацию и выходить из ситуации приходится экспериментальным путем. В классе QuerryController (ссылка на репозиторий — ниже) есть метод: chooseBuilding, в котором мы попытались решить эту задачу. Может быть у кого-то получится лучше. Запросы к БД находятся там же.

Далее, после того, как база была импортирована в Postgres — мы занялись созданием API и плагина для нашей системы.

Для API, дабы не изгаляться, использовали Laravel. Схема запросов получилась достаточно простой. Иерархия объектов выглядит следующим образом:

  • Субъект федерации
  • Регион субъекта федерации
  • Населенный пункт
  • Улица
  • Дом

К слову, тестируя систему, мы столкнулись с тем, что не во всех населенных пунктах есть улицы, и не на всех улицах есть дома, что нас немало удивило, и озадачило. Это обстоятельство не давало покоя потому, что если предоставить пользователю возможность самому вводить информацию, то понапишут такого, что невольно возникает вопрос — “Эти люди вообще в школе-то учились?!”.
Поэтому было решено не давать пользователю ни малейшей возможности для самодеятельности, а для таких вот “отсутствующих” адресов предоставить возможность подать заявку на включение отсутствующего адреса в справочную систему.

Схема запросов выглядит просто:

Для последнего пункта формируется список домов с литерами, корпусами, строениями, и прочим.
После всех мытарств сделали плагин на vue.js, для работы со справочником, и его альтернативу на jQuery.

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

В папке ASPUDcomponent — находится VueJs компонент для работы с адресной базой.
Исходники доступны в нашем репозитории.

Часть 4. Как это все обновлять?

С обновлениями ситуация следующая: для начала необходимо по протоколу SOAP получить версии обновлений. Посмотреть как это делается можно в классе UpdateController (метод: filesVersions()).

Примечание: версия, которая указана последней в полученном списке — не обязательно совпадает с той, которую можно скачать на главной странице. Но не стоит спешить скачивать только последнюю версию, так как она может оказаться “битой”. Случались и таким прецеденты. Далее скачивается архив с последней версией и распаковывается. Для работы необходимо использование расширения для php (php_rar.dll).

Ну а далее выбирается необходимый файл региона (или при необходимости все файлы) для обновления БД.

Автор: il_kow

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js