Сегодня я хотел бы поговорить об онтологии и сделать это так. Мы возьмём учебный пример - онтологию для пиццерии (Pizza Shop) - и на основе этого примера разберём основные термины, ключевые элементы онтологии и обсудим, чем этот подход отличается от привычных способов моделирования.

Это не руководство по онтологии и не инструкция к визуальному редактору Protege, в котором сделан пример - это набор первых впечатлений человека, который решил разобраться в этой теме.

Что такое онтология?

С философской точки зрения онтология - это описание того, что существует. Философов при этом зачастую интересуют некие аспекты самого существования. Например, сколько частиц можно оторвать от стола, чтобы он всё ещё оставался столом, и другие сложные вопросы мироздания.

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

В нашем примере с пиццерией всё выглядит так: есть пицца, есть её основа/тесто, есть разные топпинги и правила, какие топпинги должны быть у какой пиццы. Мы можем сказать, что одна пицца острая, а другая - вегетарианская. Дальше появляются люди, которые эту пиццу пекут, и те, кто её покупает. В онтологии также описаны бизнес-правила - например, правила для применения скидок.

То есть, по сути, онтология - это модель бизнеса, которая описывает объекты и участников, а также их взаимодействие.

Для любопытных: Небольшое введение в онтологию (плейлист)

Pizza Tutorial

Когда пытаешься разобраться с новой темой, всегда полезно иметь наглядный пример. Здесь мы возьмём Pizza Tutorial, созданный Michael DeBellis как руководство к Protege - визуальному редактору для работы с онтологиями. Нас же больше интересует конечный результат: сама онтология в виде OWL-файла, который можно скачать здесь.

? OWL - это Web Ontology Language (буквы переставлены, чтобы получилось слово "сова")

Я повторил все шаги, описанные в Pizza Tutorial, и воссоздал этот OWL-файл (что и вам рекомендую сделать). Но формат этой статьи не предполагает, что мы будем детально разбирать весь процесс. Давайте лучше посмотрим на результат - на то, как готовая онтология выглядит в редакторе. Что мы видим?

Иерархия классов - ну это, наверное, ожидаемо.

иерархия классов
иерархия классов

Свойства, которых выделяется два типа: object properties и data properties.
object properties задают связи между объектами;
data properties связывают объект с данными заданного типа, например числом или строкой.

свойства
свойства

Обратите внимание, что свойства не показываются внутри классов. Это связано с тем, что в онтологии свойства считаются глобальными: они не принадлежат одному классу, а могут использоваться в разных местах.

экземпляры объектов тожe присутствуют - обычно моделирование ограничивается только классами.

экземпляры объектов
экземпляры объектов

Reasoner

Теперь мы подходим к ключевому моменту. Есть инструмент, который называется Reasoner. Без него онтология является схемой - формальным описанием понятий и связей. Reasoner работает с этой схемой: он анализирует её структуру, проверяет логическую согласованность и делает выводы на основе заданных описаний.

reasoner
reasoner

На этой картинке я собираюсь запустить Reasoner под названием Pellet - видно, что есть ещё два доступных Reasoner-а.

Reasoner - это программа, которая анализирует онтологию. Он логически выводит новые факты, которые явно не заданы пользователем, но следуют из структуры и аксиом онтологии.

Простой пример: в нашей онтологии у пиццы есть свойство hasTopping. Мы явно задаём только это направление: у пиццы есть топпинг. Но мы также определили, что у hasTopping есть обратное свойство - isToppingOf. Это значит, что если пицца AmericanaPizza hasTopping MozzarellaTopping, то логично, что MozzarellaTopping isToppingOf AmericanaPizza. Однако мы этого вручную не указывали. Именно Reasoner добавляет такие логически вытекающие связи, которые не заданы явно, но следуют из структуры онтологии.

Из-за присутствия Reasoner-а в Protege есть два представления: Asserted - это факты и связи, которые мы задали вручную, и Inferred - это то, что Reasoner достроил автоматически на их основе, и между этими представлениями можно переключаться.

Более того, inferred-представление можно экспортировать в файл - это называется материализацией, и тогда выводы Reasoner-а будут зафиксированы так, как будто они были заданы изначально.

О структурах данных

Возвращаясь к

AmericanaPizza hasTopping MozzarellaTopping

Как вы думаете, что это за структура данных?

Это RDF-тройка: субъект - предикат - объект. Такой формат лежит в основе представления онтологий.

? RDF - это Resource Description Framework - стандарт W3C для описания данных в виде троек. Он используется, чтобы хранить онтологии и обмениваться данными между программами.

Можно сохранить онтологию в формате Turtle - это один из синтаксисов RDF - и потом найти в файле нужный фрагмент. Выглядит он так:

pizza:AmericanaPizza rdf:type owl:Class ;
rdfs:subClassOf pizza:NamedPizza ,
[ rdf:type owl:Restriction ;
    owl:onProperty pizza:hasTopping ;
    owl:someValuesFrom pizza:MozzarellaTopping
] 

Первая строчка

pizza:AmericanaPizza rdf:type owl:Class ;

значит "AmericanaPizza является классом в онтологии".

Следующая строчка

pizza:AmericanaPizza rdfs:subClassOf pizza:NamedPizza ,

значит "AmericanaPizza является подклассом NamedPizza"

Дальше идёт создание анонимного узла (blank node) - это уже сложнее, но во всяком случае видно, что речь идёт о MozzarellaTopping.

Здесь важно другое: онтологию можно описывать и без графического редактора. Все сущности и связи описываются RDF-тройками, и их можно хранить в обычном текстовом .ttl-файле.

Как задаются свойства и их значения?

Свойства тоже задаются RDF-тройками.

Pizza  hasCaloricContent  xsd:integer  

У класса Pizza есть свойство hasCaloricContent, и его значение должно быть целым числом (xsd:integer).

? xsd - это XML Schema Definition, набор стандартных типов данных, которые онтология заимствует из XML

В терминологии, принятой в онтологиях, у свойства выделяют domain и range.

Первое слово - это domain - класс, к которому относится свойство.
Второе слово - само свойство.
Третье слово - это range - тип данных, который может принимать это свойство.

AmericanaPizza1  hasCaloricContent  723  

У объекта AmericanaPizza1 свойство hasCaloricContent имеет значение 723.

(Это псевдокод, разумеется, но настоящий RDF/Turtle-код выглядит очень похоже).

Открытый мир против закрытого

Здесь я сделаю небольшое лирическое отступление, потому что этот момент принципиально важен.

Есть такой аргумент, который приводят в книжках по Prolog-у:

Откуда я знаю, что у меня нет старшего брата? Я исхожу из того, что если бы у меня был старший брат, мне бы об этом кто-нибудь да рассказал.

Это пример закрытого мира (closed world assumption). Он означает, что всё, чего нет в базе знаний, считается ложным. Иначе говоря, если система не нашла доказательства факта, она исходит из того, что этот факт неверен.

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

В отличие от этого, в онтологиях и семантических веб-технологиях принят открытый мир (open world assumption) - то, что не указано явно, не считается ложным, а остаётся неизвестным.

Поэтому Reasoner умеет только добавлять знания, а вот сказать "этого нет" он не может. Отсюда и последствия: приходится, например, явно прописывать, что условия для класса не только необходимы, но ещё и достаточны. Из-за этого онтология ведёт себя совсем не так, как, например, Prolog, где действует правило закрытого мира.

Как делать запросы?

Есть несколько языков для запросов к онтологии. Чаще всего используют два: DL-запросы и SPARQL.

DL - это Description Logic, и запрос выглядит так:

Customer and purchasedPizza some (hasTopping some (hasSpiciness value Hot))

Этот запрос возвращает всех клиентов, купивших острую пиццу.

SPARQL - это стандартный язык запросов к RDF-графам. Он больше похож на SQL, например,

Сколько всего пицц купили все клиенты?

SELECT (SUM(?pnumber) AS ?psum)
WHERE {
  ?customer pizza:numberOfPizzasPurchased ?pnumber .
}

Правила

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

Такие правила выходят за рамки обычных классов и свойств: они позволяют накладывать условия в стиле "если-то" и тем самым превращать онтологию в основу для бизнес-логики.

Правила задаются на языке SWRL (Semantic Web Rule Language).
Например, правило про скидку можно записать так:

Customer(?c) ^ numberOfPizzasPurchased(?c, ?np) ^
hasSpicinessPreference(?c, Hot) ^ swrlb:greaterThan(?np, 1) -> hasDiscount(?c, 0.2). 

Что дальше?

Мы посмотрели на Pizza Tutorial, разобрали ключевые определения, увидели, как задаются свойства и классы, и попробовали примеры запросов.

Это, конечно, только первое знакомство, но уже даёт представление о том, чем онтологии отличаются от привычных моделей. Онтологии особенно полезны в больших и сложных системах. Возможно, у вас уже есть задача с большим количеством данных и связей между объектами, и после этого обзора вы решите применить онтологию для её решения. Успехов!

Комментарии (4)


  1. itGuevara
    05.09.2025 12:15

    По инструментам посоветуйте:

    1 Онлайн RDF visualizer с URL параметром, т.е. как в graphviz мы параметром передаем скрипт и visualizer по данным из параметра отрисовывает схему. Ранее в своих примерах использовал https://www.ldf.fi/service/rdf-grapher теперь он только через VPN.

    2 RDF visualizer, который может настраивать отображение графики (графических примитивов). Например, на входе RDF turtle, он его парсит и объекты типа "...rdf:type :greenRect ."

    рисует зеленым прямоугольником (легенда задается произвольно, например, конструктором или dot), а типа "синийКруг" - синим кругом. Их label (rdfs:label) рисуется не отдельным объектом, а внутри этого прямоугольника \ круга (произвольно заданной фигуры).

    т.е. мы задаем шаблонами форму отображения каждому типу объекта, подписывая их rdfs:label \ comment и т.п. ("раскрашиваем визуализацию RDF").


    1. sledov Автор
      05.09.2025 12:15

      2 RDF visualizer, который может настраивать отображение графики (графических примитивов).

      Я не знаю онлайн-визуализатора, который позволял бы задавать произвольные формы для типов. Можно попытаться напрямую конвертировать RDF/Turtle в Graphviz DOT и отрисовать. Например, из

      :pizza  a :GreenRect ; rdfs:label "Pizza" .
      :cheese a :BlueCircle; rdfs:label "Cheese" .
      :pizza  :hasTopping :cheese .
      

      сделать

      digraph RDF {
        1 [label="Pizza" shape=rect fillcolor=green style=filled]
        2 [label="Cheese" shape=circle fillcolor=blue style=filled]
        1 -> 2 [label=":hasTopping"]
      }
      

      Это не выглядит особенно страшным.

      Посмотрите ещё на giacomociti/rdf2dot - там через N3 rules можно сопоставить :GreenRect -> shape=rect etc.


      1. itGuevara
        05.09.2025 12:15

        Это не выглядит особенно страшным.

        Да, так и делал. А если использовать https://exceltographviz.com/ то можно под именем типа, например, :GreenRect, задавать значение shape=rect fillcolor=green style=filled]

        т.е., все это (шейп, стиль) будет настроено один раз и подставляться автоматически.

        Надеялся, что что-то готовое из семейства LD-инструментов есть (в комплекте с SPARQL, reasoner и т.п.).

        Сейчас копаю в направлении не RDF2DOT, а RDF2drawio, фрагмент. В тексте хоть и про dot, но это фрагменты xml drawio. Для промышленной (серьезной) работы в любом случае нужен редактор (автопостроение \ генерация не учтет многих особенностей размещения \ формирования схемы как документации). Поэтому условно это направление RDF2SVG.

        При масштабировании тема RDF2DOT \ Diagram-as-code перерастает в RDFto [BPM\EA notation], в чем и замысел проекта SemanticBPM. Фактически мы имеет репозитарий как triplestore и набор представлений (синтаксических оберток) каждого типа объекта в одной или нескольких BPM \ EA нотациях.

        BPM\EA = {VAD, EPC, BPMN ... \ c4, archimate ...}, т.е. когда в этих нотациях "под капотом" Linked Data (RDF, reasoner, SPARQL).


  1. itGuevara
    05.09.2025 12:15

    Аналоги https://protege.stanford.edu/ и вообще подборки / обзоры бесплатных LD-инструментов?