Сравнительный анализ фреймворков для работы с онтологиями под .NET и Java

Ни для кого не секрет, что львиная доля проектов, связанных с Semantic Web, разрабатывается на Java. Фреймворки для работы с семантическими онтологиями не являются исключением: все основные проекты (Jena, OWL API, Sesame и т. д.) написаны именно на Java. Единственным серьезным представителем, использующим .NET, является фирма Intellidimension с продуктами RDF Gateway и Semantics.SDK.

В этой статье опишу свой опыт работы с вышеуказанными фреймворками и поделюсь результатами тестирования.

Вступление

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

Перед погружением в технические детали скажу пару слов о фреймворке от Intellidimension (как наименее известном продукте для Java-ориентированного сообщества). В отличие от остальных рассматриваемых в этой статье фреймворков, которые являются OpenSource-проектами, RDF Gateway и Semantics.SDK распространяются с закрытыми исходными кодами и стоят достаточно приличных денег. Так, один лишь RDF Gateway 3.0 Enterprise стоит 10000$ (хотя версия 2.0 стоила «всего» 2000$). К слову, использованные при тестировании ризонеры — Pellet и Owlim — тоже не бесплатны: Pellet распространяется по dual license, а Owlim предлагает бесплатно лишь версию, работающую в памяти; версия, работающая с хранилищем, стоит 700 евро за каждое используемое процессорное ядро.

Тестирование

Передо мной стояла задача подобрать фреймворк для реализации проекта под .NET, поэтому Java-проекты в чистом виде меня не интересовали (изначально я даже не планировал их тестирование). Необходимо было выбрать средство interop’а между Java и .NET. Мой выбор пал на ikvm.net, который позволяет конвертировать  jar’ы в .NET dll. Получив .NET-версию Jena, OWL API и Sesame, я принялся за их тестирование.  Однако тестирование было бы неполным, если бы не содержало результатов тестирования Java-фреймворков в их родной среде. Таким образом, в тестировании участвуют: Intellidimension Semantics.SDK 1.0, OWL API 2.2.0+Pellet 2.0rc5 (как под Java, так и под .NET), Jena 2.5.7+Pellet2.0rc5 (как под Java, так и под .NET) и отчасти Sesame 2.24+SwiftOwlim 3.0b9.

Из первоначального тестирования пришлось исключить Sesame ввиду отличающейся от Semantic SDK и Pellet политики логического вывода в Owlim (Owlim — основной ризонер, используемый в связке с Sesame). Так, Pellet и Semantic SDK нацелены на вывод во время запроса (query-time reasoning), хотя и включают средства заблаговременного вывода; Owlim же нацелен на полный логический вывод (full materialization). Об этом мы еще поговорим в разделе «Общая информация о ризонерах».

В качестве тестовой была выбрана онтология Thesaurus 09.02d института NCI. Правда, в чистом виде она содержит ряд противоречивостей (inconsistency). После общения со службой поддержки несовместимости были выявлены. Я использовал  модифицированную версию 09.02d (которую Вы  можете скачать с моего dropbox’а), хотя сейчас уже доступна версия 09.04d, в которой данных несовместимостей нет.

Для тестирования была смоделирована следующая ситуация:
1.    Сначала онтология из файла загружалась в модель;
2.    Затем к этой модели последовательно выполнялось 3 SparQL-запроса (тексты запросов можно скачать здесь).

Сначала рассмотрим результаты тестирования первого этапа:


Результаты тестирования первого этапа

Несмотря на то, что .NET/ikvm-фреймворки медленнее своих Java-собратьев в 2-3 раза, они оказались быстрее Intellidimension.

В плане работы с памятью .NET оставил более приятное впечатление. Сборщик мусора в Java требует указания максимального объема оперативной памяти, который может быть выделен под кучу (параметр Xmx); .NET же использует более логичную, на мой взгляд, политику: он потребляет столько памяти, сколько ему нужно (если только не задано ограничение). Ограничение через Xmx — очень старый «баг», который, к сожалению, до сих пор не пофикшен. В качестве решения предлагается просто задавать Xmx с запасом (если, конечно, объем оперативной памяти позволяет), однако в этом случае (тестирование велось с Xmx:12g) сборщик мусора особенно себя не утруждает (что мы и видим по результатам тестирования). Можно пойти другим путем — подбирать минимальное значение Xmx для конкретных входных данных (правда, рискуя напороться на OutOfMemoryException). Таким образом можно приблизить объем потребляемой JVM памяти к аналогичным показателям CLR (пусть и с некоторыми дополнительными потерями производительности на более частые сборки мусора).

Касательно ограничения на максимальный объем используемой памяти произошел довольно курьезный случай. После успешной загрузки онтологии Thesaurus при помощи конвертированного в .NET OWL API, я решил открыть эту онтологию в Protége (который базируется на той же версии OWL API) для ознакомления с ее структурой. Однако вместо дерева концептов и экземпляров я получил OutOfMemoryException (при том, что свободной памяти было предостаточно). И хотя увеличение значения атрибута Xmx разрешило проблему, такая несамостоятельность сборщика мусора в Java не радует. Курьезность ситуации заключается в том, что несмотря на то, что Java-приложение не запускается в родной среде (без танцев с JVM), после конвертации в .NET при помощи ikvm оно работает.

Теперь перейдем ко второму пункту тестирования — выполнению SPARQL-запросов. К сожалению, на этом этапе придется оставить за бортом лидера первого теста — OWL API. Дело в том, что интерфейс OWL API, который реализуют ризонеры, не содержит методов для выполнения SPARQL-запросов. Связано это с тем, что SPARQL создавался как язык запросов к RDF-графам (и с OWL он не очень дружит), а OWL API, как нетрудно догадаться по названию, ориентирован именно на OWL. Сейчас идет работа над стандартом SPARQL-DL и, возможно, его поддержка будет реализована в одной из следующих версий OWL API. На данный момент остается лишь использовать class expressions, которые позволяют писать запросы с использованием манчестерского синтаксиса. Class expressions — это, конечно, не SPARQL… но для большинства задач их достаточно.

Итак, результаты тестирования:


Результаты тестирования второго этапа

Сначала прокомментирую прочерки в графе Intellidimension. С момента запуска тестового приложения прошло 6 часов, процесс весил порядка 6Гб, а результата все не было. Ждать дольше у меня не хватило терпения. Вынужден засчитать Semantics.SDK техническое поражение. Справедливости ради стоит отметить, что с более мелкими онтологиями Semantics.SDK справляется: и вывод делает, и запросы обрабатывает… правда, сравнивая результаты с Jena+Pellet, могу с уверенностью заявить, что Semantics.SDK не всегда выдает полный результат.

Pellet же справился с выводом за вполне разумное время (запросы были не из легких) и, как и на первом этапе тестирования, .NET/ikvm-фреймворк выглядит предпочтительнее Intellidimension.

На этом этап тестирования закончен. Подводя итоги, можно сказать, что победителем стала система Jena+Pellet, а приз авторских симпатий достается OWL API+Pellet.

Общая информация о ризонерах

В целом, существует два подхода к реализации логического вывода: на базе правил (с использованием алгоритмов forward-chaining и/или backward-chaining) и на базе семантического табло (semantic tableau). На базе правил реализованы Semantics.SDK и Owlim, а на базе семантического табло — Pellet.

Насколько я могу судить, rule-based ризонеры выгодно использовать для языков с низкой выразительностью, а ризонеры на базе семантического табло — для языков с высокой выразительностью. Если Pellet (OWL-DL) и Owlim (OWL-Tiny) подтверждают это наблюдение (находясь по разные стороны баррикады), то Semantics.SDK (OWL-FULL) является исключением (и судя по тестам производительности, ничего хорошего в этом исключении нет).

Рассмотрим диаграмму c официального сайта Owlim:


Схема выразительности языков

Как видим, Owlim поддерживает лишь OWL Tiny. Именно эта особенность позволяет ему добиться очень высокой производительности.

Owlim — единственный (из рассмотренных) ризонер, который поддерживает многопоточный вывод. Тем самым Owlim реализует преимущество rule-based систем перед семантическим табло — возможность распараллеливания (алгоритмов распараллеливания процесса построения семантического табло пока нет). Разработчики Semantics.SDK утверждают, что их вывод тоже распараллеливается… но в trial-версии это не реализовано (на мой взгляд, не самое удачное ограничение для trial-версии). Просьба выделить мне краткосрочную лицензию для тестирования осталась без ответа, поэтому приходится верить разработчикам на слово.

В идеальном мире определенно должен был бы существовать ризонер, который бы при анализе онтологии определял уровень выразительности и применял для ее вывода соответствующие алгоритмы. На данный момент такого ризонера нет, да и вряд ли он когда-либо появится.

Заключение

В этой статье акцент сделан на производительности, однако при выборе семантического фреймворка для того или иного проекта акцент нужно, в первую очередь, делать на функционале (поддержка (нереляционного) хранилища, поддержка OWL2 и т. д.). Обсуждение этих вопросов выходит за рамки данной статьи (да и не настолько хорошо я знаком с каждым из фреймворков, чтобы делать такой анализ). В отношении функциональности я хотел было похвалить продукты от Intellidimension: связка RDFGateway и Semantics.SDK представляет собой очень мощный фреймворк, аналогов которому в мире Java нет… но выкрутасы их ризонера охладили мои чувства к этому фреймворку.

Автор Alexander Sidorov

P. S. Огромное спасибо за ликбез, оказанный в ходе написания статьи, Клинову Павлу.

PP. S. Так как это моя первая статья на shcherbak.net, по настоянию Сергея кратко расскажу о себе. Студент 4-го курса Томского Политехнического Университета. Помимо основной профильной деятельности (.NET-программирование) занимаюсь Semantic Web в рамках лаборатории Систем Управления Знаниями под руководством Тузовского А. Ф. Мой блог: alexidsa.blogspot.com


Понравилась статья? Поделитесь с друзьями!


12 Responses to Сравнительный анализ фреймворков для работы с онтологиями под .NET и Java

  1. Nata_Ke:

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

  2. Да , он анализирует species, но это влияет только на выбор completion strategy для tableau (т.е. фактически это стратегия построения completion graph). Александр, насколько я понял, имел в виду переключение между принципиально разными дедуктивными методами в зависимости от языка (например, от табло к resolution или наоборот).

  3. dementiev:

    привет. я паренёк из Минска, который на webconfe задавал вопросы на пленарном докладе;)
    Где вам лучше задавать вопросы на сайте, в комментариях или блоге?

  4. пробуйте задавать вопросы на форуме или в соответствующей вашему вопросу записи.
    форум по адресу shcherbak.net/forum

  5. Idsa:

    dementiev, Вы, наверное, с кем-то меня путаете: в Минске на конференции меня не было.

  6. Вот ответ на вашу статью http://4customizer.com/ru/2010/06/a-pochemu-java-a-ne-net/

  7. Idsa:

    Видео уже недоступно :(

  8. передержал в спам листе этот комментарий к сожалению…

  9. VasyaRogov:

    Запросы через Class expressions… Правильно ли я понял:
    1. В онтологии задаем некоторый класс с использование конструкций OWL
    2. Делаем лог-вывод
    3. Возврящаем экземпляры данного класса

    Есть ли в OWL api штатное средство для этого или надо добавлять аксимомы для именованного класса, получать его эзмепляры а затем удалять добавленные аксииомы?

  10. PavelK:

    Есть, см. интерфейс OWLReasoner в OWL API и пример http://owlapi.svn.sourceforge.net/viewvc/owlapi/v3/trunk/examples/src/main/java/org/coode/owlapi/examples/Example8.java?view=markup. Именно это штатное средство используется на закладке DL Query в Protege.
    Т.е. ты все правильно понял, но явным образом класс добавлять в онтологию (т.е. через аксиомы) не надо.

  11. VasyaRogov:

    Посмотрел пример но там, если ничего не пропустил, методам reasonerа передаются именованные классы, которые получаются из datafactory:

    OWLClass vegPizza = fac.getOWLClass(IRI.create(«http://owl.man.ac.uk/2005/07/sssw/people#vegetarian»));
    NodeSet subClses = reasoner.getSubClasses(vegPizza, true);

    Т.е. если я например хочу у резанера запросить экземпляры анонимного класса, который equivalent ИменованныйКлассA or ИменованныйКлассB, то мне надо сначала через datafactory получить OWLObjectIntersectionOf этих двух классов, а потом на основании полученной аксиомы опять через datafactory получить OWLEquivalentClassesAxiom и уже полученное передать резанеру.

  12. PavelK:

    Нет, тебе нужно просто через OWLDataFactory получить нужное class expression. Добавлять никакие аксиомы в онтологию не нужно. Насколько я помню, reasoner.getSubClass принимает OWLClassExpression.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


Ответить с помощью ВКонтакте: