ФИАС: различия между версиями
Mavka (обсуждение | вклад) |
Mavka (обсуждение | вклад) |
||
Строка 275: | Строка 275: | ||
// ToDo: построение полного списка исторический названий | // ToDo: построение полного списка исторический названий | ||
Примечания: | |||
# Наблюдение (в документации не разъяснено): при внесении изменений, предыдущая историческая запись №1 получает значение (CURRSTATUS = 1). Если вносится повторное изменение, то историческая запись №2 принимает значение (CURRSTATUS = 2). Таким образом, цепочка от современного названия к самому староми принимает вид: 0, ..., 3, 2, 1. |
Версия от 20:18, 9 января 2013
Введение
Вопросы/пожелания/замечания - http://gis-lab.info/forum/viewtopic.php?f=3&t=12568
Федеральная информационная адресная система (ФИАС) создана Распоряжением Правительства Российской Федерации от 10.06.2011 №1011-р. С целью...
Замена КЛАДР... Тем не менее классификатор КЛАДР продолжает публиковаться и обновляться - версия 4.0 от 24.12.2012.
С момента первой публикации структура и содержание ФИАС многократно критиковались. Тем не менее, за время существования базы, она объективно улучшается и часть ошибок уже устранена. Поэтому указанные в этом документе несоответствия могут быть устранены в будущем и их следует уточнять на свежих данных.
Загрузка данных
Процесс импорта данных из файлов XML в реляционную базу данных дается на примере PostgreSQL. Все применяемые инструменты являются кросплатформенными. Для других БД (MySQL, Oracle и т.п.) процедура потребует незначительной доработки. См. также гл. 2.3, в которой приводятся ссылки на сторонние проекты, предоставляющие подготовленные данные в других форматах.
Создание таблиц
На сайте ФИАС представлены схемы XSD, описывающие структуру данных. Для преобразования схемы в формат SQL (CREATE TABLE...) применим XSL Transformation (XSLT). В зависимости от БД может потребоваться изменить типы данных колонок.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" indent="no"/>
<xsl:template match="/">
<xsl:variable name="filename" select="lower-case(tokenize(tokenize(base-uri(.), '/')[last()],'\.')[1])" />
DROP TABLE IF EXISTS <xsl:value-of select="$filename"/>;
CREATE TABLE <xsl:value-of select="$filename"/> (
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<xsl:text> </xsl:text><xsl:value-of select="@name"/><xsl:text> </xsl:text>
<xsl:choose>
<!-- тип данных -->
<xsl:when test="xs:simpleType/xs:restriction/@base='xs:integer'">integer</xsl:when>
<xsl:when test="xs:simpleType/xs:restriction/@base='xs:byte'">integer</xsl:when>
<xsl:when test="xs:simpleType/xs:restriction/@base='xs:string'">text</xsl:when>
<xsl:when test="@type='xs:date'">date</xsl:when>
</xsl:choose>
<xsl:if test="@use='required'"> NOT NULL</xsl:if>
<xsl:if test="position()!=last()">,
</xsl:if>
</xsl:for-each>
);
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<a>COMMENT ON COLUMN <xsl:value-of select="$filename"/>.<xsl:value-of select="@name" /> IS </a>
<xsl:choose>
<!-- Часть комментариев слишком длинная, обрезаем лишние строки -->
<xsl:when test="contains(xs:annotation/xs:documentation,'
')">
<a>'<xsl:value-of select="substring-before(xs:annotation/xs:documentation,'
')"/>'</a>
</xsl:when>
<xsl:otherwise>'<xsl:value-of select="xs:annotation/xs:documentation"/>'</xsl:otherwise>
</xsl:choose>
<xsl:text>;
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Схема подходит для всех таблиц ФИАС. Для работы требуется процессор, поддерживающий XSLT 2.0. Например, Saxon XSLT Processor (MPL). Тогда обработка файлов принимает вид (версии .NET, Windows):
@echo off
SET PATH=%PATH%;d:\Program Files\Saxonica\SaxonHE9.4N\bin
for %%f in (*.xsd) do (
Transform ^
-xsl:xsd2db.xslt ^
-s:%%f ^
-o:sql\%%~nf.sql
)
Далее полученные файлы SQL желательно откорректировать, чтобы явно назначить ключи (primary keys).
//// Ссылка на готовые файлы
Импорт данных
Для работы с большими файлами XML предпочтительнее применять потоковые парсеры: используется фиксированное количество оперативной памяти (в приведенном скрипте - порядка 80 Мб) на протяжении всего процесса работы.
Ниже приводится скрипт ETL Scriptella (Apache License) на базе парсера SAX. Он подходит для любой реляционной БД, для которой есть java-драйвер.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE etl SYSTEM "http://scriptella.javaforge.com/dtd/etl.dtd">
<etl>
<connection id="in" driver="janino"/>
<connection id="out" driver="postgresql" url="jdbc:postgresql://localhost:5432/address" user="postgres" password="secret">
autocommit.size=100
</connection>
<query connection-id="in">
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean isObject = false;
int recordCnt = 0;
public void startElement(String uri, String localName,String qName, Attributes attr) throws SAXException {
if (qName.equalsIgnoreCase("Object")) {
String names = "";
String values = "";
int attrCnt = attr.getLength();
for (int i=0; i < attrCnt; i++) {
names += attr.getQName(i) + ",";
values += "'" + attr.getValue(i).replaceAll("'", "''") + "',";
}
names = names.substring(0, names.length()-1);
values = values.substring(0, values.length()-1);
set("sql_names", names);
set("sql_values", values);
<script connection-id="out">
INSERT INTO ###TABLE### ($sql_names) VALUES ($sql_values);
</script>
next();
recordCnt++;
System.out.print("\rprocessed: " + recordCnt);
}
}
};
System.out.println("\n\n\nConverting...");
saxParser.parse("../xml/###TABLE###.xml", handler);
</query>
</etl>
Примечания:
- Паттерн ###TABLE### следует заменить на имя файла/таблицы (например, ADDROBJ);
- Да работы требуются дополнительные библиотеки: Janino, PostgreSQL JDBC Driver;
- Выполняется простейшее экранирование значений (одиночная кавычка ').
Другие источники
Данные ФИАС также распространяются в формате DBF. Для работы с ними рекомендуются утилиты типа PgDBF (импорт ФИАС).
- BasicData.ru - WebAPI и файлы для импорта в БД MySQL. Также может быть интересна БД "Почтовые отделения".
- Классификаторы России (rus-ref)
- zXML Parser - "Парсинг баз ФИАС в MySQL (потоковый XML парсер)". Программа из данных XML создает файл с sql-запросами.
Структура данных ФИАС (описание таблиц)
Для понимания структуры данных ФИАС требуются следующие документы:
- Сведения о составе информации Федеральной информационной адресной системы (DOC);
- Описание Классификатора адресов российской федерации (КЛАДР) (в архиве DOCUM.ARJ)
Таблицы
Основные
- ADDROBJ - Классификатор адресообразующих элементов (край > область > город > район > улица)
- HOUSE - Сведения по номерам домов улиц городов и населенных пунктов, номера земельных участков и т.п
- HOUSEINT - Интервалы домов
- LANDMARK - Описание мест расположения имущественных объектов
- NORMDOC - Сведения по нормативному документу, являющемуся основанием присвоения адресному элементу наименования
Справочники
- SOCRBASE - Типы адресных объектов (условные сокращения и уровни подчинения)
- CURENTST - Статус актуальности КЛАДР 4.0
- ACTSTAT - Статус актуальности ФИАС
- OPERSTAT - Статус действия
- CENTERST - Статус центра
- INTVSTAT - Статус интервала домов
- HSTSTAT - Статус состояния объектов недвижимости
- ESTSTAT - Признак владения
- STRSTAT - Признак строения
- NDOCTYPE - Тип нормативного документа (закон, приказ, справка) // не упоминается в официальной документации
ADDROBJ
//ToDo:
- текстовые элементы адреса
- статус актуальности
- исторические названия
- иерархия
- ссылки, классификаторы
Иерархия административных единиц
В таблице ADDROBJ иерархия построена по типу плоского дерева. И родительские и дочерние элементы хранятся в одной таблице. Воссоздание иерархии выполняется с помощью полей:
- AOGUID - Глобальный уникальный идентификатор адресного объекта. Не смотря на название, уникальным в пределах таблицы он не является. Могут существовать несколько исторический версий и одна единственная актуальная для данного объекта. Подробнее см. раздел "Статус актуальности".
- PARENTGUID - Идентификатор объекта родительского объекта. Содержит ссылку на AOGUID родительского элемента.
- AOLEVEL - Уровень адресного объекта. Всего существует 8 основных уровней и несколько дополнительных (см. табл. SOCRBASE):
- 1 - край/область
- 4 - город/поселок
- 6 - микрорайон / нас. пункт в составе муниципального образования
- 7 - улица/квартал
- 8 - дом [Прим. - записей этого уровня в таблице нет]
// ToDo
Статус актуальности
В базе ФИАС никогда не удаляются элементы. Они могут быть только переведены в разряд "отключенных" (устаревшие, измененные и т.п.). Поведение аналогично работе КЛАДР. Рассмотрим поля, определяющие действительность объекта:
Для выбора актуальных записей рекомендуется ориентироваться на поля CURRSTATUS и LIVESTATUS.
Рассмотрим подробнее:
- LIVESTATUS - Признак действующего адресного объекта. Принимает значения: 0 - действующий, 1 - не действующий (см. прим. 1).
- CURRSTATUS - Статус актуальности КЛАДР 4. Принимает значения: 0 - актуальный, 1-50 - исторический, 51 - переподчиненный (см. табл. CURENTST и гл. 1.2. "Коды адресных объектов" документации КЛАДР).
- OPERSTATUS - Статус действия. Принимает значения: 1 - Инициация, 10 - Добавление, 20 - Изменение и др (см. табл. OPERSTAT).
- ACTSTATUS - Статус актуальности адресного объекта ФИАС. Принимает значения: 1 - актуальный, 0 – не актуальный (см. табл. ACTSTAT). Отвечает непосредственно за актуальность "имени". Если объект был переименован (чаще это исправление опечаток), то старая запись получает CURRSTATUS=1 и ACTSTATUS=0. Если же административная единица была ликвидирована или переподчинена, то имя останется по-прежнему актуальным: CURRSTATUS=99/51 и ACTSTATUS=1.
Также, в категорию актуальности можно отнести поля STARTDATE, ENDDATE, UPDATEDATE. Но, на данный момент (декабрь 2012 г.) значения этих полей не несут смысловой нагрузки.
Покажем на примере выбор актуальных и исторический записей. "Пермский край" был образован 01.12.2005 объединением "Пермской области" и "Коми-Пермяцкого АО". В базе ФИАС это отразилось следующим образом (см. табл. 1):
- Создана новая запись "Пермский край" (1-й столбец);
- Запись "Пермская область" (2-й столбец) сохранена, причем AOGUID обеих записей идентичен (для связи с дочерними объектами);
- Запись "Коми-Пермяцкий АО" (3-й столбец) также сохранена.
Таблица 1
Примечание | Актуальная запись | Пермская обл. | Коми-Пермяцкий АО |
AOID | c685f6ca-d7e1-4938-8b21-7c20035652d2 | 744e2599-d2bb-4364-9922-c13febb16e81 | 68824dc3-da0f-42d3-bd0b-1ceb91ff27bf |
AOGUID | 4f8b1a21-e4bb-422f-9087-d3cbf4bebc14 | 4f8b1a21-e4bb-422f-9087-d3cbf4bebc14 | e3d95b95-cc2d-440d-95c6-65577fae076e |
AOLEVEL | 1 | 1 | 1 |
PREVID | 744e2599-d2bb-4364-9922-c13febb16e81 | 68824dc3-da0f-42d3-bd0b-1ceb91ff27bf | |
NEXTID | c685f6ca-d7e1-4938-8b21-7c20035652d2 | 744e2599-d2bb-4364-9922-c13febb16e81 | |
ACTSTATUS | 1 | 0 | 1 |
OPERSTATUS | 1 | 1 | 1 |
CURRSTATUS | 0 | 1 | 51 |
LIVESTATUS | 1 | 0 | 0 |
UPDATEDATE | 2011-09-13 | 2011-09-13 | 2011-09-13 |
STARTDATE | 1900-01-01 | 1900-01-01 | 1900-01-01 |
ENDDATE | 2079-06-06 | 2079-06-06 | 2079-06-06 |
FORMALNAME | Пермский | Пермская | Коми-Пермяцкий |
OFFNAME | Пермский | Пермская | Коми-Пермяцкий |
SHORTNAME | край | обл | АО |
Значения полей:
- ACTSTATUS для Коми-Пермяцкого АО сохранен в значении "Актуальный";
- OPERSTATUS не изменился - ошибочно(?);
- CURRSTATUS правильный (0 - актуальный, 1 - исторический, 51 - переподчиненный);
- LIVESTATUS показывает единственную актуальную запись, но значения инвертированы (см. прим. 1).
Примечания:
- Все актуальные записи (CURRSTATUS = 0) имеют значение (LIVESTATUS = 1) и наоборот. Очевидно, что поведение LIVESTATUS не соответствует документации. Поле можно использовать для выбора актуальных записей, но осторожно до выяснения ситуации в будущем.
Исторические названия
Поля AOID, PREVID, NEXTID в совокупности составляют цепочку от современного к устаревшим наименованиям объекта. Хотя, если имеется два прямых предка (как в примере про "Пермский край"), то наследование невозможно отразить полностью однозначно.
// ToDo: построение полного списка исторический названий
Примечания:
- Наблюдение (в документации не разъяснено): при внесении изменений, предыдущая историческая запись №1 получает значение (CURRSTATUS = 1). Если вносится повторное изменение, то историческая запись №2 принимает значение (CURRSTATUS = 2). Таким образом, цепочка от современного названия к самому староми принимает вид: 0, ..., 3, 2, 1.