Поддержка макросов
Примечание: В этом разделе рассматриваются продвинутые функциональные возможности, полезные при написании больших и сложно организованных правил. Его можно пропустить и перейти к следующим разделам без ущерба для понимания. Макросы стоит использовать, когда в коде многократно повторяется одно и то же (или почти одно и то же) правило или поисковый запрос. Чтобы не писать идентичные правила, можно объявить макрос, который содержит повторяющиеся фрагменты, и вызывать его при необходимости. Использование макросов позволяет менять код только в одном месте: сделанные в макросе изменения затронут и другие правила, где используется этот макрос.
Синтаксис объявления макроса
Объявление макроса начинается с ключевого слова macro:, после идет имя макроса и взятый в скобки список аргументов, перечисленных через запятую. Если у макроса нет аргументов, в скобках можно ничего не указывать. Тело макроса заключается в фигурные скобки. Имя макроса задается пользователем, оно может содержать любые число-буквенные символы и знак нижнего подчеркивания (специальные символы и пунктуация, например, знак процента, коммерческое at, точка, запятая, пробел, скобки и т.д. недопустимы).
Если макрос содержит PDL-запрос, допускается упрощенное объявление макроса:
Макросы объявляются либо наверху правила (глобальные макросы, которые можно вызвать в любом месте файла), либо внутри правила перед разделом запроса (локальные макросы, которые можно вызывать как внутри правил, где они были объявлены, так и в их дочерних правилах).
Объявление макроса должно предшествовать вызову макроса.
Синтаксис вызова макроса
Вызов макроса начинается словом macro, за ним следует имя макроса и (опционально) взятый в скобки список аргументов, перечисленных через запятую.
Обратите внимание, что макросы сокращают не время выполнения правил, а время их написания. Они помогают избежать повторения одинаковых фрагментов правил, что облегчает чтение.
Пример. Найти названия компаний и их аббревиатуры
Рассмотрим правила на Изображении 1, которые извлекают названия компаний.

Фрагмент правила
rule: full_company_names
// например, Ульяновский авиастроительный завод "Авиастар СП", Батыр Мальсагов, владелец группы компаний "Акрополь"
{
query: {phrase(0, char(quote), {phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
rule_filter: business_context
// оставляем только контексты, в которых может встретиться название компании (например, после слова "компания")
{
query: phrase(0, orn(госкомпания, директор, завод, компания, предприятие, работник, фабрика), $comp_whole)
result: Компания = $comp_whole: comp
}
}
rule: company_after_type
// например, ЗА0 "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char (quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
result: Компания = $comp_whole:comp
}
Первое правило («full_company_names») извлекает названия компаний в кавычках, после которых идет существительное или прилагательное в смешанном, заглавном или верхнем регистре, а затем от 1 до 3 повторяющихся существительных или прилагательных. Например, «Авиатор СП», «Курорты Северного Кавказа». Вложенное фильтрующее правило необходимо, чтобы находить название компании только в правильных контекстах, например, после слов «компания», «директор», «завод», «предприятие».
Второе правило ищет названия компаний после типа компании (например, ЗАО «Гражданские самолеты Сухого»).
На следующем этапе можно извлечь аббревиатуры компании, часто следующие за названием. Лучше делать это отдельным правилом, чтобы не перегружать правило, извлекающее названия.
Как показано на Изображении 2, правило, извлекающее аббревиатуры, нужно добавить как в правило «full_company_names», так и в правило «company_after_type».

Фрагмент правила
rule: full_company_names
// например, Ульяновский авиастроительный завод "Авиастар СП", Батыр Мальсагов, владелец группы компаний "Акрополь"
{
query: {phrase(0, char(quote), {phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
rule_filter: business_context
// оставляем только контексты, в которых может встретиться название компании (например, после слова "компания")
{
query: phrase(0, orn(госкомпания, директор, завод, компания, предприятие, работник, фабрика), $comp_whole)
result: Компания = $comp_whole:comp
rule: abbreviations
// Госкомпания "Курорты Северного Кавказа" /КСК/
{
query: {phrase($comp_whole, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
result: Компания = $comp_full
attribute: Аббревиатура = $comp_full:abbr
}
}
}
rule: company_after_type
// например, ЗА0 "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char (quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
result: Компания = $comp_whole:comp
rule: abbreviations
// Госкомпания "Курорты Северного Кавказа" /КСК/
{
query: {phrase($comp_whole, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
result: Компания = $comp_full
attribute: Аббревиатура = $comp_full:abbr
}
}
Уже на этом этапе правила выглядят громоздко и сложно, а при добавлении новых правил, после которых нужно будет искать аббревиатуры, правило увеличится еще больше.
Избавиться от повторяющихся фрагментов поможет макрос. На Изображении 3 показано, как объявить макрос с PDL-запросом.

Фрагмент правила
macro: abbrev_query()
{
query: {phrase($comp, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
}
На Изображении 3 показно стандартное объявление макроса. Так как макрос содержит только PDL-запрос, можно использовать упрощенный способ объявления макроса (см. Изображение 4).

Фрагмент правила
macro: abbrev_query() = {phrase($comp, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
После объявления макроса его можно вызвать в любом месте правила.
На Изображении 5 показано, как это можно сделать.

Фрагмент правила
macro: abbrev_query()
{
{phrase($comp, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
}
rule: full_company_names
// например, Ульяновский авиастроительный завод "Авиастар СП", Батыр Мальсагов, владелец группы компаний "Акрополь"
{
query: {phrase(0, char(quote), {phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
rule_filter: business context
// оставляем только контексты, в которых может встретиться название компании (например, после слова "компания")
{
query: phrase(0, orn(госкомпания, директор, завод, компания, предприятие, работник, фабрика), $comp_whole)
result: Компания = $comp_whole:comp
rule: abbreviations
// Госкомпания "Курорты Северного Кавказа" /КСК/
{
query: macro(abbrev_query)
result: Компания = $comp_full
attribute: Аббревиатура = $comp_full:abbr
}
}
}
rule: company_after_type
// например, ЗАО "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char (quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
result: Компания = $comp_whole:comp
rule: abbreviations
// Госкомпания "Курорты Северного Кавказа" /КСК/
{
query: macro(abbrev_query)
result: Компания = $comp_full
attribute: Аббревиатура = $comp_full:abbr
}
}
После удаления повторяющихся запросов правила легче читать. Можно еще больше их упростить, объявив макрос с XPDL-правилом, как показано на Изображении 6.

Фрагмент правила
macro: abbreviations()
{
rule: abbreviations
// Госкомпания "Курорты Северного Кавказа" /КСК/
{
query: {phrase($comp, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
result: Компания = $comp_full
attribute: Аббревиатура = $comp_full:abbr
}
}
rule: full_company_names
// например, Ульяновский авиастроительный завод "Авиастар СП", Батыр Мальсагов, владелец группы компаний "Акрополь"
{
query: {phrase(0, char(quote), {phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
rule_filter: business_context
// оставляем только контексты, в которых может встретиться название компании (например, после слова "компания")
{
query: phrase(0, orn(госкомпания, директор, завод, компания, предприятие, работник, фабрика), $comp_whole)
result: Компания = $comp_whole:comp
macro(abbreviations)
}
}
rule: company_after_type
// например, ЗАО "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char(quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
result: Компания = $comp_whole: comp
macro(abbreviations)
}
Как передавать параметры в макрос
Макросы с аргументами функциональнее макросов без аргументов, так как могут заменять похожие, но не идентичные правила и запросы.
Рассмотрим немного измененное правило для извлечения названий компаний на Изображении 7.

Фрагмент правила
rule: company_after type
// например, ЗА0 "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char(quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
rule: abbreviations
{
query: {phrase($comp, phrase(0, "(" or "/", {length(2, 4, case(upper))}:abbr, ")" or "/"))}:comp_full
result: Компания = $comp_full:comp
attribute: Аббревиатура = $comp_full:abbr
}
rule: location
{
query: {phrase($comp, phrase(0, "(" or "/", {knownword(GeoAdministrative)}:location, ")" or "/"))}:comp_full
result: Компания = $comp_full:comp
attribute: Расположение = $comp_full:location
}
}
Эти правила извлекают не только названия компаний, но и сопутствующую информацию, например, расположение компании, которое часто указывается в скобках после названия («ОАО «Аэропорт Кольцово» (Екатеринбург)»).
Расположение и аббревиатура выводятся в колонки «Расположение» и «Аббревиатура» соответственно.
Правило отрабатывает на следующем тексте:

Результаты работы правила показаны на Изображении 8.

Обратите внимание, что правила «abbreviation» и «location» отличаются только именем правила (они выделены красным на изображении выше), поисковой частью правила, которая находит информацию в скобках (выделено синим), и названием атрибутов (выделено зеленым). Эти части можно сделать параметрами макроса. При вызове макроса им будут присвоены разные значения. Измененный вариант правила, содержащего макрос с параметрами, представлен на Изображении 9.
Чтобы определить макрос, принимающий аргументы, при его объявлении после имени нужно перечислить параметры в скобках. Параметрами макроса могут быть имя правила, запрос, подзапрос, значение достоверности, результат, имя атрибута или значение.
При вызове макроса нужно перечислить в скобках все его аргументы. Количество аргументов, указанных при вызове макроса должно совпадать с количеством параметров, указанных при объявлении макроса. При выполнении правила каждый параметр в теле макроса заменяется значением соответствующего аргумента.

Фрагмент правила
macro: additional_info(rule_name, info_in_bracket, attribute_name)
{
rule: rule_name
{
query: {phrase($comp_phrase(0, "(" or "/", info_ in_bracket, ")" or "/"))}:comp_full
result: Компания = $comp_full:comp
attribute: attribute name = $comp_full:info
}
}
rule: company_after type
// например, ЗА0 "Гражданские самолеты Сухого"
{
query: {phrase(0, orn(ooo, пао, зао, оао), char(quote),
{phrase(0, case(mixed_title upper, lemma(noun|adjective)), repeat(1, 3, lemma(noun|adjective)))}:comp, char(quote))}:comp_whole
macro(additional_info, abbreviation, {length(2, 4, case(upper))}:info, Аббревиатура)
macro(additional_info, location, {knownword GeoAdministrative }:info, Расположение)
}
На Изображении 10 подробно объясняется выполнение макроса.
