Поиск по сайту

Login Form



Главная Инструменты Простое приложение Semantic Web на C#
Простое приложение Semantic Web на C# PDF Печать E-mail
Рейтинг пользователей: / 0
ХудшийЛучший 
Автор: Эндрю Мэттьюс   
04.04.2008 14:42

Эндрю Мэттьюс
Оригинал: A Simple Semantic Web Application In C#

Последнее обновление библиотеки SemWeb от Джоша Тауберера включает C# реализацию механизма вывода Эйлера. Этот механизм способен идти дальше простого RDFS вывода (т.е. элементарного следования взаимоотошениям между классами), и позволяет воспользоваться правилами. Для того, чтобы разобраться с подходами, которые предлагает эта среда, я воспользовался онтологией моделирующей простой конечный автомат. Онтология - проще некуда. Вот N3 файл, в котором определены классы и взаимоотношения между ними.

@prefix daml: <http://www.daml.org/2000/12/daml+oil#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <file:///C:/dev/prototypes/semantic-web/ontologies/2007/04/states/states.rdf#> .
 
#Classes
:State a owl:Class;
daml:comment "states the system can be in";
daml:disjointUnionOf ( :S1 :S2 :S3 ).
 
:InputToken a owl:Class;
daml:comment "inputs to the system";
daml:disjointUnionOf ( :INil :I1 :I2 ).
 
:Machine a owl:Class.
:System a owl:Class.
 
#properties
:isInState
rdfs:domain :Machine;
rdfs:range :State;
owl:cardinality "1".
 
:hasInput
rdfs:domain :System;
rdfs:range :InputToken;
owl:cardinality "1".
 
#Instances
:Machine1
a :Machine;
:isInState :S1.
 
:This a :System;
:hasInput :INil.
 

Как в любом детерминированном конечном автомате, здесь работают два ключевых класса: :State (Состояние) и :InputToken (ВходнойСимвол). Состояние - это попарно непересекающиеся множество классов :S1, :S2 и :S3. Это значит, что :S1 - не является :S2, и не является :S3. Если вы явно не специфицируете такое разделение механизм вывода не сможет предположить его наличие. Если нет правила утверждающего, что классы не пересекаются, то механизм вывода не сможет предположить, что эти классы различны. То есть если Автомат1 находится в состоянии S1, то это не означает, что он не может одновременно находиться и в состоянии S2. Вы должны четко определить, что S1 - это не S2. Педантичность всегда имеет значение, когда вы имеете дело с онтологиями. И в то время как я превращался в законченного педанта за годы программирования я был шокирован тем уровнем семантической поддержки, которую я получал от языков программирования. OWL обеспечивает вас очень богатой палитрой для работы, но не слишком удобной поддержкой. Вы чувствуете новую степень свободы, когда проектируете библиотеку классов на OWL по сравнению с объектно-ориентированными языками. Примерно как в случае перехода от командной строки DOS на Bash.

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

#@prefix log: .
#@prefix rdfs: .
#@prefix owl: .
@prefix :  <file:///C:/dev/prototypes/semantic-web/ontologies/2007/04/states/states.rdf#> .
 
# ~>
{ :Machine1 :isInState :S1. :This :hasInput :I1. }
=>
{ :Machine1 :isInState :S1. :This :hasInput :INil. }.
 
# ~>
{ :Machine1 :isInState :S1. :This :hasInput :I2. }
=>
{ :Machine1 :isInState :S2. :This :hasInput :INil. }.
 
# ~>
{ :Machine1 :isInState :S1. :This :hasInput :I3. }
=>
{ :Machine1 :isInState :S3. :This :hasInput :INil.}.
 
 

Первоначально я натолкнулся на проблему, в силу того, что я думал о задаче с точки зрения императивного программирования. Я подошел к проектированию как будто я собираюсь присваивать значения переменным. Это неверный подход. Рассматривайте проектирование правил как добавление фактов к тому, что вы уже знаете. Так что, вместо того, чтобы говорить "если X, то Y", используйте фразу "если я знаю X, то я также знаю Y". Программа для работы с этим набором правил выглядит так:

internal class Program
{
    private static readonly string ontologyLocation =
      @"C:/dev/prototypes/semantic-web/ontologies/20074/states/";
 
    private static string baseUri = 
      @"file:///C:/dev/prototypes/semantic-web/ontologies/2007/04/states/states.rdf#";
    private static MemoryStore store = new MemoryStore();
    private static Entity Machine1 = new Entity(baseUri + "Machine1");
    private static Entity Input1 = new Entity(baseUri + "I1");
    private static Entity Input2 = new Entity(baseUri + "I2");
    private static Entity theSystem = new Entity(baseUri + "This");
    private static string hasInput = baseUri + "hasInput";
    private static string isInState = baseUri + "isInState";
 
    private static void Main(string[] args)
    {
        InitialiseStore();
        DisplayCurrentStates();
        SetNewInput(Input2);
        DisplayCurrentStates();
    }
 
    private static void DisplayCurrentStates()
    {
        SelectResult ra = store.Select(new Statement(Machine1, new Entity(isInState), null));
        Debug.Write("Current states: ");
        foreach (Statement resource in ra.ToArray())
        {
            Debug.Write(resource.Object.Uri);
        }
        Debug.WriteLine("");
    }
 
    private static void InitialiseStore()
    {
        string statesLocation = Path.Combine(ontologyLocation, "states.n3");
        string rulesLocation = Path.Combine(ontologyLocation, "rules.n3");
        Euler engine = new Euler(new N3Reader(File.OpenText(rulesLocation)));
        store.Import(new N3Reader(File.OpenText(statesLocation)));
        store.AddReasoner(engine);
    }
 
    private static void SetNewInput(Entity newInput)
    {
        Resource[] currentInput = store.SelectObjects(theSystem, hasInput);
        Statement input = new Statement(theSystem, hasInput, Input1);
        store.Remove(new Statement(theSystem, hasInput, currentInput[0]));
        store.Add(new Statement(theSystem, hasInput, newInput));
        Resource[] subsequentState = store.SelectObjects(Machine1, isInState);
        Statement newState = new Statement(Machine1, isInState, subsequentState[0]);
        store.Replace(new Statement(Machine1, isInState, null), newState);
    }
}
 
 

Задача была проста. Я хотел установить конечный автомат в состояние :S1 с помощью входного символа :INil, затем подать на вход символ :I1 и увидеть как статус изменится с :S1 на :S2. Поступая таким образом я пытаюсь сделать нечто необычное по сравнению с тем, для чего предполагается использовать онтологии. По большей части онтология - это статическая декларация знаний, а не динамически изменяемый набор фактов. Это значит, что онтологии допускают расширение. Среды и механизмы вывода позволяют вам добавлять информацию и, тем самым, увеличивать количество знаний. Поэтому мы можем полагаться на Semantic Web и повторно использовать данные хранящиеся там [1, 2]. Если я могу взять вашу онтологию и изменить ее так, что она будет означать нечто иное, нежели то, что вы имели ввиду, тогда результат окажется непредсказуемым. Онтологии должны быть последовательными. Если вы хотите описывать некоторые данные опираясь на онтологию - это ваше дело, и вы можете легко это организовать. На практике это означает, что вы должны вручную изменять входные сигналы и состояния. Что касается онтологии, так она просто создает среду для представления данных, и набор правил для определения того, каким должно быть следующее состояние. Это довольно мощное средство, но меня интересует вопрос: как хорошо оно будет масштабироваться.


Что нужно отметить

Существует несколько вещей на которые вы должны обратить особое внимание если вы хотите разрабатывать приложения Semantic Web используя библиотеку SemWeb. Прежде всего, это определение в онтологии пространства имен по умолчанию, и файлы определяющие правила. Обычно примеры файлов в формате N3 на сайте W3C используют следующий формат для определения пространства имен по умолчанию:

@prefix : <#> 

К сожалению такая декларация оставляет слишком много пространства для маневра в SemWeb, и не всегда можно определенно сказать каким будет реальный URI в этом случае. Обычно SemWeb опирается на местоположение, откуда был получен файл. Поэтому лучше использовать более точно определенный URL. Например:

@prefix : <http://aabs.purl.org/ontologies/2007/04/states/states.rdf#>.

Этот URL не является адресом файла, это просто URL который я раньше использовал для файлов в формате N3. Важно то, что вы должны предоставить недвусмысленный адрес, чтобы SemWeb и ее механизм вывода могли правильно отличать ресурсы друг от друга, когда вы задаете ей вопросы. Я использовал тот же самый URL в файле rules.n3, т.к. большинство объектов, на которые я ссылался, были определены в этом пространстве имен. Я так же мог бы определить новый префикс для файла states.n3 и предварить все элементы в правилах этим префиксом. Главное - не иметь URL по умолчанию, чтобы SemWeb всегда точно знала URL ресурсов на которые вы ссылаетесь.

Далее, запомните, что вам придется погрузиться глубоко в хранилище, и вручную менять состояние объектов - также как в любом приложении имеющем дело с реляционными базами данных. Хотя первоначально я был немного расстроен, т.к. я надеялся, что механизм вывода произведет все необходимые изменения самостоятельно. Увы, очевидно это не в духе Semantic Web, так что приготовьтесь интенсивно управлять системой.

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

Перевод: Михаил Навернюк
Обновлено 10.04.2008 15:39
 
 
 
© 2012 Semantictools.ru. Все права защищены.
Joomla! — свободное программное обеспечение, распространяемое по лицензии GNU/GPL.
Design by augs-burg.de & go-vista.de
 
 
     
 
   
Design by windows vista forum and energiesparlampen