Ещё один язык

О том, почему мы придумали еще один язык

(примерное время чтения 6 минут)

Почему?

После вступления в "болонский процесс" рядовому заведующему кафедрой пришлось отказаться от содержательной педагогической и научной работы в пользу бумажно-таблично-бюрократической. Даже поверхностный взгляд показывает, что содержание этой новой работы состоит в генерации из малого количества первичных данных большого количества плохо-организованных вторичных данных, из которых потом с трудом приходится извлекать информацию. Первичной содержательной информации не так много - гораздо больше вторичных представлений информации (вот маленький пример). Спасение в том, чтобы: а) автоматически генерировать вторичные представления, и б) автоматически извлекать информацию из чужих вторичных представлений, которые нужны для составления своих.

Попытки решить данный вопрос с помощью так называемых информационных систем только усугубляют ситуацию; общая причина в том, что принципы построения т.н. "информационных систем" не позволяют (на методологическом уровне) синхронизировать размещенную в них информацию с реальностью. Поэтому повсеместной является вот такая ситуация: "ексель поверх 1С". Вот небольшое объяснение причин такого положения вещей.

Исключительно с целью спасения "утопающих" была разработана технология и инструментарий для того, чтобы переиспользовать единожды созданные данные без необходимости их повторного ввода. Естественно, что эта технология имеет под собой некоторые методологические основания (которые пока для краткости опустим). Технология получила развитие в рамках некоммерческого проекта TRaC, реализуемого группой artel ("напрасный труд"). В основе этой технологии лежит идея приведения данных (содержащих содержательно ценную информацию) к некоторому универсальном представлению. В качестве такого представления выбрана концепция RDF (Resource Description Framework). Она позволяет представить большую часть сущностей и отношений реального мира в машиночитаемой форме. И эта концепция принята в качестве стандарта консорциумом "всемирной паутины" W3C (стандарт "Концепции и абстрактный синтаксис").

Как?

Как можно заметить абсолютное большинство "оцифрованных" данных можно представить в виде иерархических структур ("деревьев"). Любая таблица или список могут быть представлены в виде "дерева" (например, такая может быть представлена вот так). Документы электронного вида типа вородовских (.docx) изначально хранятся в виде "деревьев-графов" (вот такой вордовский документ на самом деле хранится вот так). Не говоря уже о реляционных базах данных (но о них в последнюю очередь). Таким образом, задача получения универсального RDF-представления сводится к трансформации одного "дерева" в другое (носителем RDF также является иерархическая структура "дерево"). Подобная трансформация легко выполняется средствами языка XQuery, который также как и RDF принят в качестве стандарта W3C. На этом можно было бы остановиться - принять XQuery в качестве такого языка, но есть "но"...

Но... (которых несколько)

  • Первое "но" (которое не главное). В силу того, что сама концепция RDF и принятые стандарты ее реализации обладают довольно компактными семантикой и структурой, то "XQuery как есть" является избыточным. Задача трансформации решается ограниченным набором конструкций, написанных на этом языке. Таким образом, для реализации задачи нам достаточно подмножества языка "XQuery".
  • Второе "но" (которое существенно важнее). По-настоящему "сильная" трансформация требует связывания сущностей, описанных в одном "дереве", с сущностями другого "дерева". В реляционных базах данных эта задача решается с помощью индексов (примерно вот так). Эти идентификаторы-индексы являются локальными. Поэтому переиспользование информации из реляционных баз требует знания внутренней схемы отношений (немного об этом см. примечание), то есть на практике невозможно даже в рамках одной организации. В концепции RDF эта задача (связвания) решается с помощью глобальных идентификаторов - так называемых URI. URI для вновь объявляемой сущности можно без проблем сгенерировать, например, средствами XQuery. Однако для того, чтобы сослаться на уже существующую сущность (в терминологии RDF - ресурс), этот URI надо как-то узнать - получить извне. Для этого надо отправить запрос к тому "дереву", в котором искомая сущность появилась и "обрела" свой URI. В рамках концепции RDF запросы к данным осуществляются средствами языка SPARQL. Значит средства этого языка целесообразно интегрировать в механизм трансформации "любых деревьев" в "RDF-деревья".

Попытки решения задачи обсуждаемой здесь - создания языка для описания трансформаторов - предпринимались, и даже были реализованы в продуктах таких авторитетных компаний как Oracle. Но эти решения не дали желаемого результата. По мнению авторов-разработчиков этих решений (см. раздел "Lessons Learned") именно в силу указанных выше "но". Причиной этого, как можно судить по эволюции предлагавшихся решений, явился выбранный дедуктивный метод поиска - от высоких абстракций к частным конструкциям. В результате из поля зрения выпадали существенные аспекты действительности.
"Мы стоим на плечах великанов". Поэтому и велики :). В реализации нашей задумки мы шли параллельным, но встречным путем - непопулярным в научных кругах - индуктивным. Каждый этап нашей технологии был шагом в решении более общего класса задач, который мы внедряли и опробовали (пара слов о примерах реализации здесь).

Собственно язык и наша самонадеянность

Название языка в англоязычной аббревиатуре эволюционно сложилось такое: CCCR - язык конструирования контекстно связанных рекурсивных вычислений (context-compute-construct-recursive), как сокращенное указание на основные типы конструкций языка и принцип (рекурсивный) их организации.
Сам язык появился в результате обобщения решений, которые мы последовательно получили при создании технологии и средств трансформации "простых деревьев" в "RDF-деревья". На этом языке можно писать инструкции для трансформации "произвольных деревьев" в их RDF-представления с целью последующего использования в качестве источника данных. Для извлечения информации из RDF-представлений нет необходимости знать структуру данных, т.к. сущности связаны глобальными идентификаторами, а само представление информации имеет универсальную конструкцию "субъект-предикат-объект". Средством извлечения служит язык SPARQL. Стоит иметь в виду, что в концепции RDF сущностями, кроме описываемых объектов выступают также и свойства, и таксоны, и онтологии, которые также получают глобальное обозначение и возможность универсальной интерпретации.

Пример. Вот из такой эксель-таблицы (она же в виде дерева) с помощью вот такой инструкции можно получить вот такое RDF-представление. Читатель может заметить, что сущность "учебный класс" с глобальным идентификатором https://semantics.lipers24.ru/ресурсы/учебныеКлассы#2b55cc04-73a3-4045-8dde-c662800ea102 через свойство https://semantics.lipers24.ru/schema/учебныйПлан связана (связан) с сущностью "учебный план" https://semantics.lipers24.ru/ресурсы/учебныеПланы#2022-ДО-базовый. Реестр учебных планов школы ранее из такой таблицы с помощью такой схемы был преобразован в такое RDF-представление и загружен в RDF-базу. Именно из этой базы с помощью такого запроса извлекаются идентификаторы учебных планов, и конкретный учебный план на основе набора признаков сопоставляется конкретном учебному классу.

Коротко грамматика языка описана здесь. Носителем текстов на нашем языке является json, который выбран за иерархическую структуру, приличную человекочитаемость и большую популярность.

В алфавите языка мы насчитали 20 символов:

  • 13 слов, отражающих первичные конструкции;
  • 4 скобки (2 фигурные и 2 квадратные);
  • 3 разделителя: двойные кавычки, двоеточие, запятая.

В грамматике языка есть несколько "магических" конструкций, которые требуют отдельного пояснения. Мы насчитали три:

  • ВнутреннийЗапрос - применяется к обработке контекста - это собственно обрабатываемое "дерево", и использует средства языка XQuery;
  • ВнешнийЗапрос - использует средства языка SPARQL для извлечения данных из внешней RDF-базы (в принципе из любой, к котрой есть доступ);
  • @СписокУзлов - часть контекста, которая содержит набор узлов для итеративной обработки в соответствующей конструкции схемы.
    Остальное, надеемся, будет более менее интуитивно понятно.

Примечания

  1. В практике нашей работы нам неоднократно (вообще говоря, постоянно) приходилось сталкиваться с ситуацией, когда схема отношений в реляционной базе данных либо утеряна (разработчик ушел из организации), либо не задокументирована поставщиком базы данных. Поэтому многие базы "умирают", т.к. их невозможно поддерживать. Такие технологии как ORM в современных фреймворках отчасти помогают решить эту проблему. Но лишь отчасти.
  2. Некоторые типичные примеры реализации (в открытом доступе):
    • сведения о педагогах школы - генерируются "налету" из xlsx-файла с кадровым составом, хранящегося в корпоративном "облаке" организации (школы), избавляя ответственного завуча от рутинных операций по переносу обновленных данных и размещению их на сайте;
    • автоматическая генерация рабочих программ дисциплин - масштабный свервис-генератор РПД и аннотаций дисциплин из первичных документов преподавателей, находящихся в их облачных хранилищах; генератор на основе шаблона автоматически собирает все формальные реквизиты рабочей программы (включая, компетенции, часы, номера и даты протоколов и т.п.); трудоемкость первичного ввода содеражательной информации преподавателями близка к нулю, т.к. сводится к размещению вородовского файла в нужной папке.
    • кадровая база кафедры КИК МИСИС - данные хранятся распределенно в "облаках" преподавателей вот в таких табличках; сервис генерирует CV преподавателей для публикации на сайте университета, но также и генерирует вторичные представления ("отчеты для деканата") вот, например, такое, а также (и это главное) позволяет создавать произвольные запросы (на языке SPARQL) - вот, например, такие (для запуска запроса надо нажать на черный треугольничек в углу окна с текстом запроса).