MarkLogic RDF4j API Overview

MarkLogic RDF4j

marklogic-rdf4j enables applications based on RDF4J 2.2.2 to use MarkLogic as a persistence layer for triples, and as a source to query with SPARQL. In addition to basic support for graph CRUD and SPARQL query and update, marklogic-rdf4j also exposes the following MarkLogic capabilities to the RDF4J framework:

Before Starting

Ensure that you have the following information available for a MarkLogic instance:

If you need something to help you configure and deploy MarkLogic application servers, try ml-gradle. Note: If you are starting with 8.0-4 MarkLogic installation on your local machine, the configuration of ml-gradle out of the box will set up a test server for you.

The API

RDF4J uses a {@link org.eclipse.rdf4j.repository.Repository} to represent a quad store and {@link org.eclipse.rdf4j.repository.RepositoryConnection} to connect to a quad store.

import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.semantics.rdf4j.MarkLogicRepository;
import com.marklogic.semantics.rdf4j.MarkLogicRepositoryConnection;
import com.marklogic.semantics.rdf4j.query.MarkLogicTupleQuery;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.FOAF;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.model.vocabulary.XMLSchema;
import org.eclipse.rdf4j.query.*;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

public class Example1_Simple {

    protected static Logger logger =LoggerFactory.getLogger(Example1_Simple.class);

    public static void main(String... args) throws RepositoryException, IOException, RDFParseException, MalformedQueryException, QueryEvaluationException {

        // instantiate repository
        MarkLogicRepository repo = new MarkLogicRepository("localhost",8200, new DatabaseClientFactory.DigestAuthContext("admin", "admin"));
        repo.initialize();

        // get repository connection
        MarkLogicRepositoryConnection conn = repo.getConnection();

        // return number of triples contained in repository
        logger.info("number of triples: {}", conn.size());

        // add triples from a file
        File inputFile = new File("src/main/resources/testdata/test-small.owl");
        conn.add(inputFile, null, RDFFormat.RDFXML, (Resource) null);

        logger.info("number of triples: {}", conn.size());

        // add a few constructed triples
        Resource context1 = conn.getValueFactory().createIRI("http://marklogic.com/examples/context1");
        Resource context2 = conn.getValueFactory().createIRI("http://marklogic.com/examples/context2");
        ValueFactory f= conn.getValueFactory();
        String namespace = "http://example.org/";
        IRI john = f.createIRI(namespace, "john");
        conn.add(john, RDF.TYPE, FOAF.PERSON,context1);
        conn.add(john, RDFS.LABEL, f.createLiteral("John", XMLSchema.STRING),context2);

        // check if triples with subject john exist in repository
        String checkJohnQuery = "ASK { <http://example.org/john> ?p ?o .}";
        BooleanQuery booleanJohnQuery = conn.prepareBooleanQuery(QueryLanguage.SPARQL, checkJohnQuery);
        logger.info("result of query: {}",booleanJohnQuery.evaluate());

        // perform SPARQL query with pagination
        String queryString = "select * { ?s ?p ?o }";
        MarkLogicTupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
        tupleQuery.setIncludeInferred(true);
        TupleQueryResult results = tupleQuery.evaluate(1,10);

        //iterate through query results
        while(results.hasNext()){
            BindingSet bindings = results.next();
            logger.info("subject:{}",bindings.getValue("s"));
            logger.info("predicate:{}", bindings.getValue("p"));
            logger.info("object:{}", bindings.getValue("o"));
        }

        // clear all triples
        conn.clear();
        logger.info("number of triples: {}", conn.size());

        // close connection and shutdown repository
        conn.close();
        repo.shutDown();
    }
}

Add and Remove Triples Operation

Use RDF4J's CRUD operations to store, retrieve, merge, or delete triples.

        Resource context1 = conn.getValueFactory().createIRI("http://marklogic.com/examples/context1");
        Resource context2 = conn.getValueFactory().createIRI("http://marklogic.com/examples/context2");
        ValueFactory f = conn.getValueFactory();
        String namespace = "http://example.org/";
        IRI john = f.createIRI(namespace, "john");
        conn.begin();
        conn.add(john, RDF.TYPE, FOAF.PERSON, context1);
        conn.add(john, RDFS.LABEL, f.createLiteral("John", XMLSchema.STRING), context2);
        logger.info("total triples:{}", conn.size());
        conn.commit();
        conn.remove(john,RDF.TYPE,null,context1);
        conn.remove(john,null,null,context2);
        logger.info("total triples:{} should be zero", conn.size());

Load 100k triples

        ValueFactory vf = SimpleValueFactory.getInstance();
        IRI graph = vf.createIRI("urn:test");
        int docSize = 100000;

        conn.configureWriteCache(750,750,600); // customise write cache (initDelay interval, delayCache interval, cache size)

        conn.begin();
        Set bulkInsert = new HashSet();
        for (int term = 0; term < docSize; term++) {
            bulkInsert.add(vf.createStatement
                    (vf.createIRI("urn:subject:" + term),
                            vf.createIRI("urn:predicate:" + term),
                            vf.createIRI("urn:object:" + term)));
        }
        conn.add(bulkInsert, graph);
        conn.commit();

SPARQL Queries

Perform SPARQL query with pagination.

        // perform SPARQL query
        String queryString = "select * { ?s ?p ?o }";
        MarkLogicTupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);

        // enable rulesets set on MarkLogic database
        tupleQuery.setIncludeInferred(true);

        // set base uri for resolving relative uris
        tupleQuery.setBaseURI("http://www.example.org/base/");

        // set rulesets for infererencing
        tupleQuery.setRulesets(SPARQLRuleset.ALL_VALUES_FROM, SPARQLRuleset.HAS_VALUE);

        // set a combined query
        String combinedQuery =
                "{\"search\":" +
                        "{\"qtext\":\"*\"}}";
        RawCombinedQueryDefinition rawCombined = qmgr.newRawCombinedQueryDefinition(new StringHandle().with(combinedQuery).withFormat(Format.JSON));
        tupleQuery.setConstrainingQueryDefinition(rawCombined);

        // evaluate query with pagination
        TupleQueryResult results = tupleQuery.evaluate(1,10);

        //iterate through query results
        while(results.hasNext()){
            BindingSet bindings = results.next();
            logger.info("subject:{}",bindings.getValue("s"));
            logger.info("predicate:{}", bindings.getValue("p"));
            logger.info("object:{}", bindings.getValue("o"));
        }

        // must explicitly close QueryResult
        results.close();

SPARQL Update

        //update query
        String updatequery = "INSERT DATA { GRAPH <http://marklogic.com/test/context10> {  <http://marklogic.com/test/subject> <pp1> <oo1> } }";
        MarkLogicUpdateQuery updateQuery = conn.prepareUpdate(QueryLanguage.SPARQL, updatequery,"http://marklogic.com/test/baseuri");

        // set perms to be applied to data
        updateQuery.setGraphPerms(gmgr.permission("admin", Capability.READ).permission("admin", Capability.EXECUTE));

        try {
            updateQuery.execute();
        } catch (UpdateExecutionException e) {
            e.printStackTrace();
        }