
В больших проектах, которые объединяют множество компонентов, нередко возникают проблемы унификации подходов и понимания связей между всеми сервисами. В результате долгое время у ИТ-команд существовал запрос на новую модель описания структуры данных и семантики приложения. Она появилась благодаря адаптации онтологии под нужны ИТ.
Меня зовут Алексей Гуляев. Я архитектор решений в команде VK Tech. В этой статье я расскажу об онтологии в ИТ, вариантах ее использования и нашем кейсе применения онтологического подхода для решения внутренней задачи.
Сначала о проблеме: об основных вызовах для разработчиков в контексте работы со сложной структурой приложений
Современные приложения, как правило, состоят из множества сервисов и компонентов — это повышает удобство администрирования и отказоустойчивость, а также упрощает масштабирование. Вместе с тем, это создает и некоторые трудности. Например, даже одинаковые сущности, используемые в разных компонентах, могут иметь разные названия и неочевидные взаимосвязи: допустим, не всегда понятно, «Клиент» из CRM, это тот же «Пользователь» из Auth или нет? И чем больше компонентов задействовано в приложении, тем выше риск возникновения таких недопониманий и связанных с этим проблем.

Чтобы избавиться от подобных сложностей, с которыми сталкиваются многие разработчики, важно сформировать явное представление о терминах, связях, структуре данных и семантике приложения.
Для этого можно задействовать принципы онтологии.
Чем могут быть полезны принципы онтологии в ИТ
Классически под «онтологией» понимают систематическое представление знаний определенной области в виде понятий, отношений между ними и правил вывода. Но этот термин вполне можно адаптировать под ИТ. Так, в разработке онтологию можно рассматривать как формальную спецификацию понятий и связей между ними, используемую для описания структуры данных и семантики приложений. Если проще — в ИТ онтология помогает превратить бизнес-логику в машиночитаемый код.
Чтобы понять, как это работает, рассмотрим несколько примеров.
Аналогия 1: Справочник++
Принципы онтологии можно применять в справочниках, причем не для простого описания терминов, а для формального описания предметной области, которое позволит преобразовать бизнес-правила в код.
Например, для решения бизнес-задачи нам важно, чтобы выполнялось три правила:
все клиенты — пользователи;
клиент должен иметь хотя бы один заказ;
заказ всегда содержит хотя бы один товар.
В онтологии в синтаксисте TURTLE эти правила можно описать всего несколькими строками кода.
Примечание: TURTLE (Terse RDF Triple Language) — лаконичный синтаксис для представления RDF-данных (Resource Description Framework), разработанный специально для удобства написания и чтения RDF-триплетов вручную. Формат широко используется в проектах, ориентированных на разработку онтологий и семантических сетей.
:Client a owl:Class ;
rdfs:label "Клиент" ;
rdfs:subClassOf :User ; # Все клиенты - пользователи
# Клиент ДОЛЖЕН иметь хотя бы один заказ
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty :hasOrder ;
owl:someValuesFrom :Order ;
owl:minCardinality "1"^^xsd:nonNegativeInteger
] .
:Order a owl:Class ;
rdfs:label "Заказ" ;
# Заказ ДОЛЖЕН содержать хотя бы один товар
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty :containsItem ;
owl:someValuesFrom :Product ;
owl:minCardinality "1"^^xsd:nonNegativeInteger
] .
Здесь видно, что:
класс — «Client» является подклассом «User»;
есть дополнительное ограничение: — клиент должен быть связан хотя бы с одним объектом (owl:minCardinality "1"^^xsd:nonNegativeInteger).
Примечание: С заказом аналогично — должна быть связь минимум с одним товаром.
Таким образом, онтология позволяет выстроить не просто словарь, а исполняемую спецификацию, которая будет понятна и компьютеру, и человеку.
Аналогия 2: ООП на стероидах
Онтология позволяет описывать классы, экземпляры классов и их свойства.
Помимо этого, она позволяет определять и более сложные связи, например, принадлежность к конкретной категории.
Разберем на примере. Допустим, у нас есть три индивида:
Иван;
Марина;
Петр.
Изначально задана связь типа «Родитель»: Иван — родитель Марины, а Марина — родитель Петра.

Соответственно, при построении онтологии в синтаксисе мы указываем, что:
никто не может быть своим собственным родителем;
если А родитель В, то В не может быть родителем А.
:hasParent a owl:ObjectProperty ;
rdfs:label "имеет родителя" ;
rdfs:domain :Person ;
rdfs:range :Person ;
owl:irreflexive true ; # Никто не может быть своим собственным родителем
owl:asymmetric true . # Если А родитель В, то В не может быть родителем А
Сюда же мы можем добавить и дополнительную связь. Например, «Предок». Причем можно задействовать свойство транзитивности, которое позволяет автоматически распространять правило на все последующие сущности.
:hasAncestor a owl:ObjectProperty ;
rdfs:label "имеет предка" ;
rdfs:domain :Person ;
rdfs:range :Person ;
owl:transitive true ; # Ключевое свойство: если А предок В, а В предок С, то А предок С
owl:irreflexive true . # Никто не может быть своим собственным предком
То есть связь «Предок» (Иван предок Петра) будет автоматически построена онтологической моделью если в модели будет указано что Иван предок Марины, а Марина предок Петра.

Аналогия 3: Схема БД++
Реляционный подход позволяет описать все сущности и даже связи между ними, что успешно используется в реляционных базах данных.

Вместе с тем, в подобной структуре разбираться с классами, их наследованием и другими связями не всегда удобно.
При построении графа онтологии это становится значительно проще и нагляднее. Причем в таком случае даже связи («один к одному», «один ко многим», «многие ко многим») будут нести дополнительную нагрузку в части описания структуры данных и приложения.

Одним из важных преимуществ онтологии в контексте БД является и механизм наследования сабклассов. Рассмотрим, как именно это работает, на примере DDL (Data Definition Language) — части SQL, предназначенной для управления структурой данных в БД.
Допустим, у нас есть 3 таблицы в DDL. Разобраться в такой структуре можно, но не всегда просто без глубокого погружения.
CREATE TABLE users (
id SERIAL PRIMARY KEY
);
CREATE TABLE user_roles (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
role_type VARCHAR(20) NOT NULL CHECK (role_type IN ('customer', 'employee', 'supplier')),
UNIQUE(user_id, role_type)
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER REFERENCES users(id),
assigned_employee_id INTEGER REFERENCES users(id)
);
В онтологии всё значительно прозрачнее и очевиднее. Так:
добавляем класс "User" — пользователь;
объявляем класс "Customer", который является наследником пользователя;
добавляем ограничение, согласно которому пользователь становится клиентом только в том случае, если сделал хотя бы один заказ.
:User rdf:type owl:Class ;
rdfs:label "Пользователь" .
:Customer rdf:type owl:Class ;
rdfs:subClassOf :User ,
[ rdf:type owl:Restriction ;
owl:onProperty :createdOrder ;
owl:someValuesFrom :Order ] ;
rdfs:label "Клиент" .
:createdOrder rdf:type owl:ObjectProperty ;
rdfs:domain :Customer ;
rdfs:range :Order ;
rdfs:label "Создал заказ" .
Основное отличие SQL-кода от онтологии в данном случае заключается в том, что код SQL указывает то, как именно данные сохраняются, а онтология — описывает характер данных и их связи.
Ключевые элементы
Таким образом, онтология базируется на нескольких ключевых сущностях, к которым относят:
классы (Concepts) (например, "User");
экземпляры (индивиды) (например, "Ivanov_Ivan");
-
свойства:
атрибуты (Data Properties), к которым относятся простые значения: строки, числа и другие (например, e-mail);
отношения (Object Properties), которые описывают связь одного индивида с другим (например, hasOrder);
отношения между классами.

Когда онтологический подход может быть полезен
Применение онтологического подхода упрощает решение нескольких важных технических и бизнесовых задач.
Борьба с «Вавилонской Башней» и упрощение интеграции. Онтологический подход позволяет упорядочить и сформировать понятную структуру данных и всех используемых сервисов. Благодаря этому не только легче понимать всё, что происходит в проекте, но и проще интегрировать новые компоненты, налаживая с ними требуемые связи.
Валидация. Онтология и онтологический подход помогают в валидации, задавая чёткую структуру данных и строгие правила их взаимодействия. Онтология определяет классы объектов, их свойства и связи, а также устанавливает обязательные условия и ограничения. Специальные инструменты, называемые резонерами, автоматически проверяют соблюдение этих правил, исключают противоречия и ошибки, обеспечивая целостность и правильность данных.
Шаг к «умным» данным. Онтология добавляет к данным смысловые связи и контекст. Это позволяет компьютерам лучше понимать содержание и применять более прогрессивные интеллектуальные методы анализа и автоматизацию.
Форматы и инструменты
Работу с онтологией можно упрощенно выстроить на использовании нескольких инструментов и технологий.
Для представления классически используется RDF (Resource Description Framework) — универсальный стандарт представления данных, применяемый для работы с онтологиями. Он используется для описания ресурсов и их свойств в форме простых утверждений («триплетов»), состоящих из трех элементов: субъект, предикат и объект.
В качестве основного языка применяется OWL (Web Ontology Language) — язык разметки для построения и описания онтологий, который разработан специально для формализации знаний и стандартов их представления в рамках Семантического Веба (Semantic Web).
При этом хранить онтологию можно любым удобным способом. Например, для этого подойдут:
триплсторы (Triplestores) — например, GraphDB, Stardog, которые созданы специально для RDF/OWL и умеют в логический вывод;
Apache Jena, которая позволяет выполнять SPARQL запросы по протоколу HTTP, поэтому дает возможность балансировать нагрузку стандартными средствами (nginx);
любые базы данных, в том числе PostgreSQL.

Пример применения онтологии для решения задачи: построение портала данных бизнеса
Теперь перейдем от теории к практике. Рассмотрим прикладную задачу, ради которой мы изначально и начали изучать онтологический подход.
Так, у нас был проект, в рамках которого нужно было организовать хранение и публикацию данных показателей в рамках отчетных кампаний, где данные показателя хранятся в кубах. При этом модель данных бизнеса формулируется на стороне и поступает к нам в виде набора правил, по которым осуществляется хранение, публикация и версионирование данных.
Упрощенная модель, которую мы использовали на этапе MVP, имела примерно следующий вид:

Изначально мы пытались решить поставленную задачу с помощью реляционного подхода, но столкнулись с проблемами, которые для нас оказались критическими. Среди них:
Много промежуточных таблиц для связей M:M (many to many), соответственно, было много запросов с обилием вложенных JOIN’ов.
Для работы каждому участнику требуется погружаться как в предметную область, так и в схему данных, что было проблематично из-за сложности самой реализации.
Путь от изменений модели данных на стороне бизнеса до реализации модели в схеме БД стоил очень дорого, поскольку требовалось вносить много изменений, пересобирать миграции и выполнять еще большой пул смежных задач.
Для поставки правил формирования отчетности из внешнего источника нам фактически пришлось придумать свой формат EMBD с поддержкой версионности, что обычно просто избыточно.
Именно поэтому мы перешли к онтологии и применили гибридный подход, при котором:
Онтология для Портала Данных Бизнеса в Apache Jena представлена в виде внешнего справочника — артефакта, поставляемого в виде файла формата turtle, который становится контрактом между бизнесом и разработкой.
Значения куба хранятся отдельно в Postgres, что позволяет не перегружать онтологию.

Благодаря такой реализации мы решили сразу несколько задач:
развязали сложную предметную модель и данные;
получили возможность использовать хорошо документированный и известный синтаксис EMBD, а не самописный «велосипед»;
значительно упростили создание редактора;
получили возможность применять нейросети для решения различных бизнес-задач на основе онтологии.
В результате у нас получился граф онтологии, который упрощенно (его часть) выглядит примерно следующим образом:

И для работы с таким графом онтологии (напоминаю, что выше показана только его часть) можно применять довольно простые запросы. Например:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX emdb: <http://odb.b2gcomm.taxmon.ru/onto/1.0/emdb.owl#>
SELECT
?cp
?Code
?DisplayName
?ProvisionTerms
WHERE {
emdb:1_I_F164272 emdb:r_I_2 CP ?cp .
?cp emdb:r_CP_2_DictCPV ?cpv .
?cp emdb:ProvisionTerms ?ProvisionTerms .
?cpv emdb:Code ?Code .
?cpv emdb:DisplayName ?DisplayName .
}
ORDER BY ?Code
Этот запрос мы отправляем постом в Apache Jena, после чего она дает ответ из запрошенной онтологической модели.
Библиотеки для нашего стека
Мы оценили эффективность и удобство онтологического подхода. Поэтому в перспективе планируем всё активнее применять его в своих процессах. Так, мы уже определили для себя оптимальный набор библиотек под разные решения в свой стек.
Python. Для Python мы выбрали RDFLib — библиотеку для языка программирования Python, предназначенную для работы с ресурсными описаниями формата RDF согласно спецификациям W3C. Она позволяет создавать, читать, изменять и сохранять RDF-графики и файлы, поддерживая множество форматов сериализации RDF (например, RDF/XML, N-Triples, JSON-LD).
Golang. В Golang можно задействовать базовый RDF — стандартный способ представления данных в виде набора троек («субъект-предикат-объект»), широко применяемый в семантическом вебе для описания ресурсов и связей между ними. Помимо этого, для работы с онтологией можно применить JSON-GOLD (Graph Object Linked Data) — расширение стандарта JSON, которое объединяет преимущества формата JSON с возможностями семантического веба и связывания данных RDF (Resource Description Framework).
PostgreSQL. Для работы с данными PostgreSQL подойдет JSONB, который представляет собой эффективный механизм для хранения и обработки данных в формате JSON. Однако в контексте работы с онтологиями этот тип данных приобретает особое значение, поскольку он позволяет хранить и манипулировать данными в полуструктурированном формате, идеально подходящем для задач моделирования знаний и семантического анализа. Также можно задействовать триплет-таблицы — например, делать JOIN'ы по subject и object, а для обхода графа использовать рекурсивные CTE (WITH RECURSIVE).
Apache Jena. В случае Apache Jena всё довольно просто — файлы онтологий загружаются в Jena и выполняются запросы SPARQL по HTTP.
Что в итоге
Онтологический подход — вполне эффективное решение, которое можно применять во многих сценариях. Так, его можно рассмотреть, если у вас в проекте:
сложная предметная область со множеством связей;
часто меняющиеся требования к данным;
проблемы интеграции множества источников;
нужен более «умный» поиск или важна гибкость модели;
требуется, чтобы данные «понимались» приложением на более глубоком уровне.
Но есть и ограничения. Например, онтология — не лучший вариант, когда:
модель данных очень проста (CRUD над парой таблиц);
критична сверхвысокая производительность;
команда абсолютно не готова к восприятию новой парадигмы.
При этом, мы уже начинаем применять подход для решения части наших задач. О том, что из этого получится — обязательно расскажем в одной из следующих статей.
А вы пробовали онтологию в своих проектах? Делитесь опытом.