Пример работы парсера
Рассмотрим это на примере, в котором будем собирать информацию о том, кто в каком городе родился. При этом посмотрим последовательно на все этапы анализа текста. Для начала опишем поля факта. Факт можно представить себе как запись в таблице, а поля - как ее колонки. В данном случае нужны две колонки: одна для имени человека (назовем Person), другая — для места рождения (назовем Place). Сам факт назовем BornFact.
Файл facttypes.proto
import "base.proto";
import "facttypes_base.proto";
message BornFact: NFactType.TFact
{
required string Person = 1;
required string Place = 2;
}
Возьмем два простых предложения, в которых есть интересующая нас информация: Иван родился в Нижнем Новгороде
и Михаил родился в Петербурге
и напишем грамматику, которая может описать предложения такого типа:
Файл bornin.cxx
#encoding "utf-8"
Born -> Verb<kwtype=born>;
City -> Noun<kwtype=city>;
Person -> AnyWord<gram="имя">;
S -> Person interp(BornFact.Person) Born "в" City interp(BornFact.Place);
Правило Born -> Verb<kwtype=born>
описывает возможные предикаты, которые могут указывать на рождение, и ссылается на kw-type газеттира born
. Аналогичным образом, правило City -> Noun<kwtype=city>
описывает возможные названия городов и ссылается на kw-type city
. Правило Person -> AnyWord<gram="имя">
сработает на словах, у которых есть граммема имя
. Последнее правило собирает полную цепочку с предлогом в
. Корневой словарь газеттира при этом будет выглядеть следующим образом:
Файл dic.gzt
encoding "utf8";
import "base.proto";
import "articles_base.proto";
import "kwtypes_my.proto";
import "facttypes.proto";
TAuxDicArticle "РодилсяВ"
{
key = { "tomita:bornin.cxx" type=CUSTOM }
}
city "Нижний_Новгород"
{
key = "Нижний Новгород";
mainword = 2;
}
city "Санкт_Петербург"
{
key = "Санкт-Петербург" | "Питер" | "Петербург";
lemma = "Санкт-Петербург";
}
born "родиться"
{
key = "родиться"
}
born "появиться_на_свет"
{
key = "появиться на свет"
}
Статья РодилсяВ
ссылается на грамматику, находящуюся в файле bornin.cxx
. Статьи типа city
и born
перечисляют слова и словосочетания соответствующих типов, чтобы на них можно было ссылаться в грамматике при помощи ограничения kwtype=...
. Свойство mainword = 2
указывает, что в словосочетании Нижний Новгород
главным словом является Новгород
, а не первое слово, как было бы по умолчанию. Это важно, т.к. грамматические признаки главного слова приписываются всему словосочетанию. Санкт-Петербург может быть назван несколькими способами. Чтобы учесть и это, три варианта перечислены в поле key
. Для того, чтобы в поле BornFact.Place все записи про Санкт-Петербург выглядели одинаково, добавлено поле lemma=
, указывающее на тот вариант названия, который должен быть использован при нормализации.
kw-типы city
и born
объявлены в файле kwtypes_my.proto
. Все используемые kw-типы должны быть описаны таким образом. Некоторые из них (ссылка?) уже описаны во встроенном файле kwtypes_base.proto
.
Файл kwtypes_my.proto
import "base.proto";
import "articles_base.proto";
message born : TAuxDicArticle {}
message city : TAuxDicArticle {}
Конфигурационный файл для запуска парсера выглядит следующим образом:
Файл config.proto
encoding "utf8";
TTextMinerConfig {
Dictionary = "dic.gzt"; // корневой словарь газеттира
PrettyOutput = "debug.html"; // файл с отладочным выводом
Input = {
File = "test.txt"; // файл с анализируемым текстом
Type = dpl; // режим чтения "document per line" (каждая строка - отдельный документ)
}
Articles = [
{ Name = "РодилсяВ" } // Запустить статью корневого словаря "РодилсяВ"
]
Facts = [
{ Name = "BornFact" } // Сохранить факт "BornFact"
]
Output = {
File = "facts.txt"; // Записать факты в файл "facts.txt"
Format = text; // используя при этом простой текстовый формат
}
}
Файл test.txt
Иван родился в Нижнем Новгороде.
Михаил появился на свет в Петербурге.
Для запуска парсера достаточно указать в качестве аргумента программы tomitaparser.exe
имя конфигурационного файла config.proto
:
tomitaparser.exe config.proto
В результате своей работы парсер напечатает сообщения об успешной компиляции корневого словаря и грамматики, а также о времени начала и завершения обработки текста:
Compiling "dic.gzt" ... OK
Compiling bornin.cxx ... (10 unique symbols, 5 rules) OK
[25:10:12 13:35:05] - Start. (Processing files.)
[25:10:12 13:35:05] - End. (Processing files.)
В результате обработки будут сгенерированы два файла: facts.txt
и debug.html
. Первый файл (facts.txt
) содержит обработанный текст и выделенные из него факты. Простой текстовый формат удобен для проверки выделения фактов во время разработки и не предназначен для последующей автоматической обработки. Для автоматической обработки используйте формат Format=xml
. Второй файл (debug.html
) содержит более подробную отладочную информацию, включая морфологический разбор (отображается при наведении указателя мышки на слово) и цепочки слов, соответствующие статьям корневого словаря.
Файл facts.txt
Иван родился в Нижнем Новгороде .
BornFact
{
Person = иван
Place = Нижний Новгород
}
Михаил появился на свет в Петербурге .
BornFact
{
Person = михаил
Place = Санкт-петербург
}
Файл debug.html
Далее рассмотрим подробно работу парсера на этих двух предложениях. В приведенных ниже таблицах последовательно показаны этапы анализа текста, начиная с морфологического разбора, результатом которого являются леммы и грамматические признаки. Далее ищутся ключи из упомянутых в грамматике статей газеттира. В первом предложении это ключ «родиться» (kwtype="born"
) и ключ «Нижний Новгород» (kwtype="city"
). Поскольку kwtype="city"
используется в грамматике, то цепочка «Нижний Новгород» попадет к ней на вход в виде мультиворда, на котором сработает терминал Noun<kwtype="city">
. Аналогичным образом сработает и терминал Verb<kwtype="born">
на цепочке «появился на свет». Из терминалов, перечисленных в строке «терминалы», GLR-парсер соберет нетерминалы Person
, Born
и City
по правилам, описаным в файле bornin.cxx
. В правиле S -> Person interp(BornFact.Person) Born "в" City interp(BornFact.Place)
выполняется интерпретация, в ходе которой цепочки, сопоставленные нетерминалам Person
и City
, нормализуются и интерпретируются (записываются) в поля BornFact.Person
и BornFact.Place
факта BornFact
.
текст | Иван | родился | в | Нижнем | Новгороде |
леммы | иван | родиться | в | нижний | новгород |
грамматические признаки | S, persn, nom, sg, m, anim | V, praet, sg, indic, m, ipf, intr | PR | A, abl, sg, plen, m, n | S, geo, abl, sg, m, inan |
kw-type | born | city | |||
терминалы | AnyWord<gram="persn"> | Verb<kwtype="born"> | "в" | Noun<kwtype="city"> | |
нетерминалы | Person | Born | "в" | City | |
интерпретация (поля факта) | BornFact.Person | BornFact.Place |
текст | Иван | родился | в | Нижнем | Новгороде |
леммы | иван | родиться | в | нижний | новгород |
грамматические признаки | S, persn, nom, sg, m, anim | V, praet, sg, indic, m, ipf, intr | PR | A, abl, sg, plen, m, n | S, geo, abl, sg, m, inan |
kw-type | born | city | |||
терминалы | AnyWord<gram="persn"> | Verb<kwtype="born"> | "в" | Noun<kwtype="city"> | |
нетерминалы | Person | Born | "в" | City | |
интерпретация (поля факта) | BornFact.Person | BornFact.Place |
текст | Михаил | появился | на | свет | в | Петербурге |
леммы | Михаил | появиться | на | свет | в | Санкт-Петербург |
грамматические признкаи | S, persn, nom, sg, m, anim | V, praet, sg, indic, m, pf, intr | PR | S, nom, acc, sg, m, inan | PR | S, geo, abl, sg, m, inan |
kw-type | born | city | ||||
терминалы | AnyWord<gram="persn"> | Verb<kwtype="born"> | "в" | Noun<kwtype="city"> | ||
нетерминалы | Person | Born | "в" | City | ||
интерпретация (поля факта) | BornFact.Person | BornFact.Place |
текст | Михаил | появился | на | свет | в | Петербурге |
леммы | Михаил | появиться | на | свет | в | Санкт-Петербург |
грамматические признкаи | S, persn, nom, sg, m, anim | V, praet, sg, indic, m, pf, intr | PR | S, nom, acc, sg, m, inan | PR | S, geo, abl, sg, m, inan |
kw-type | born | city | ||||
терминалы | AnyWord<gram="persn"> | Verb<kwtype="born"> | "в" | Noun<kwtype="city"> | ||
нетерминалы | Person | Born | "в" | City | ||
интерпретация (поля факта) | BornFact.Person | BornFact.Place |