Introduction to the YARS API


This document illustrates the basics of the YARS (Yet Another RDF Store) API (Application Program Interface). Here, you will learn to use the basic YARS API (YAPI) to insert and delete RDF data, pose queries, retrieve results and catch exceptions and errors.

YAPI is inspired by Sun's JDBC API. This document draws heavily from the Introduction to JDBC document at Stanford.


Overview

Call-level interfaces such as YAPI are programming interfaces allowing external access to N3 repository manipulation and update commands. They allow the integration of N3QL calls into a general programming environment by providing library routines which interface with the repository. In particular, Java based YAPI has a rich collection of routines which make such an interface extremely simple and intuitive.

Here is an easy way of visualizing what happens in a call level interface: You are writing a normal Java program. Somewhere in the program, you need to interact with a repository. Using standard library routines, you open a connection to the repository. You then use YAPI to send your N3QL code to the database, and process the results that are returned. When you are done, you close the connection.


Establishing A Connection

The first thing to do, of course, is to install Java and YARS on your working machines.

As we said earlier, before a repository can be accessed, a connection must be opened between our program (client) and the database (server). To make the connection, you may create an instance of a Connection object using:

    Connection con = DriverManager.getConnection("http://localhost:8180/yars/");

Okay, lets see what this jargon is. The parameter is the URL for the repository including the protocol (http), the server (localhost), the port number (8180). Alternatively, you can open a repository on the local file system.

    Connection con = DriverManager.getConnection("file:///tmp/yars");

That's it! The connection returned in the last step is an open connection which we will use to pass N3QL statements to the database. In this code snippet, con is an open connection, and we will use it below.


Creating a YAPI Statement

A YAPI Statement object is used to send your N3 statements to the repository, and should not to be confused with an N3/RDF statement. A YAPI Statement object is associated with an open connection, and not any single RDF statement. You can think of a YARS API Statement object as a channel sitting on a connection, and passing one or more of your N3 statements (which you ask it to execute) to the repository.

An active connection is needed to create a Statement object. The following code snippet, using our Connection object con, does it for you:

    Statement stmt = con.createStatement("context");

At this point, a Statement object exists, but it does not have an N3 statement to pass on to the repository. We learn how to do that in a following section.


Inserting/Deleting RDF Data

Executing N3 statements in YAPI varies depending on the ``intention'' of the N3 statement. Insert operations are executed using the method executeInsert, and delete operations using the method executeDelete. Notice that these commands change the state of the repository. Insert operations take as parameter a string containing N3 (Turtle) statements, or alternatively a java.io.Reader object for streaming inserts. Delete operations take as parameter an N3QL query the returns triples, which are then removed from the repository.

The following snippet has an example of an executeInsert and executeDelete statement.

    Statement stmt = con.createStatement("context");

    stmt.executeInsert("@prefix dc: <http://purl.org/dc/elements/1.1/> . \n" +
                       "<http://sw.deri.org/~knud/mov/beer.mov> dc:subject \"Beer\" . \n" +
                       "<http://www.example.org/tbr> dc:title \"an example\" .");

    stmt.executeDelete("@prefix ql: <http://www.w3.org/2004/12/ql#> . \n" +
                       "@prefix yars: <http://sw.deri.org/2004/06/yars#> . \n" +
                       "<> ql:select { { <http://www.example.org/tbr> ?p ?o . } yars:context ?c .\n" +
                       "}; ql:where { { <http://www.example.org/tbr> ?p ?o . } yars:context ?c . } .");

Since the N3 statements will not quite fit on one line on the page, we have split it into multiple strings concatenated by a plus sign (+) so that it will compile. Note that we are reusing the same Statement object rather than having to create a new one.

The executeInsert method accepts both String and Reader objects as parameters. Pass a Reader as parameter if you have a large dataset which should be transferred in a streaming fashion.


Executing Queries

As opposed to the previous section statements, a query is expected to return a set of tuples as the result, and not change the state of the repository. Not surprisingly, there is a corresponding method called executeQuery, which returns its results as a ResultSet object:

    Triple triple;

    ResultSet rs = stmt.executeQuery("@prefix ql: <http://www.w3.org/2004/12/ql#> . \n"+
                                     "@prefix yars: <http://sw.deri.org/2004/06/yars#> . \n" +
                                     "<> ql:select { ?s ?p ?o . \n" +
                                     "}; ql:where { { ?s ?p ?o . } yars:context ?c . } .");

    while (rs.next()) {
        triple = rs.getTriple();
        System.out.println("Triple: " + triple);
    }

The bag of RDF triples (or RDF lists, depending on the ql:select clause) resulting from the query are contained in the variable rs which is an instance of ResultSet. A set is of not much use to us unless we can access each row and the attributes in each row. The ResultSet provides a cursor to us, which can be used to access each row in turn. The cursor is initially set just before the first row. Each invocation of the method next causes it to move to the next row, if one exists and return true, or return false if there is no remaining row.


Handling Errors with Exceptions

The truth is errors always occur in software programs. Often, database programs are critical applications, and it is imperative that errors be caught and handled gracefully.

The client (program) accessing a server (repository) needs to be aware of any errors returned from the server. YAPI give access to such information by providing two levels of error conditions: N3Exception and N3Warning. N3Exceptions are Java exceptions which, if not handled, will terminate the application. N3Warnings are subclasses of N3Exception, but they represent nonfatal errors or unexpected conditions, and as such, can be ignored.

In Java, statements which are expected to ``throw'' an exception or a warning are enclosed in a try block. If a statement in the try block throws an exception or a warning, it can be ``caught'' in one of the corresponding catch statements. Each catch statement specifies which exceptions it is ready to ``catch''.

Here is an example of catching an N3Exception:

    try {
        stmt.executeInsert("<http://sw.deri.org/~knud/mov/beer.mov> dc:subject \"Beer\" .");
    } catch (N3Exception ex) {
        System.err.println("N3Exception: " + ex.getMessage()) ;
    }

In this case, an exception is thrown because the namespace dc is not defined using the @prefix declaration. Since the N3 string cannot be parsed, an N3Exception is thrown. The output in this case would be:

    org.semanticweb.yars.api.N3Exception: Response code 500

SQLWarnings can be retrieved from Connection objects, Statement objects, and ResultSet objects. Each only stores the most recent N3Warning. So if you execute another statement through your Statement object, for instance, any earlier warnings will be discarded. Here is a code snippet which illustrates the use of N3Warnings:

    ResultSet rs = stmt.executeQuery("@prefix ql: <http://www.w3.org/2004/12/ql#> . \n"+
                                          "@prefix yars: <http://sw.deri.org/2004/06/yars#> . \n" +
                                          "<> ql:select { ?s ?p ?o . \n" +
                                          "}; ql:where { { ?s ?p ?o . } yars:context ?c . } .");
    N3Warning warn = stmt.getWarnings();
    if (warn != null)
        System.out.println("Message: " + warn.getMessage());

N3Warnings (as opposed to N3Exceptions) are actually rather rare.


Sample Code and Compilation Instructions

Hopefully, by now you are familiar enough with YAPI to write serious code. In the following you find a simple program which ties all the ideas in the tutorial together.

Don't forget to add yars-api.jar to your classpath that you can make use of the classes described in this document.

import org.semanticweb.yars.api.Connection;
import org.semanticweb.yars.api.DriverManager;
import org.semanticweb.yars.api.Statement;
import org.semanticweb.yars.api.ResultSet;
import org.semanticweb.yars.api.N3Exception;

public class AccessYARS {
    public static String YARS_URL = "http://localhost/yars";

    public static void main(String[] args) {
	try {
	    Connection con = DriverManager.getConnection(YARS_URL);
	    Statement stmt = con.createStatement("context");
	    
	    stmt.executeInsert("@prefix dc: <http://purl.org/dc/elements/1.1/> . \n" +
			       "<http://sw.deri.org/~knud/mov/beer.mov> dc:subject \"Beer\" . \n" +
			       "<http://www.example.org/tbr> dc:title \"an example\" .");

	    stmt.executeDelete("@prefix ql: <http://www.w3.org/2004/12/ql#>\n" +
	                       "@prefix yars: <http://sw.deri.org/2004/06/yars#> . \n" +
			       "<> ql:select { { <http://www.example.org/tbr> ?p ?o . } yars:context ?c . \n" +
			       "}; ql:where { { <http://www.example.org/tbr> ?p ?o . } yars:context ?c . } .");
			
	    ResultSet rs = stmt.executeQuery("@prefix ql: <http://www.w3.org/2004/12/ql#> . \n"+
	                                     "@prefix yars: <http://sw.deri.org/2004/06/yars#> . \n" +
					     "<> ql:select { " +
					     "  ?s ?p ?o . " +
					     "}; ql:where { " +
					     "  { ?s ?p ?o . } yars:context ?c . } .");

	    while (rs.next()) {
		System.out.println(rs.getTriple());
	    }

	    rs.close();
	    stmt.close();
	    con.close();
	} catch (N3Exception nex) {
	    System.err.println(nex.getMessage());
	}
    }
}

Most of this document was taken from the "Introduction to JDBC" document from Widom's and Ullman's CS145 class. Adapted by Andreas Harth to describe YAPI instead of JDBC. $Id: java-api.html 2339 2006-02-24 12:31:00Z aharth $