SDB JavaAPI


The Apache Jena SDB module has been retired and is no longer supported.
The last release of Jena with this module was Apache Jena 3.17.0.


This page describes how to use SDB from Java.

Code examples are in src-examples/ in the SDB distribution.

Concepts

  • Store
  • SDBFactory
  • SDBConnection

SDB loads and queries data based on the unit of a Store. The Store object has all the information for formatting, loading and accessing an SDB database. One database or table space is one Store. Store objects are made via the static method of the StoreFactory class.

SDBConnection wraps the underlying database connection, as well as providing logging operations.

  • StoreDesc

A store description is the low level mechanism for describing stores to be created.

  • DatasetStore
  • GraphSDB

Two further class are not immediately visible because they are managed by the SDBFactory which creates the necessary classes, such as Jena models and graphs.

An object of class DatasetStore represents an RDF dataset backed by an SDB store. Objects of this class trigger SPARQL queries being sent to SDB.

The class GraphSDB provides the adapter between the standard Jena Java API and an SDB store, either to the default graph or one of the named graphs. The SDBFactory can also create Jena Models backed by such a graph.

Obtaining the Store

A store is build from a description. This can be a description in file as a Jena assembler or the application can build the store description programmatically.

From a configuration file

The stored description is the only point where the specific details of store are given. This includes connection information, the database name, and database type. It makes sense to place this outside the code. That way, the application can be switched between different databases (e.g. testing and production) by changing a configuration file, and not the code, which would require recompilation and a rebuild.

To create a Store from a store assembler

  Store store = SDBFactory.connectStore("sdb.ttl") ;

The assembler file has two parts, the connection details and the store type.

 @prefix rdfs:     <http://www.w3.org/2000/01/rdf-schema#> .
 @prefix rdf:      <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
 @prefix ja:       <http://jena.hpl.hp.com/2005/11/Assembler#> .
 @prefix sdb:      <http://jena.hpl.hp.com/2007/sdb#> .

 _:c rdf:type sdb:SDBConnection ;
     sdb:sdbType        "derby" ;
     sdb:sdbName        "DB/SDB2" ;
     sdb:driver         "org.apache.derby.jdbc.EmbeddedDriver" ;
     .

 [] rdf:type sdb:Store ;
     sdb:layout         "layout2" ;
     sdb:connection     _:c ;
    .

See the full details of store description files for the options.

In Java code

The less flexible way to create a store description is to build it in Java. For example:

   StoreDesc storeDesc = new StoreDesc(LayoutType.LayoutTripleNodesHash,
                                       DatabaseType.Derby) ;
   JDBC.loadDriverDerby() ;
   String jdbcURL = "jdbc:derby:DB/SDB2";
   SDBConnection conn = new SDBConnection(jdbcURL, null, null) ;
   Store store = SDBFactory.connectStore(conn, storeDesc) ;

Database User and Password

The user and password for the database can be set in explicitly in the description file but it is usually better to use an environment variable or Java system property because this avoid writing use and password in a file.

Environment variable: SDB_USER Java property: jena.db.user

Environment variable: SDB_PASSWORD Java property: jena.db.password

Connection Management

Each store has a JDBC connection associated with it.

In situations where such connections are managed externally, the store object can be created and used within a single operation.

A Store is lightweight and does not perform any database actions when created, so creating and releasing them will not impact performance. Closing a store does not close the JDBC connection.

Similarly, a SDBConnection is lightweight and creation does not result in any database or JDBC connection actions.

The store description can be read from the same file because any SDB connection information is ignored when reading to get just the store description. The store description can be kept across store creations:

  storeDesc = StoreDesc.read("sdb.ttl") ;

then used with an JDBC connection object passed from the connection container:

    public static void query(String queryString,
                             StoreDesc storeDesc,
                             Connection jdbcConnection)
    {
        Query query = QueryFactory.create(queryString) ;

        SDBConnection conn = SDBFactory.createConnection(jdbcConnection) ;

        Store store = SDBFactory.connectStore(conn, storeDesc) ;

        Dataset ds = SDBFactory.connectDataset(store) ;
        try(QueryExecution qe = QueryExecutionFactory.create(query, ds)) {
            ResultSet rs = qe.execSelect() ;
            ResultSetFormatter.out(rs) ;
        }
        store.close() ;
    }

Formatting or Emptying the Store

SDB stores do not ensure that the database is formatted. You can check whether the store is already formatted using:

StoreUtils.isFormatted(store);

This is an expensive operation, and should be used sparingly.

Once you obtain a store for the first time you will need to:

store.getTableFormatter().create();

This will create the necessary tables and indexes required for a full SDB store.

You may empty the store completely using:

store.getTableFormatter().truncate();

Loading data

Data loading uses the standard Jena Model.read operations. GraphSDB, and models made from a GraphSDB, implement the standard Jena bulk data interface with backed by an SBD implementation of that interface.

Executing Queries

The interface to making queries with SDB is same as that for querying with ARQ. SDB is an ARQ query engine that can handle queries made on an RDF dataset which is of the SDB class DatasetStore:

   Dataset ds = DatasetStore.create(store) ;

This is then used as normal with ARQ:

   Dataset ds = DatasetStore.create(store) ;
   try(QueryExecution qe = QueryExecutionFactory.create(query, ds)) {
       ResultSet rs = qe.execSelect() ;
       ResultSetFormatter.out(rs) ;
   }

When finished, the store should be closed to release any resources associated with the particular implementation. Closing a store does not close it’s JDBC connection.

   store.close() ;

Closing the SDBConnection does close the JDBC connection:

   store.getConnection().close() ;
   store.close() ;

If models or graphs backed by SDB are placed in a general Dataset then the query is not efficiently executed by SDB.

Using the Jena Model API with SDB

A Jena model can be connected to one graph in the store and used with all the Jena API operations.

Here, the graph for the model is the default graph:

    Store store = SDBFactory.connectStore("sdb.ttl") ;
    Model model = SDBFactory.connectDefaultModel(store) ;

    StmtIterator sIter = model.listStatements() ;
    for ( ; sIter.hasNext() ; )
    {
        Statement stmt = sIter.nextStatement() ;
        System.out.println(stmt) ;
    }
    sIter.close() ;
    store.close() ;

SDB is optimized for SPARQL queries but queries and other Jena API operations can be mixed. The results from a SPARQL query are Jena RDFNodes, with the associated model having a graph implemented by SDB.