Henriette's Notes

Category Archives: RDF4J

Getting started with Ontotext GraphDB and RDF4J

In this post I will explain how to quickly get started with the free version of Ontotext GraphDB and RDF4J. Ontotext GraphDB is an RDF datastore and RDF4J is a Java framework for accessing RDF datastores (not just GraphDB). I will explain

  1. how to install and start GraphDB, as well as how to use the workbench to add a repository, and
  2. how to do SPARQL queries against GraphDB using RDF4J.

Install and start GraphDB and create a Repository

To gain access to the free version of GraphDB you have to email Ontotext. They will respond with an email with links to a desktop and stand-alone server version of GraphDB. You want to download the stand-alone server version. This is a graphdb-free-VERSION-dist.zip file, that you can extract somewhere on your filesystem, which I will refer to here as $GRAPHDB_ROOT. To start GraphDB, go to $GRAPHDB_ROOT/bin and run ./graphdb.

To access the workbench you can go to http://localhost:7200. To create a new repository, in the left-hand side menu navigate to Setup>Repositories. Click the Create new repository button. For our simple example we will use PersonData as an Repository ID. The rest of the settings we leave as-is. At the bottom of the page you can press the Create button.

Accessing a GraphDB Repository using RDF4J

To access our PersonData repository we will use RDF4J. Since GraphDB is based on the RDF4J libraries, we only need to include the GraphDB dependencies since these already include RDF4J. Thus, in our pom.xml file we only need to add the following:

 <dependency>
   <groupId>com.ontotext.graphdb</groupId>
   <artifactId>graphdb-free-runtime</artifactId>
   <version>8.5.0</version>
 </dependency>

In our example Java code we first insert some RDF data and then do a query based on the added data. For inserting data we start a transaction and commit it, or, if it fails we do a rollback. For querying the data we iterate through the TupleQueryResult, retrieving values for the binding variables we are interested in (i.e. name in this case). In line with the TupleQueryResult documentation, we close the TupleQueryResult once we are done.

package org.graphdb.rdf4j.tutorial;
package org.graphdb.rdf4j.tutorial;

import org.eclipse.rdf4j.model.impl.SimpleLiteral;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.http.HTTPRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class SimpleInsertQueryExample {
  private static Logger logger = 
    LoggerFactory.getLogger(SimpleInsertQueryExample.class);
  // Why This Failure marker
  private static final Marker WTF_MARKER = 
    MarkerFactory.getMarker("WTF");
  
  // GraphDB 
  private static final String GRAPHDB_SERVER = 
    "http://localhost:7200/";
  private static final String REPOSITORY_ID = "PersonData";

  private static String strInsert;
  private static String strQuery;
  
  static {
    strInsert = 
        "INSERT DATA {"
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://dbpedia.org/ontology/birthDate> \"1906-12-09\"^^<http://www.w3.org/2001/XMLSchema#date> ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://dbpedia.org/ontology/birthPlace> <http://dbpedia.org/resource/New_York_City> ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://dbpedia.org/ontology/deathDate> \"1992-01-01\"^^<http://www.w3.org/2001/XMLSchema#date> ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://dbpedia.org/ontology/deathPlace> <http://dbpedia.org/resource/Arlington_County,_Virginia> ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://purl.org/dc/terms/description> \"American computer scientist and United States Navy officer.\" ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://dbpedia.org/ontology/Person> ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://xmlns.com/foaf/0.1/gender> \"female\" ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://xmlns.com/foaf/0.1/givenName> \"Grace\" ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://xmlns.com/foaf/0.1/name> \"Grace Hopper\" ."
         + "<http://dbpedia.org/resource/Grace_Hopper> <http://xmlns.com/foaf/0.1/surname> \"Hopper\" ."        
         + "}";
    
    strQuery = 
        "SELECT ?name FROM DEFAULT WHERE {" +
        "?s <http://xmlns.com/foaf/0.1/name> ?name .}";
  }  
  
  private static RepositoryConnection getRepositoryConnection() {
    Repository repository = new HTTPRepository(
      GRAPHDB_SERVER, REPOSITORY_ID);
    repository.initialize();
    RepositoryConnection repositoryConnection = 
      repository.getConnection();
    return repositoryConnection;
  }
  
  private static void insert(
    RepositoryConnection repositoryConnection) {
    
    repositoryConnection.begin();    
    Update updateOperation = repositoryConnection
      .prepareUpdate(QueryLanguage.SPARQL, strInsert);
    updateOperation.execute();
    
    try {
      repositoryConnection.commit();
    } catch (Exception e) {
      if (repositoryConnection.isActive())
        repositoryConnection.rollback();
    }
  }

  private static void query(
    RepositoryConnection repositoryConnection) {
    
    TupleQuery tupleQuery = repositoryConnection
      .prepareTupleQuery(QueryLanguage.SPARQL, strQuery);
    TupleQueryResult result = null;
    try {
      result = tupleQuery.evaluate();
      while (result.hasNext()) {
        BindingSet bindingSet = result.next();

        SimpleLiteral name = 
          (SimpleLiteral)bindingSet.getValue("name");
        logger.trace("name = " + name.stringValue());
      }
    }
    catch (QueryEvaluationException qee) {
      logger.error(WTF_MARKER, 
        qee.getStackTrace().toString(), qee);
    } finally {
      result.close();
    }    
  }  
  
  public static void main(String[] args) {
    RepositoryConnection repositoryConnection = null;
    try {   
      repositoryConnection = getRepositoryConnection();
      
      insert(repositoryConnection);
      query(repositoryConnection);      
      
    } catch (Throwable t) {
      logger.error(WTF_MARKER, t.getMessage(), t);
    } finally {
      repositoryConnection.close();
    }
  }  
}

Conclusion

In this brief post I gave a quick example of how you can setup a simple GraphDB repository and query it using SPARQL. You can find sample code on github.

Creating a Remote Repository for GraphDB with RDF4J Programmatically

In my previous post I have detailed how you can create a local Ontotext GraphDB repository using RDF4J. I indicated that there are some problems when creating a local repository. Therefore, in this post I will detail how to create a remote Ontotext GraphDB repository using RDF4J. As with creating a local repository, there are three steps:

  1. Create a configuration file, which is as for local repositories.
  2. Create pom.xml file, which is as for local repositories.
  3. Create the Java code.

The benefit of creating a remote repository is that it will be under the control of the Ontotext GraphDB Workbench. Hence, you will be able to monitor your repository from the Workbench.

Java Code

package org.graphdb.rdf4j.tutorial;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;

import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.impl.TreeModel;
import org.eclipse.rdf4j.model.util.Models;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.config.RepositoryConfig;
import org.eclipse.rdf4j.repository.config.RepositoryConfigSchema;
import org.eclipse.rdf4j.repository.http.config.HTTPRepositoryConfig;
import org.eclipse.rdf4j.repository.manager.RemoteRepositoryManager;
import org.eclipse.rdf4j.repository.manager.RepositoryManager;
import org.eclipse.rdf4j.repository.manager.RepositoryProvider;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFParser;
import org.eclipse.rdf4j.rio.Rio;
import org.eclipse.rdf4j.rio.helpers.StatementCollector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class CreateRemoteRepository {
  private static Logger logger = LoggerFactory.getLogger(CreateRemoteRepository.class);
  // Why This Failure marker
  private static final Marker WTF_MARKER = MarkerFactory.getMarker("WTF");
	
  public static void main(String[] args) {
    try {		
      Path path = Paths.get(".").toAbsolutePath().normalize();
      String strRepositoryConfig = path.toFile().getAbsolutePath() + "/src/main/resources/repo-defaults.ttl";
      String strServerUrl = "http://localhost:7200";
		
      // Instantiate a local repository manager and initialize it
      RepositoryManager repositoryManager  = RepositoryProvider.getRepositoryManager(strServerUrl);
      repositoryManager.initialize();
      repositoryManager.getAllRepositories();

      // Instantiate a repository graph model
      TreeModel graph = new TreeModel();

      // Read repository configuration file
      InputStream config = new FileInputStream(strRepositoryConfig);
      RDFParser rdfParser = Rio.createParser(RDFFormat.TURTLE);
      rdfParser.setRDFHandler(new StatementCollector(graph));
      rdfParser.parse(config, RepositoryConfigSchema.NAMESPACE);
      config.close();

      // Retrieve the repository node as a resource
      Resource repositoryNode =  Models.subject(graph
        .filter(null, RDF.TYPE, RepositoryConfigSchema.REPOSITORY))
        .orElseThrow(() -> new RuntimeException(
            "Oops, no <http://www.openrdf.org/config/repository#> subject found!"));

		
      // Create a repository configuration object and add it to the repositoryManager		
      RepositoryConfig repositoryConfig = RepositoryConfig.create(graph, repositoryNode);
      repositoryManager.addRepositoryConfig(repositoryConfig);

      // Get the repository from repository manager, note the repository id 
      // set in configuration .ttl file
      Repository repository = repositoryManager.getRepository("graphdb-repo");

      // Open a connection to this repository
      RepositoryConnection repositoryConnection = repository.getConnection();

      // ... use the repository

      // Shutdown connection, repository and manager
      repositoryConnection.close();
      repository.shutDown();
      repositoryManager.shutDown();					
   } catch (Throwable t) {
     logger.error(WTF_MARKER, t.getMessage(), t);
   }		
  }
}   

Conclusion

In this post I detailed how you can create remote repository for Ontotext GraphDB using RDF4J, as well as the benefit of creating a remote repository rather than a local repository. You can find the complete code of this example on github.

Creating a Local Repository for GraphDB with RDF4J Programmatically

If you want to create a local repository for Ontotext GraphDB, according to the documentation. The are essentially 3 steps:

  1. Create a configuration file.
  2. Create a pom.xml file.
  3. The Java code.

However, there are reasons why you may not want to do this, which I detail.

Configuration File

@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix rep: <http://www.openrdf.org/config/repository#>.
@prefix sr: <http://www.openrdf.org/config/repository/sail#>.
@prefix sail: <http://www.openrdf.org/config/sail#>.
@prefix owlim: <http://www.ontotext.com/trree/owlim#>.

[] a rep:Repository ;
  rep:repositoryID "graphdb-repo" ;
  rdfs:label "graphdb-repo-label" ;
  rep:repositoryImpl [
    rep:repositoryType "graphdb:FreeSailRepository" ;
    rep:repositoryType "owlim:MonitorRepository" ;
    sr:sailImpl [
      sail:sailType "graphdb:FreeSail" ;
       
      owlim:base-URL "http://myexample.ontotext.com/graphdb#" ;
      owlim:defaultNS "" ;
      owlim:entity-index-size "10000000" ;
      owlim:entity-id-size  "32" ;
      owlim:imports "" ;
      owlim:repository-type "file-repository" ;
      owlim:ruleset "owl-horst-optimized" ;
      owlim:storage-folder "storage" ;
  
      owlim:enable-context-index "true" ;
      owlim:cache-memory "256m" ;
      owlim:tuple-index-memory "224m" ;

      owlim:enablePredicateList "true" ;
      owlim:predicate-memory "32m" ;

      owlim:fts-memory "0" ;
      owlim:ftsIndexPolicy "never" ;
      owlim:ftsLiteralsOnly "true" ;

      owlim:in-memory-literal-properties "true" ;
      owlim:enable-literal-index "true" ;
      owlim:index-compression-ratio "-1" ;
           
      owlim:check-for-inconsistencies "false" ;
      owlim:disable-sameAs "false" ;
      owlim:enable-optimization "true" ;
      owlim:transaction-mode "safe" ;
      owlim:transaction-isolation "true" ;
      owlim:query-timeout "0" ;
      owlim:query-limit-results "0" ;
      owlim:throw-QueryEvaluationException-on-timeout "false" ;
      owlim:useShutdownHooks "true" ;
      owlim:read-only "false" ;
    ]
  ].

pom.xml File

   
   <dependency>
      <groupId>com.ontotext.graphdb</groupId>
      <artifactId>graphdb-free-runtime</artifactId>
      <version>8.4.1</version>
   </dependency>       

Java Code

package org.graphdb.rdf4j.tutorial;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.impl.TreeModel;
import org.eclipse.rdf4j.model.util.Models;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.config.RepositoryConfig;
import org.eclipse.rdf4j.repository.config.RepositoryConfigSchema;
import org.eclipse.rdf4j.repository.manager.LocalRepositoryManager;
import org.eclipse.rdf4j.repository.manager.RepositoryManager;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFParser;
import org.eclipse.rdf4j.rio.Rio;
import org.eclipse.rdf4j.rio.helpers.StatementCollector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class CreateLocalRepository {
  private static Logger logger = LoggerFactory.getLogger(CreateLocalRepository.class);
  // Why This Failure marker
  private static final Marker WTF_MARKER = MarkerFactory.getMarker("WTF");
	
  public static void main(String[] args) {
    try {		
      Path path = Paths.get(".").toAbsolutePath().normalize();
      String strRepositoryConfig = path.toFile().getAbsolutePath() + 
          "/src/main/resources/repo-defaults.ttl";
		
      // Instantiate a local repository manager and initialize it
      RepositoryManager repositoryManager = new LocalRepositoryManager(new File("."));
      repositoryManager.initialize();

      // Instantiate a repository graph model
      TreeModel graph = new TreeModel();

      // Read repository configuration file
      InputStream config = new FileInputStream(strRepositoryConfig);
      RDFParser rdfParser = Rio.createParser(RDFFormat.TURTLE);
      rdfParser.setRDFHandler(new StatementCollector(graph));
      rdfParser.parse(config, RepositoryConfigSchema.NAMESPACE);
      config.close();

      // Retrieve the repository node as a resource
      Resource repositoryNode =  Models.subject(graph
         .filter(null, RDF.TYPE, RepositoryConfigSchema.REPOSITORY))
         .orElseThrow(() -> new RuntimeException(
             "Oops, no <http://www.openrdf.org/config/repository#> subject found!"));

      // Create a repository configuration object and add it to the repositoryManager
      RepositoryConfig repositoryConfig = RepositoryConfig.create(graph, repositoryNode);
      repositoryManager.addRepositoryConfig(repositoryConfig);

      // Get the repository from repository manager, note the repository id
      // set in configuration .ttl file
      Repository repository = repositoryManager.getRepository("graphdb-repo");

      // Open a connection to this repository
      RepositoryConnection repositoryConnection = repository.getConnection();

      // ... use the repository

      // Shutdown connection, repository and manager
      repositoryConnection.close();
      repository.shutDown();
      repositoryManager.shutDown();					
    } catch (Throwable t) {
      logger.error(WTF_MARKER, t.getMessage(), t);
    }		
  }
}  

Why you may not want to do this

new LocalRepositoryManager(new File(".")); will create a repository where ever your Java application is running from. This means the repository will not be under the control of your Ontotext GraphDB Workbench. Hence, you will not be able to run SPARQL queries or monitor your database from the Workbench. I am not aware of any way via which you can instruct GraphDB to look for repositories in an additional directory.

If you change the directory to $GRAPH DB INSTALL$/data/repositories, the repository will be under the control of Ontotext GraphDB (assuming you have a local GraphDB instance) only if GraphDB is not running. If you start GraphDB after running your program, you will be able to see the repository in GraphDB workbench.

Conclusion

In this post I have detailed how you can create an Ontext GraphDB repository using RDF4J and why you may not want to do this. In my next post I detail how
to create a remote repository, which addresses the problem I detailed here. You can find the complete code of this example on github.