Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Create Scalable Semantic Applications with Database-Backed RDF Stores : Page 3

Store your RDF triples in a database for faster performance and greater scalability.

Managing Jena RDF Databases
Now that you've explored some of the general RDF database considerations and options, here's a more in-depth look at using Jena. A recent DevX article described Jena well. The Model interface is a key abstraction in Jena. A Jena Model represents an RDF graph, which is composed of a set of statements, each of which is an RDF triple. There are several implementations of the Model interface, each of which works with a different type of model, such as in-memory, file based, inferencing, and database backed. This article focuses on the database-backed implementation.

Figure 4. Jena Model Abstraction: These simple classes provide an abstraction on top of the Jena API. They encapsulate access to the Jena APIs and are used by the SWT components to manipulate the underlying Jena data structures.
A Jena database can store multiple models, typically storing each model in its own set of tables in the database. The ModelRDB class implements database-backed models; you should create instances via the ModelFactory class. You can see how to accomplish this by exploring what happens when a user selects a named database connection and clicks the Connect button (illustrated in Figure 1) to connect to a Jena database. Although Jena will create the necessary tables to represent models in a database, you need to create the database itself ahead of time using the database's native tools.

All the screen elements in the example Jena Model Manager application manipulate an abstraction of databases, connections, and Jena Models. These classes in turn wrap and manipulate the Jena API to perform the user's actions. To distinguish the Jena Model interface from the Model Manager representation, this article uses the class name "AppModel" to refer to the application's Model representation. Figure 4 illustrates this simple representation as a class diagram.

When a user selects a named database connection from the connection list and clicks the Connect button, a listener event fires that invokes the connect method of the selected Connection object. The Connection object, in turn, uses the Jena API to connect to a Jena database and verify the state of the connection as shown below:

// from com/devx/tools/jena/manager/domain/Connection.java import com.hp.hpl.jena.db.DBConnection; import com.hp.hpl.jena.db.IDBConnection; public Connection { private String driver; private String url; private String user; private String password; private String databaseType; // The underlying Jena database connection private IDBConnection conn; ... public void connect() { Class.forName(driver); conn = new DBConnection(url, user, password, databaseType); testConnection(); } private void testConnection() { conn.getAllModelNames(); } ... }

As is typical in JDBC, the code loads the database driver into the classpath, so that subsequent requests to the DriverManager can construct instances of the specified driver. Next, it creates a Jena DBConnection object to represent the database connection parameters. Constructing a Jena DBConnection object simply creates a connection specification—it doesn't attempt to connect to the underlying database. Invoking the getAllModelNames method on the connection forces the connection attempt to the database so that errors in the connection parameters can be uncovered early.

Initially, the database will contain no models when the user clicks the Models tab shown in Figure 2. When a user clicks the Create Model button a listener fires that prompts the user to enter a name for the new model, constructs a new AppModel object, and invokes its createModel method. This method in turn uses the Jena API to create an empty model in the database as shown below:

// from com/devx/tools/jena/manager/domain/AppModel.java import com.hp.hpl.jena.db.IDBConnection; import com.hp.hpl.jena.db.ModelRDB; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelMaker; public class AppModel { private final Database database; private final String name; public AppModel(Database database, String name) { this.database = database; this.name = name; } public void createModel() { ModelRDB.createModel(getJenaConnection(), name); } private IDBConnection getJenaConnection() { return database.getConnection().getJenaConnection(); } ... }

Subsequently, when users select the Load link next to the newly created model, they see a prompt where they can specify an RDF file to load and a base URI for the data to be loaded. That information is then passed to the AppModel's load method, which uses the Jena API to load the data into the underlying model as shown below. The load operation has been wrapped with a Jena transaction to improve performance and provide more reliable handling of error conditions:

// from com/devx/tools/jena/manager/domain/AppModel.java public class Model { ... public void load(InputStream data, String baseUri) { ModelMaker maker = ModelFactory.createModelRDBMaker( getJenaConnection()); Model model = maker.openModel( name, false); model.begin(); try { model.read(data, baseUri); model.commit(); } catch (Throwable e) { model.abort(); throw new RuntimeException(e); } } ... }

This persistent model is now populated with data and can be consumed just like any other Jena model through the Jena or ARQ (for SPARQL queries) APIs. The Query tab shown in Figure 3 lets users select one or more models and execute SPARQL queries against the selected models. After a user clicks the Execute button, the following code adds all the selected models to an application QueryExecutor object (see Listing 1) that nests the selected models as submodels under a composite parent, and then executes the query against the composite:

// from com/devx/tools/jena/manager/views/QueryTab.java public class QueryTab { ... class ExecuteButtonListener extends SelectionAdapter { @Override public void widgetSelected(SelectionEvent e) { resultsTable.removeAll(); Collection<String> selectedModels = Arrays.asList(modelsList.getSelection()); QueryExecutor executor = new QueryExecutor(); for (AppModel appModel : Application.database.listModels()) { if (selectedModels.contains(appModel.getName())) { executor.addModel(Application.database, appModel); } } ResultSet results = executor.execute(queryTextBox.getText()); // Format results ... } } ... }

There are other more efficient approaches for doing this that are beyond the scope of this article. But if you are looking for ways to further optimize complex queries across multiple models check out the com.hp.hpl.jena.graph.compose package in the Jena Javadocs.

As you can see the Jena API for managing RDF databases is very straightforward and easy to use. The guts of the Jena Model Manager application you have been exploring are very small and provide a nice example of how the Jena API can be used to manage Jena databases and models. And as an added benefit the running application available for download will hopefully provide more visibility and ease of use for managing Jena RDF databases.

Although this introduction to RDF databases has been relatively brief, you have seen a high-level overview of the various RDF-database tools and technologies available, as well as more specific examples that use the Jena API to create, load, and query Jena RDF databases. You can apply these same concepts to other RDF databases and APIs.

Author's Note: Dave Reynolds and Andy Seaborne from the Jena team graciously contributed thoughts and suggestions to this article, and I am very thankful for their input.

Related Resources

Rod Coffin is an agile technologist at Semantra, helping to develop an innovative natural language ad hoc reporting platform. He has many years of experience mentoring teams on enterprise Java development and agile practices and has written several articles on a range of topics from Aspect-Oriented Programming to EJB 3.0. Rod is a frequent speaker at user groups and technology conferences and can be contacted via his home page.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.