Tuesday, 4 June 2013

Does your application understand you? Hello World with microOntorion SDK.

Nature likes symmetry. If you interact with someone, usually you expect the interaction from the other side. The same situation is in the case of application. A huge effort is put on developing programmes, that will not only process the input, but also understand it (or at least try to understand). That is the point of ontology matters and semantic technology.
Now, as a programmer, you can participate in the semantic world of applications. This post will show how to use ontology in your application with help of microOntorion.

microOntorion SDK

microOntorion is an end point to Ontorion environment. It makes all reasoning locally, on your computer. It is provided as a .dll library.

Before you start working on your semantic application, you need to add reference to microOntorion library.

Using directives may be helpful.
using Ontorion.MicroOntorion;
using Ontorion;

Initialization


Lets create in Main function microOntorion object, that allows to import ontology and query against it:

MicroOntorion oep = new MicroOntorion();

Now, we can load ontology. The source ontology should be prepared as CNL sentences. The easiest way to do this is to use Fluent Editor 2. It has auto-complete feature that ensures you that your ontology and queries are valid grammar sentences. Fluent Editor 2 writes ontology as *.encnl files, which can you stream directly to microOntorion.
There is also possibility to construct sentences as string and load in that form to microOntorion library.
We will utilize the first method.
Lets construct simple ontology (in Fluent Editor 2) and save as myOntology.encnl file.


Comment: 'Sample IT ontology'.

Server-1 is a server and hosts Application-1.
Server-2 is a server and hosts Application-2.

Server-1 has-ip-address equal-to '173.194.70.102'.
Server-1 has-ip-address equal-to '173.194.70.103'.
Server-1 has-ip-address equal-to '173.194.70.104'.

Server-2 has-ip-address equal-to '206.190.36.45'.

Application-1 is an application that serves Customer-1 and serves Customer-2.
Application-3 is an application that serves Customer-3.

Application-1 has-name equal-to 'Fluent Editor'.
Application-1 has-name equal-to 'Fluent Editor 2'.
Application-3 has-name equal-to 'Ontorion'.

Customer-1 is a customer and has-severity critical.
Customer-2 is a customer and has-severity medium.
Customer-3 is a customer and has-severity low.

X is-hosted-on Y if-and-only-if Y hosts X.
Every application must be-hosted-on server.

Part-2: 'Incidents'.
Incident-1 has-reported-date equal-to 2012-01-01 and was-reported-by Operator-1.
Incident-1 has-affected Server-1.

Incident-2 has-reported-date equal-to 2012-01-02 and was-reported-by Operator-1.
Incident-2 has-affected Application-2.


Now we can import our ontology to microOntorion:

try
{
    using (FileStream ontologyFileStream = new FileStream("../../../myOntology.encnl", FileMode.Open, FileAccess.Read))
    {
        // load ontology from file
        microOntorion.Load(ontologyFileStream);
    }
}
catch (Ontorion.ConsistencyException e)
{
    // when exception has been thrown check if knowledge has been incosistent
    foreach (var expl in microOntorion.GetExplanations())
    {
        PrintResults(expl);
    }
    return;
}
catch (Exception e)
{
    return;
}

Function Load makes also some preprocessing and your application processes ontology only once.
Function GetExplanations provides some information about sources of errors, that occurred due to ontology preprocessing (e.g. ontology is inconsistent).
Function PrintResults just prints results:

private static void PrintResults(List<string> result)
{
    string res = "";
    foreach (var item in result)
    {
        res += item + " ";
    }
    Console.WriteLine(res);
}

Asking query

At this moment we have create MicroOntorion object and ontology is loaded. It is time to ask some question. Lets prepare it:

// build your query
string query = String.Format("Who-Or-What is-hosted-on server that has-ip-address equal-to '173.194.70.102' ?");

Get results of this query:

// get superconcepts returned by the query
List<string> superconcepts = microOntorion.GetSuperconceptsOf(query);
Console.Write("Superconcepts: ");
PrintResults(superconcepts);

// get superconcepts returned by the query
List<string> subconcepts = microOntorion.GetSubconceptsOf(query);
Console.Write("Subconcepts: ");
PrintResults(subconcepts);

// get all instances returned by the query
List<string> instances = microOntorion.GetInstances(query, int.MaxValue);
Console.Write("Instances: ");
PrintResults(instances);

GetSubconceptsOf, GetSuperconceptsOf and GetInstances returns subconcepts, superconcepts and instances respectively that satisfy query.

Attributes

We can also ask for attributes of specified instances, e.g. Application-1, that were returned from the previous function. Application-1 has name attribute. Lets get this attribute:

// get names of the applications (as attributes)
foreach (var item in instances)
{
    Console.WriteLine("{0} has name(s): {1}", item, string.Join(", ", microOntorion.GetAttributeValues(item, "have-name").ToArray()));
}

OWLAPI has some problems with extracting attributes from complex sentences. It is recommended to attach attributes to instances in separate sentence.

Requirements

There is also possibility to ask for requirements. Lets get all requirements for application concept.

// get all modalities for application concept.
var res = microOntorion.GetRequirements("application");
Console.WriteLine("Requirements for application concept:");
foreach (var item in res)
{
    Console.WriteLine("- {0}", item.Key);
    foreach (var req in item.Value)
    {
        Console.WriteLine("--- {0}", req);
    }
}

MicroOntorion.GetRequirements supports now only simple requirements:
Every <C> <modality><R><D>
where:
<C> is concept, e.g. application,
<modality> is modality such as must, should, ... etc.,
<R> is role, e.g. be-hosted-on,
<D> is any ending of sentence, can be quite complex

The result of querying our ontology:

Superconcepts:
Subconcepts:
Instances: Application-1
Application-1 has name(s): Fluent Editor 2, Fluent Editor
Requirements for application concept:
- MUST
--- is-hosted-on a server
Press any key to continue . . .

Whole source code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ontorion.MicroOntorion;
using System.IO;
using Ontorion;

namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            MicroOntorion microOntorion = new MicroOntorion();
            try
            {
                using (FileStream ontologyFileStream = new FileStream("../../../myOntology.encnl", FileMode.Open, FileAccess.Read))
                {
                    // load ontology from file
                    microOntorion.Load(ontologyFileStream);

                    // build your query
                    string query = String.Format("Who-Or-What is-hosted-on server that has-ip-address equal-to '173.194.70.102' ?");

                    // get superconcepts returned by the query
                    List<string> superconcepts = microOntorion.GetSuperconceptsOf(query);
                    Console.Write("Superconcepts: ");
                    PrintResults(superconcepts);

                    // get superconcepts returned by the query
                    List<string> subconcepts = microOntorion.GetSubconceptsOf(query);
                    Console.Write("Subconcepts: ");
                    PrintResults(subconcepts);

                    // get all instances returned by the query
                    List<string> instances = microOntorion.GetInstances(query, int.MaxValue);
                    Console.Write("Instances: ");
                    PrintResults(instances);


                    // get names of the applications (as attributes)
                    foreach (var item in instances)
                    {
                        Console.WriteLine("{0} has name(s): {1}", item, string.Join(", ", microOntorion.GetAttributeValues(item, "have-name").ToArray()));
                    }

                    // get all modalities for application concept.
                    var res = microOntorion.GetRequirements("application");
                    Console.WriteLine("Requirements for application concept:");
                    foreach (var item in res)
                    {
                        Console.WriteLine("- {0}", item.Key);
                        foreach (var req in item.Value)
                        {
                            Console.WriteLine("--- {0}", req);
                        }
                    }

                }
            }
            catch (Ontorion.ConsistencyException e)
            {
                // when exception has been thrown check if knowledge has been incosistent
                foreach (var expl in microOntorion.GetExplanations())
                {
                    PrintResults(expl);
                }
                return;
            }
            catch (Exception e)
            {
                return;
            }
        }

        private static void PrintResults(List<string> result)
        {
            string res = "";
            foreach (var item in result)
            {
                res += item + " ";
            }
            Console.WriteLine(res);
        }
    }
}

---

You can download microOntorion SDK here.



*) FluentEditor 2, ontology editor, is a comprehensive tool for editing and manipulating complex ontologies that uses Controlled Natural Language. Fluent editor provides one with a more suitable for human users alternative to XML-based OWL editors. It's main feature is the usage of Controlled English as a knowledge modeling language. Supported via Predictive Editor, it prohibits one from entering any sentence that is grammatically or morphologically incorrect and actively helps the user during sentence writing. The Controlled English is a subset of Standard English with restricted grammar and vocabulary in order to reduce the ambiguity and complexity inherent in full English.