Skip to content

Sail Ouplementation

sharispe edited this page Aug 7, 2012 · 26 revisions

<dependency>
   <groupId>com.tinkerpop.blueprints</groupId>
   <artifactId>blueprints-graph-sail</artifactId>
   <version>??</version>
</dependency>

Sail is an RDF triple/quad store interface developed by OpenRDF. Any database the implements the Sail interfaces properly is a valid RDF triple/quad store. A graph database is a great way to build a triple/quad store because its possible to mix indexing and graph traversals to solve the RDF “pattern match” problem. To go from Graph to Sail, simply use GraphSail. GraphSail requires an IndexableGraph (e.g. TinkerGraph, Neo4jGraph, OrientGraph). The examples below use TinkerGraph and expose it as a GraphSail and thus, a Sail. While some basic examples are provided, please refer to the OpenRDF Sail documentation for a complete review of the framework.

NOTE ON TRANSACTION SAFETY: as of Blueprints 2.0, there are issues in the Neo4jGraph and OrientGraph implementations which affect the transaction safety of GraphSail (see here, and here), among other applications. There is a workaround for the Neo4jGraph issue (see below), while the OrientGraph issue has yet to be resolved. In the meantime, please contact us if you encounter any problems, and we will do our best to come up with a targeted solution.

To ensure the transaction safety of Neo4jGraph, use the setCheckElementsInTransaction method, e.g.

Neo4jGraph graph = new Neo4jGraph("/path/to/db");
graph.setCheckElementsInTransaction(true);
Sail sail = new GraphSail(graph);
sail.initialize();

Basic Statement Handling

A statement in RDF is a triple or quad. The components of a statement are called: subject, predicate, object, and graph/context. The subject can be a URI or blank node. The predicate can only be a URI. The object can be a URI, blank node, or literal. Finally, the graph (or context) can be a URI or blank node.

TinkerGraph graph = new TinkerGraph();
Sail sail = new GraphSail(graph);
sail.initialize();
SailConnection sc = sail.getConnection();
ValueFactory vf = sail.getValueFactory();
sc.addStatement(vf.createURI("http://tinkerpop.com#1"), vf.createURI("http://tinkerpop.com#knows"), vf.createURI("http://tinkerpop.com#3"), vf.createURI("http://tinkerpop.com"));
sc.addStatement(vf.createURI("http://tinkerpop.com#1"), vf.createURI("http://tinkerpop.com#name"), vf.createLiteral("marko"), vf.createURI("http://tinkerpop.com"));
sc.addStatement(vf.createURI("http://tinkerpop.com#3"), vf.createURI("http://tinkerpop.com#name"), vf.createLiteral("josh"), vf.createURI("http://tinkerpop.com"));

System.out.println("get statements: ?s ?p ?o ?g");
CloseableIteration<? extends Statement, SailException> results = sc.getStatements(null, null, null, false);
while(results.hasNext()) {
    System.out.println(results.next());
}

System.out.println("\nget statements: http://tinkerpop.com#3 ?p ?o ?g");
results = sc.getStatements(vf.createURI("http://tinkerpop.com#3"), null, null, false);
while(results.hasNext()) {
    System.out.println(results.next());
}

sc.close();
graph.shutdown();
sail.shutDown();
get statements: ?s ?p ?o ?g
(http://tinkerpop.com#1, http://tinkerpop.com#knows, http://tinkerpop.com#3) [http://tinkerpop.com]
(http://tinkerpop.com#3, http://tinkerpop.com#name, "josh") [http://tinkerpop.com]
(http://tinkerpop.com#1, http://tinkerpop.com#name, "marko") [http://tinkerpop.com]

get statements: http://tinkerpop.com#3 ?p ?o ?g
(http://tinkerpop.com#3, http://tinkerpop.com#name, "josh") [http://tinkerpop.com]

Using SPARQL

SPARQL is the standard query language for RDF stores. OpenRDF provides a SPARQL query engine that can be used over any Sail. An example is provided below. Assume that the same statements from the previous example exist in the GraphSail below.

SPARQLParser parser = new SPARQLParser();
CloseableIteration<? extends BindingSet, QueryEvaluationException> sparqlResults;
String queryString = "SELECT ?x ?y WHERE { ?x <http://tinkerpop.com#knows> ?y }";
ParsedQuery query = parser.parseQuery(queryString, "http://tinkerPop.com");

System.out.println("\nSPARQL: " + queryString);
sparqlResults = sc.evaluate(query.getTupleExpr(), query.getDataset(), new EmptyBindingSet(), false);
while (sparqlResults.hasNext()) {
    System.out.println(sparqlResults.next());
}
SPARQL: SELECT ?x ?y WHERE { ?x <http://tinkerpop.com#knows> ?y }
[y=http://tinkerpop.com#3;x=http://tinkerpop.com#1]

Moving Between Sail and Graph

Its possible to get the Graph that is being modeled as a Sail and work from the Blueprints API perspective. In this way, its possible to leverage the tools provided for both Sail and Blueprints Graph.

Graph graph = ((GraphSail) sail).getBaseGraph();
System.out.println();
for (Vertex v : graph.getVertices()) {
    System.out.println("------");
    System.out.println(v);
    for (String key : v.getPropertyKeys()) {
        System.out.println(key + "=" + v.getProperty(key));
    }
}
for (Edge e : graph.getEdges()) {
    System.out.println("------");
    System.out.println(e);
    for (String key : e.getPropertyKeys()) {
        System.out.println(key + "=" + e.getProperty(key));
    }
}
------
v[2]
value=http://tinkerpop.com#3
kind=uri
------
v[1]
value=http://tinkerpop.com#1
kind=uri
------
v[0]
value=urn:com.tinkerpop.blueprints.pgm.oupls.sail:namespaces
------
v[6]
value=josh
kind=literal
------
v[4]
value=marko
kind=literal
------
e[3][1-http://tinkerpop.com#knows->2]
cp=U http://tinkerpop.com U http://tinkerpop.com#knows
c=U http://tinkerpop.com
p=U http://tinkerpop.com#knows
------
e[7][2-http://tinkerpop.com#name->6]
cp=U http://tinkerpop.com U http://tinkerpop.com#name
c=U http://tinkerpop.com
p=U http://tinkerpop.com#name
------
e[5][1-http://tinkerpop.com#name->4]
cp=U http://tinkerpop.com U http://tinkerpop.com#name
c=U http://tinkerpop.com
p=U http://tinkerpop.com#name

Inferencing support

Blueprints Sail implements NotifyingSail, produces InferencerConnections, and does all of the right things under the hood to support Sesame-based reasoning/inferencing tools such as ForwardChainingRDFSInferencer, with no extra plumbing required. For example:

 Sail reasoner = new ForwardChainingRDFSInferencer(new GraphSail(new TinkerGraph()));
 reasoner.initialize();

How it works: a reasoner such as ForwardChainingRDFSInferencer is expected to listen for RDF statements added to or removed from the base Sail (here: an instance of GraphSail) and to manage a collection of “inferred” statements accordingly. The inferred statements are stored along with the explicitly asserted RDF statements in the base Sail. In Blueprints Sail, these statements are marked with a special property, inferred, which when present has the boolean value true, so you can see which edges “you” have added, and which edges the reasoner has added, when traversing the underlying Property Graph. The following is a more detailed example:

Resource beijing = new URIImpl("http://example.org/things/Beijing");
Resource city = new URIImpl("http://example.org/terms/city");
Resource place = new URIImpl("http://example.org/terms/place");

Graph graph = new TinkerGraph();
Sail reasoner = new ForwardChainingRDFSInferencer(new GraphSail(graph));
reasoner.initialize();

try {
    SailConnection c = reasoner.getConnection();
    try {
        c.addStatement(city, RDFS.SUBCLASSOF, place);
        c.addStatement(beijing, RDF.TYPE, city);
        c.commit();

        CloseableIteration<? extends Statement, SailException> i
                = c.getStatements(beijing, null, null, true);
        try {
            while (i.hasNext()) {
                System.out.println("statement " + i.next());
            }
        } finally {
            i.close();
        }
    } finally {
        c.close();
    }
} finally {
    reasoner.shutDown();
}

graph.shutdown();

Output of the example:

statement (http://example.org/things/Beijing, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/2000/01/rdf-schema#Resource)
statement (http://example.org/things/Beijing, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://example.org/terms/place)
statement (http://example.org/things/Beijing, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://example.org/terms/city)