воскресенье, 3 января 2010 г.

Semantic Web, Web of Data, Linked Data и агенты в двух абзацах

Оригинал:
According to (Berners-Lee, 2000, pp.191) "The first step is putting data on the Web in a form that machines can naturally understand, or converting it to that form. This creates what I call a Semantic Web - a web of data that can be processed directly or indirectly by machines". Therefore, while the Semantic Web, or Web of Data, is the goal or the end result of this process, Linked Data provides the means to reach that goal.

By publishing Linked Data, numerous individuals and groups have contributed to the building of a Web of Data, which can lower the barrier to reuse, integration and application of data from multiple, distributed and heterogeneous sources. Over time, with Linked Data as a foundation, some of the more sophisticated proposals associated with the Semantic Web vision, such as intelligent agents, may become a reality.
Вольный перевод:
Согласно (Бернерс-Ли, 2000, стр. 191), "Первый шаг - размещение в сети информации в форме, которую могли бы легко понимать компьютеры, или перевод существующей информации в такую форму." Поэтому, если Semantic Web, или Web of Data, - конечная цель, то Linked Data является средством достижения этой цели.

Размещая Linked Data, люди и сообщества делают вклад в создание Web of Data, который снизит сложность интеграции и использования данных из распределенных разнородных источников. Базируясь на Linked Data, со временем некоторые более сложные концепции Semantic Web (например, интеллектуальные агенты) могут стать реальностью.
Взято отсюда.

четверг, 31 декабря 2009 г.

Обзор высокопроизводительных SAIL-решений

Около полугода назад, я уже сравнивал семантические фреймворки и ризонеры. Если на том этапе для меня важнее был выбор удобного фреймворка, нежели производительность, безопасность и т. д. (и выбор пал на OWLAPI+Pellet), то сейчас нашему проекту нужен высокопроизводительный ризонер с хранилищем в виде базы данных. Посему предлагаю рассмотреть и по возможности сравнить доступные на рынке SAIL-решения (Storage And Inference Layer).

Разделю хранилища на две группы: независимые (назовем их standalone) и являющиеся частью комплексных семантико-ориентированных enterprise-систем (для краткости дальше они будут именоваться PESSS-хранилища - Part of Enterprise Semantic System Store).

Сначала рассмотрим первую группу.

Standalone-хранилища

AllegroGraph

Официальный сайт: http://www.franz.com/agraph/allegrograph/
Цена: Бесплатно до 50 миллионов триплетов. При превышении лимита: Developer Edition: $4195 за процессор, Enterprise Edition: $34995 за процессор; академическая скидка - 50%. RacerPro продается отдельно; стоимость его лицензии можно узнать на официальном сайте (цены примерно того же порядка).
Поддерживаемые фреймворки: Jena, Sesame, Clojure
Архитектура:
Описание:
AllegroGraph разрабатывает фирма Franz Inc., которая широко известна благодаря таким продуктам, как TopBraid Composer (редактор онтологий), RacerPro (OWL DL ризонер) и др.

Поддерживает 2 основных типа вывода:
1. RDFS++
Уж как только не называют "RDFS плюс немного OWL"... На сей раз имеются в виду следующие предикаты: rdf:type, rdfs:subClassOf, rdfs:range, rdfs:domain, rdfs:subpropertyof, owl:sameAs, owl:inverseOf, owl:TransitiveProperty, owl:hasValue.
2. RacerPro
AllegroGraph интегрирован с еще одним ризонером Franz Inc. - RacerPro, который имеет выразительность OWL DL. Обсуждение OWL DL ризонеров в некоторой степени выходит за рамки сегодняшней статьи (ибо высокопроизводительными их пока назвать сложно), однако мы еще коснемся RacerPro при обсуждении PelletDb.

Итак, AllegroGraph является RDF-хранилищем с поддержкой двух ризонеров с полярными характеристиками. Впечатляет.

Franz Inc. также разрабатывает проект AGWebView, который, как несложно догадаться из названия, представляет собой Web-интерфейс для AllegroGraph.

BigOWLIM
Официальный сайт: http://www.ontotext.com/owlim/big/
Цена: 700 евро за каждое процессорное ядро
Поддерживаемые фреймворки: Sesame
Архитектура: Реализует SAIL для Sesame
Описание:
BigOWLIM имеет выразительность "RDFS with most of OWL Lite" (здесь подробнее), которая чуть шире выразительности ризонера RDFS++ AllegroGraph.

Разработчики OWLIM не скромничают и заявляют, что "BigOWLIM is the most scalable and efficient RDF Database!"

Интересно было бы сравнить производительность BigOWLIM с AllegroGraph RDFS++, но сделать это не так просто, ибо ризонеры базируются на разных принципах: static и dynamic materialization соответственно. Разобраться в различиях поможет описание RDFS++ dynamic materialzation (кстати, в видео идет сравнение с OWLIM). Итак, в теории AllegroGraph RDFS++ должен
1. быстрее загружать онтологии (ибо при этом ему не нужно делать вывод)
2. абсолютно безболезненно переживать модификацию онтологии
3. дольше выполнять запросы (ибо каждый запрос требует выполнения логического вывода).

От теории перейдем к практике и сравним результаты теста LUBM(8k) (информация взята отсюда и отсюда) при использовании сопоставимых конфигураций:
  • BigOWLIM: Core i7 940 (2.93GHz, quad-core, HT), 12GB (DDR3), 3x320GB 7.2krpm, RAID 0

  • AllegroGraph: Quad 1.8GHz AMD64 Opteron 884, with 16Gb of memory running Fedora 8

Все с ног на голову.

AllegroGraph показал в два раза худшее время загрузки (и это при том, что BigOWLIM во время загрузки еще и вывод делает). Так как у тестовой конфигурации AllegroGraph отсутствовала информация о дисковой подсистеме, пришлось восполнить этот пробел при помощи службы поддержки. Оказалось, использовались 2 обычных Sata диска, не объединенных в RAID (что равносильно одному диску). Если учесть преимущество на этапе загрузки в скорости тройного RAID 0 (используемого для тестирования BigOWLIM) против обычного диска, все встает на свои места.

А вот объяснить четырехкратное преимущество AllegroGraph при выполнении запросов (особенно при том, что теоретически на этом этапе он должен проигрывать BigOWLIM), пожалуй, можно лишь тем, что у AllegroGraph отлично реализованы алгоритмы вывода и поиска.

Подведем итоги локального сравнения.

В теории все звучит предельно ясно: чем более динамично меняется онтология, тем лучше себя показывает dynamic materialization; и наоборот. На практике же не все так однозначно: многое решают нюансы реализации.

Несмотря на то, что AllegroGraph производит впечатление гораздо более мощной, целостной и функциональной системы, BigOWLIM определенно достоин внимания при выборе высокопроизводительного RDF-хранилища (особенно учитывая колоссальную разницу в стоимости лицензий).

PelletDb

Официальный сайт: http://clarkparsia.com/pelletdb
Цена:
EULA-лицензия на PelletDb - 2495$ + лицензия на Pellet (если ваш проект распространяется по GPL, Pellet бесплатен) EULA 4995$ за сервер + лицензия Oracle Enterprise.
Поддерживаемые фреймворки: Jena
Архитектура: Взаимодействует с Oracle Enterpise при помощи Jena Oracle Adaptor
Описание:
Сомневался, в какую категорию поместить PelletDb. С одной стороны, что может быть "более enterprise", чем Oracle, с другой, - категория PESSS подразумевает семантико-ориентированность enterprise-системы. А в Oracle реализовано лишь хранилище с ризонером да SPARQL-endpoint. Я посчитал, что этого недостаточно для попадания в категорию PESSS. Кроме того, при таком раскладе в обоих категориях по три продукта :) В любом случае, это не принципиально.

Совсем "свеженький" продукт (релиз состоялся 1 декабря текущего года), реализующий для Oralce Enterprise логический вывод с выразительностью OWL DL.

Работает PelletDb следующим образом:
1. При помощи Jena Oracle Adaptor загружает из Oralce триплеты
2. Делает полный вывод
3. Загружает выведенные триплеты обратно в Oracle

Вырисовываются два существенных минуса такого подхода:
1. Для вывода вся модель должна быть в памяти. Это существенно снижает целесообразность использования PelletDb в enterpise-проектах (а жесткая привязка к Oracle Enterprise диктует использование PelletDb именно в этом секторе). Конечно же, разработчики учли этот "нюанс", поэтому PelletDb поддерживает (подробности в pelletdb whitepaper) режим вывода только схемы (=TBox). При этом в результате мы получим ABox, выведенный ризонером Oracle, и TBox, выведенный PelletDb.
2. Если "классический" Pellet делает вывод динамически, то PelletDb, очевидно, делает его статически. Полный OWL DL вывод - это очень медленно. Здесь бы пригодился динамический вывод... но используемая архитектура его не предполагает. В этом отношении интереснее смотрится связка RacerPro (OWL DL ризонер, который мы упоминали выше) и AllegroGraph. Ведь это продукты одной фирмы, а значит у них больше гибкости в вопросе интеграции.

<Лирическое отсупление на тему RacerPro>

В RacerPro можно выделить два режима работы.

В первом режиме происходит inmemory-вывод, который влечет за собой ограничение на размер ABox (аналогичен первому режиму PelletDb). В качестве решения можно отказаться от вывода ABox при помощи RacerPro, положившись на RDFS++ ризонер AllegroGraph (аналогично второму режиму PelletDb). Есть еще альтернативное решение, которое предполагает разбиение ABox на независимые части, которые выводились бы отдельно друг от друга. Пока это можно сделать только вручную, но уже в будущей версии для этого будет специальный API, а в более далекой перспективе обещают реализовать автоматический алгоритм разбиения ABox.

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

</Лирическое отступление на тему RacerPro>

В целом PelletDb выглядит слишком узконаправленным: он заточен не только под Oracle Enterprise, но еще, по сути, под вывод лишь TBox. А ведь стоит недешево. Хотя, с другой стороны, "Everything is better with Bluetooth Oracle" :)

PESSS-хранилища

Virtuoso
Официальный сайт: virtuoso.openlinksw.com
Цена: Virtuoso Open Source Edition бесплатна. На нее распространяется ограничение соединения с внешними базами данных, отсутствие поддержки репликации и Virtual Database. Цену на подходящую вам конфигурацию коммерческой версии можно узнать на официальном сайте, выбрав Virtuoso Universal Server.
Поддерживаемые фреймворки: Jena, Sesame, Redland, Linq2Rdf, dotnetRDF
Архитектура:

Описание:
Virtuoso - очень мощный Enterprise-продукт фирмы OpenLink, которая специализируется на разработке RDBMS Middleware.

В состав Virtuoso входит одно из самых производительных и масштабируемых (например, сейчас в этом LOD-хранилище числится более 9 гигаквад) RDF-хранилищ, снабженных изощренной SPARQL-endpoint с поддержкой RDF Views. RDF Views - это реализация RDBMS2RDF, позволяющая динамически работать с реляционными данными через SPARQL (незаменимая возможность для проектов, ориентированных на интеграцию данных).

Выразительность встроенного ризонера довольно скромная: поддерживаются rdfs:subClassOf, rdfs:subPropertyOf, owl:equivalentClass, owl:equivalentProperty и owl:sameAs.

Отдельного упоминания стоит обилие качественной документации по Virtuoso.

OpenAnzo

Официальный сайт: http://www.openanzo.org/
Цена: Бесплатно (Eclipse Public License -v 1.0)
Описание:
OpenAnzo представляет собой RDF-хранилище с широким спектром семантического middleware, которое включает поддержку распределенных сервисов, работу в оффлайн, версионирование, ограничение доступа и т. д.

Одна из концепций данного проекта - ориентация на сервисы. Так, например, упомянутое выше RDF-хранилище, именуемое Anzo Store, не является хранилищем в привычном понимании этого слова. Anzo Store - это data-source-сервис, реализующий хранение триплетов в реляционных СУБД. Другой пример использования сервисов - синхронизация информации, реализованная при помощи сервисов репликации и уведомлений.

Встроенный ризонер отсутствует. В качестве решения этой проблемы предлагается выводить триплеты при помощи внешнего ризонера (а актуализировать информацию при помощи упомянутых выше сервисов репликации и уведомлений) или встроить вызов ризонера в обработчик SPARQL-запросов.

Предоставляется клиентский API для Java, .NET и JavaScript.

В целом, очень интересный Open Source проект с широким enterprise-функционалом.

Semantics.Server

Официальный сайт: http://www.intellidimension.com/products/semantics-server/
Цена: В зависимости от версии: например, Standard Edition License - 10000$, Enterprise Edition License - 15000$ + лицензия Microsoft SQL Server.
Описание:
Одна из немногих семантических разработок на .NET. Причем не просто на .NET, а в тесном сотрудничестве с Microsoft.

Semantics.Server представляет собой целый ряд средств, включая свой фреймворк, OWL Full ризонер и хранилище на базе SQL Server. Особенно хотелось бы отметить следующие возможности:
1. Объединение реляционных и семантических данных при помощи T-SQL (в отличие от Virtuoso RDF Views, другие СУБД не поддерживаются)
2. Распределение одного RDF-графа на множество серверов.

В maillist'е Semantics.Server периодически появляются сообщения о низкой производительности продукта по сравнению с конкурирующими системами. Публичных тестов практически нет, но подобные отзывы полностью коррелируют с моим опытом использования Semantics.Server. Поэтому перед тем, как воспользоваться возможностью распределения RDF-графа на множество серверов, стоит проверить: может выйти так, что конкурирующий продукт решит поставленную задачу в заданные сроки даже на одном сервере.

Также серьезным недостатком Semantics.Server является ограниченная поддержка других (помимо SQL Server) СУБД. Хотя работа в этом направлении ведется:
"Yes, it only works with SQL Server at the moment using out of the box components (you could write a custom datasource component to connect to any external source of data). We do expect to support access to additional relational stores using our SQL Datasource, but have no timeline for that right now."

Заключение

Пожалуй откажусь от идеи делать выводы уровня must live/must die касательно вышеописанных продуктов: уж слишком они все разные.

В обзоре были рассмотрены далеко не все существующие продукты. Буду рад увидеть в комментариях дополнение этого поста.

воскресенье, 4 октября 2009 г.

LINQ. First vs. Single. Часть вторая.

Неожиданно предыдущий пост про LINQ породил несколько вопросов, которые в свою очередь породили еще несколько :) О них-то мы сегодня и поговорим.

Основная мысль того поста была настолько очевидной, что я даже сомневался, писать или нет. Когда же пост уже был написан, решил сделать его хоть немного менее унылым, снабдив исходниками реализаций методов First и Single LINQ To Objects. При этом реализация метода Single мне показалась неоптимальной. За комментариями по этому поводу я обратился на форумы MSDN. К сожалению, я не сразу понял мысль коллег про "exceptional cases"... но в целом дискуссия получилась довольно конструктивной.

Итак, напомню, как выглядел код, полученный при помощи Reflector'a:

TSource local = default(TSource);
long num = 0L;
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
num += 1L;
}
}
long num2 = num;
if ((num2 <= 1L) && (num2 >= 0L))
{
switch (((int) num2))
{
case 0:
throw Error.NoMatch();

case 1:
return local;
}
}
throw Error.MoreThanOneMatch();

А почему бы не добавить в тело условия if (predicate(local2)) проверку на равенство num двум:

TSource local = default(TSource);
long num = 0L;
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
num += 1L;
if (num == 2)
throw Error.MoreThanOneMatch();
}
}
long num2 = num;
if ((num2 <= 1L) && (num2 >= 0L))
{
switch (((int) num2))
{
case 0:
throw Error.NoMatch();

case 1:
return local;
}
}

С одной стороны, этот код привносит условие, которое тоже требует машинного времени для своего выполнения. Но, во-первых, условие if (num == 2) - элементарное, а во-вторых, при любом раскладе оно выполнится не более двух раз. Что же мы при этом экономим? Экономим мы k проходов Enumenator'а (который лежит в основе foreach) и столько же выполнений предиката (только в случае наличия дубликатов, ибо если элемент уникальный, нам все равно придется пройти коллекцию полностью). Очевидно, что стандартная реализация проигрывает.

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

В целом, конечно, данный вопрос представляет собой, в большей степени, академический интерес (кстати, неплохая иллюстрация закона дырявых абстракций): на практике в 99.9% случаев проблем из-за текущей реализации метода Single не будет. Если же для Вас метод Single стал проблемой, замените его на собственный extension method.

На этом с LINQ To Objects на сегодня закончим - поговорим о LINQ To Entities и его реализации метода Single. Напомню, что в EF v1 метод Single не поддерживался: приходилось либо довольствоваться First, либо использовать разные костыли, например, вот этот. Проблема приведенного по ссылке workaround'а в том, что при вызове query.Count из базы будут возвращены все удовлетворяющие запросу записи (в том числе и дублирующиеся). В случае, если мы обращаемся к "тяжелым" данным, результат может быть плачевным.

Так как же с Single обстоят дела в EF 4? Добравшись до VS 2010, я был приятно удивлен - работает. Но маленький параноик в моей голове убедил меня (спасибо ему за это) открыть Profiler и посмотреть на генерируемый SQL-код. А вот и он:

SELECT TOP (2)
[Extent1].[AddressId] AS [AddressId],
[Extent1].[City] AS [City],
[Extent1].[Street] AS [Street],
[Extent1].[PostalCode] AS [PostalCode],
[Extent1].[Apartment] AS [Apartment]
FROM [dbo].[Addresses] AS [Extent1]
WHERE 1 = [Extent1].[AddressId]

Данный код при наличии дубликатов возвращает две записи. Это, конечно, чуть лучше, чем решение, обсуждавшееся выше (там возвращалось неограниченное число дубликатов), но хотелось бы большего: хотелось бы, чтобы вопрос наличия дубликатов решался на стороне СУБД (например, при помощи подзапросов), а возвращалась бы либо одна (уникальная) запись, либо вообще ничего (если есть дубликаты).

За комментариями я в очередной раз обратился на форумы MSDN (прекрасное место :) ). Прежде всего, меня интересовало, финальное ли это решение для EF 4. Как Вы можете судить по ответу, шансов на то, что это поведение изменится до релиза .NET 4, мало.

На этой печальной ноте и закончим сегодняшний разговор о LINQ.

суббота, 3 октября 2009 г.

Знакомимся с IKVM.NET

В статье "Сравнительный анализ фреймворков для работы с онтологиями под .NET и Java" я уже упоминал проект IKVM.NET. Cегодня я хотел бы поговорить о нем подробнее.

IKVM.NET предоставляет поддержку Java для Mono и .NET, включает в себя JVM, рализованную на .NET, а также interoperability-средства между Java и .NET (с акцентом на использование Java в .NET, а не наоборот).

3 основных варианта использования IKVM.NET:

1. Drop-in JVM (ikvm.exe): Позволяет динамически запускать Java приложения под .NET.
2. Use Java libraries in your .NET applications (ikvmc.exe): Статически компилирует jar'ы в .NET-сборки.
3. Develop .NET applications in Java (ikvmstub.exe): Позволяет использовать .NET-классы при разработке на Java (при условии, что затем Java-код будет скомпилирован в .NET при помощи ikvmc.exe).

Несмотря на то, что текущая версия проекта "всего лишь" 0.40, он уже очень многое умеет. Самое узкое место - графический интерфейс: конвертация AWT и Swing в WinForms (ни о Java FX, ни о WPF пока ни слова) - очень трудоемкая задача. К тому же, по заявлению разработчиков, приоритет этой задачи низкий (хотя, насколько я могу судить по их блогу, в последнее время деятельность в этом направлении существенно активизировалась). Полностью разделяю позицию разработчиков относительно GUI и считаю гораздо более ценной миссию "портирования" бесчисленного множества Java-библиотек в .NET. В конце концов, имея backend, всегда можно прикрутить какой-никакой интерфейс, а вот наоборот - вряд ли.

Быстродействие и потребление памяти IKVM.NET можно измерить, как минимум, двумя способоами: сравнить показатели 1. "чистой" Java и конвертированной под .NET 2. конвертированного под .NET кода и "чистого" .NET кода. В первом варианте используются разные платформы, поэтому многое зависит от деталей реализации (чего только различия в сборщиках мусора стоят). А вот второй вариант более объективен (при как можно близких реализациях тестовых программ под Java и .NET). По заверениям разработчиков, быстродействие (вероятно, использовался второй подход) может падать в 1.5-2 раза... хотя на форумах я встречал и свидетельства об ускорении работы приложений (видимо, здесь для сравнения использовался первый подход). Вообще при перекомпиляции происходит много интересных метаморфоз: так, например, мне приходилось сталкиваться с тем, что не работающий при некоторых условиях Java-код отлично работал после компиляции в .NET.

А не костыль ли это? В определенной степени - да. Первое, что бросается в глаза при начале использования конвертированных Java-классов, - несоответствие code agreement'ов в Java и .NET. Из-за этого код становится немного "грязнее". Но это мелочь по сравнению, например, с тем фактом, что в любой момент Вы можете натолкнуться на критичную для Вас возможность, которая еще не реализована. Но, с другой стороны, а какие есть альтернативы? Использовать другие interoperability-средства (возможно, еще менее надежные) или переписывать необходимый Java-фреймворк под .NET? Сложный выбор. Если Вам потребуется функциональность IKVM.NET, тщательно взвесьте все за и против, ибо последствия принятого решения могут оказаться очень серьезными. Я свой выбор сделал (по крайней мере для текущего проекта) и пока не разочаровался.

С огромным уважением отношусь к разработчикам такого технического сложного проекта. It is really rocket science! Заставить две разные платформы (которые похожи лишь с высоты орлиного полета) работать вместе - это дорогого стоит.

Я хотел было материализовать свою благодарность разработчикам в виде "пожертвования"... но не нашел традиционной кнопки Donate на официальном сайте. Списавшись с разработчиками, получил ответ:

Hi Alexander,

A donation is not necessary, but your mail is appreciated!

Regards,
Jeroen

Вот так.

На этом знакомство с IKVM.NET будем считать оконченным. Если возникнет интерес, в следующий раз рассмотрим применение IKVM.NET на практике.