Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Design

Graphs Versus Objects


Cooking with Graphs

Now let's address the same problem with graphs. We implemented the graphs using the Web Ontology Language (OWL)—an expressive knowledge representation language based on the Resource Description Framework (RDF). Based on XML, RDF connects information using a "triple"—a subject, predicate, and object. This basic approach can represent all kinds of knowledge constructs such as the class structure ("Transaction hasBuyer Person"), instance data ("toaster hasCost $12"), and constraints ("PurchasableItem contains 1 Manufacturer"). Usually, the main data model, when expressed in OWL, is called an "ontology".

Figure 2 illustrates the graph. There is no drawing standard for graphs but the diagram adheres to common practices. The ovals represent classes (similar to OO classes), the thin named lines represent relationships, and the rectangles represent actual data. The numbers (1) and types (string) indicate restrictions placed on a relationship or type. Relationships can be represented in two ways—object properties that link two objects (classes) and datatype properties that link a data item with an object.

Figure 2: Graph model.

Here is an extract of the ontology in abbreviated RDF/XML format. We've used TopBraid Composer (www.topbraidcomposer.com) but Protege (protege.stanford.edu) or other editors would work just as well:

 
<?xml version="1.0"?>
<rdf:RDF
    xmlns="http://www.example.com/storeOnt#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
  xml:base="http://www.example.com/storeOnt">
  <owl:Ontology rdf:about="">
    <owl:versionInfo rdf:datatype="http://www.w3.org/2001/XMLSchema#string">Graphs and Objects</owl:versionInfo>
  </owl:Ontology>
  <owl:Class rdf:ID="PurchasableItem">
    <rdfs:subClassOf>
      <owl:Restriction>
        <owl:onProperty>
          <owl:DatatypeProperty rdf:ID="hasCost"/>
        </owl:onProperty>
        <owl:allValuesFrom rdf:resource="http://www.w3.org/2001/XMLSchema#decimal"/>
      </owl:Restriction>
    </rdfs:subClassOf>
    ....
  </owl:Class>
</rdf:RDF>


Switching to graphs, let's apply our business acumen and create an online store where the knowledge representation is in the data instead of the code. There is no need to create the representation in the code itself. The Java code below relies on Jena (jena.sourceforge .net), the most popular open-source package for creating Semantic Web solutions currently available.

First, we'll load our graph model, which defines the classes and properties in Figure 2. To view the full ontology, go to graphsvsobjects .blogspot.com.

 
OntModelSpec s = new OntModelSpec(OntModelSpec.OWL_DL_MEM_RULE_INF);
ntModel m = ModelFactory.createOntologyModel(s);


Second, based on this graph, we can begin to add the items and related facts. Here we create instances; they could have been contained in the original ontology. This approach allows you to see both methods. Again, this is just a subset of the code. The full suite is available online:


// Matt ...
Resource seller = m.createResource(defaultNS + "mattFisher");
m.add(seller, RDF.type, m.getResource(defaultNS + "Person"));
m.add(seller, RDFS.label, m.createTypedLiteral("Matt Fisher", XSDDatatype.XSDstring));
// ... is selling his special toaster ...
Resource toaster = m.createResource(defaultNS + "shinyToaster");
m.add(toaster, RDFS.label, m.createTypedLiteral("High-wolf shiny toaster", XSDDatatype.XSDstring));
m.add(toaster, RDF.type, m.getResource(defaultNS + "PurchasableItem"));
Literal manufacturer = m.createTypedLiteral("Dualit",
XSDDatatype.XSDstring);
m.add(toaster, m.getProperty(defaultNS, "hasManufacturer"), manufacturer); // similar code follows for hasCost

// John ...
Resource john = m.createResource(defaultNS + "johnHebeler");
m.add(john, RDF.type, m.getResource(defaultNS + "Person"));
m.add(john, RDFS.label, m.createTypedLiteral("Matt Fisher", XSDDatatype.XSDstring));
// ... is buying the toaster ...
Resource sale = m.createResource(defaultNS + "toasterSale");
m.add(sale, RDF.type, m.getResource(defaultNS + "Transaction"));
m.add(sale,    m.getProperty(defaultNS, "containsItem"), toaster); // similar code follows for hasBuyer, hasSeller
// ... very soon!
Literal sellingDate =  m.createTypedLiteral("2008-03-24T10:00:00", XSDDatatype.XSDdateTime);
m.add(sale, m.getProperty(defaultNS, "hasSellDate"), sellingDate);
 


At this point, we're ready for real queries:


// Now, how many items has John bought? (
//   without using a special purpose query language)
ResIterator junk = m.listSubjectsWithProperty(m.getProperty(defaultNS, "hasBuyer"), john);
   int count = 0;
   while (junk.hasNext()) {
       count++;
       junk.next();
   }
  System.out.println("John has purchased " + count + "item(s)");
   // Now, what has John bought? (using SPARQL)
String queryString = "PREFIX rdf: <"m.getNsPrefixURI("rdf")"> " +
// PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
     "PREFIX rdfs: <" m.getNsPrefixURI("rdfs") "> " 
// PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>   

     "PREFIX store: <" defaultNS "> "
// PREFIX store: <http://www.example.com/storeOnt#>
       "SELECT ?label "  // SELECT ?label
       "WHERE { "        // WHERE {
        "       ?trans rdf:type store:Transaction . "
//         ?trans rdf:type store:Transaction .
        "       ?trans store:containsItem ?item . " 
//         ?trans store:containsItem ?item .
                ?item rdfs:label ?label . " 
//         ?item rdfs:label ?label .  " } ";
//       }
// Take the SPARQL query and, using Jena's ARQ library for SPARQL
// build and execute the query
   Query query = QueryFactory.create(queryString) ;
   QueryExecution qexec = QueryExecutionFactory.create(query, m) ;
       try {
         ResultSet results = qexec.execSelect();
         System.out.println("John has bought:");
         while (results.hasNext())
         {
           // Print out each item's label, stripping off 
           // the XSD type information
      QuerySolution soln = results.nextSolution();
      String labelString = soln.getLiteral("label").toString();
      int index = labelString.lastIndexOf("^^");
      System.out.println("   " + labelString.substring(0, index));
      }
    }
   finally {
  qexec.close();
 }


The resulting output is:

John has purchased 1 item(s)
John has bought:
    High-wolf shiny toaster

Our queries are basic and don't exploit all the graph properties—but they easily could. Integrating other graphs would be straightforward. If the graphs were based on a similar representation, we would not need to make any changes to our program. If the graphs were based on a different representation, we have two choices. We could make program changes similar to objects or, better yet, use a rule language such as the Semantic Web Rule Language (SWRL) to align the differences. For example, a rule could take advantage of the OWL's equivalentClass construct. equivalentClass equates classes ("Automobile equivalentClass Car") while OWL's sameAs construct equates instances ("James sameAs Jim"). A rule representation maintains separation between the KR and its various translations for other representations. And with all this fun, we are not even touching on advanced constructs such as inference and advanced queries. This is only the beginning.

"Hey, that's a lot of code", you say and, well, you are right. Much of this is structural and could be contained in an encapsulated programming class. Alternatively, all this data creation could be serialized in a file and merely read into the application, but this example provides a clearer handle as to what is happening behind the mirror. What you paid for in keystrokes pays off as we enter the agile part—the evolution.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.