Skip to content

Instantly share code, notes, and snippets.

@mhgrove
Last active March 21, 2017 01:48
Show Gist options
  • Save mhgrove/1045573 to your computer and use it in GitHub Desktop.
Save mhgrove/1045573 to your computer and use it in GitHub Desktop.
Example of how to use the native Stardog API, SNARL
aConn.begin();
aConn.add().io()
.format(RDFFormat.N3)
.stream(new FileInputStream("data/sp2b_10k.n3"));
Model aGraph = Models2.newModel(Values.statement(Values.iri("urn:subj"),
Values.iri("urn:pred"),
Values.iri("urn:obj")));
Resource aContext = Values.iri("urn:test:context");
aConn.add().graph(aGraph, aContext);
aConn.commit();
/*
* Copyright (c) 2010-2015 Clark & Parsia, LLC. <http://www.clarkparsia.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.complexible.stardog.examples.api;
import java.io.FileInputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Paths;
import com.complexible.common.openrdf.model.ModelIO;
import com.complexible.common.openrdf.model.Models2;
import com.complexible.common.rdf.model.Values;
import com.complexible.stardog.protocols.snarl.SNARLProtocolConstants;
import org.openrdf.model.IRI;
import org.openrdf.model.Model;
import org.openrdf.model.Resource;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.query.resultio.QueryResultIO;
import org.openrdf.rio.RDFFormat;
import com.complexible.common.protocols.server.Server;
import com.complexible.common.rdf.query.resultio.TextTableQueryResultWriter;
import com.complexible.stardog.Stardog;
import com.complexible.stardog.api.Connection;
import com.complexible.stardog.api.Getter;
import com.complexible.stardog.api.ConnectionConfiguration;
import com.complexible.stardog.api.SelectQuery;
import com.complexible.stardog.api.admin.AdminConnection;
import com.complexible.stardog.api.admin.AdminConnectionConfiguration;
/**
* <p>Example code illustrating use of the Stardog Connection API</p>
*
* @author Michael Grove
* @since 0.4
* @version 4.0
*/
public class ConnectionAPIExample {
// Using the SNARL API
// -------------------
// In this example we'll walk through the basic usage of the Stardog Native API for the RDF Language (SNARL)
// API, which is the preferred way to interact with Stardog. This will show how to use both the administrative
// and client APIs to perform some basic operations.
public static void main(String[] args) throws Exception {
// Creating a Server
// -----------------
// You'll need a server to connect to, obviously. The `Stardog`
// class provides a simple [builder interface](http://docs.stardog.com/java/snarl/com/complexible/common/protocols/server/ServerBuilder.html) to specify which protocol
// the server should use (options are HTTP & SNARL) and takes a `SocketAddress`
// the server should bind to. This will return you a [Server](http://docs.stardog.com/java/snarl/com/complexible/common/protocols/server/Server.html) object which
// can be used to start & stop the Stardog server.
//
// This example shows up to create and start the embedded SNARL server. Note that
// you can only embed the *SNARL* server, not HTTP.
Server aServer = Stardog
.buildServer()
.bind(SNARLProtocolConstants.EMBEDDED_ADDRESS)
.start();
try {
// Using AdminConnection
// ---------------------
// Now that the server is running, we want to create a connection to the DBMS itself so we can perform
// some administrative actions, namely, creating a new database to use for the purpose of this example.
// We need to create a connection to perform administrative actions, so we can use the `AdminConnectionConfiguration`
// utility class for opening the connection.
//
// Most operations supported by the DBMS require specific permissions, so either an admin account
// is required, or a user who has been granted the ability to perform the actions. You can learn
// more about this in the [Security chapter](http://docs.stardog.com/security).
try (AdminConnection aAdminConnection = AdminConnectionConfiguration.toEmbeddedServer()
.credentials("admin", "admin")
.connect()) {
// With our admin connection, we're able to see if the database for this example already exists, and
// if it does, we want to drop it and re-create so that we can run the example from a clean database.
if (aAdminConnection.list().contains("testConnectionAPI")) {
aAdminConnection.drop("testConnectionAPI");
}
// Convenience function for creating a non-persistent in-memory database with all the default settings.
aAdminConnection.createMemory("testConnectionAPI");
}
// Using the SNARL API
// -------------------
// Now that we've created our database for the example, let's open a connection to it. For that we use the
// [ConnectionConfiguration](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/ConnectionConfiguration.html)
// to configure and open a new connection to a database.
//
// We'll use the configuration to specify which database we want to connect to as well as our login information,
// then we can obtain a new connection.
try (Connection aConn = ConnectionConfiguration
.to("testConnectionAPI")
.credentials("admin", "admin")
.connect()) {
// All changes to a database *must* be performed within a transaction. We want to add some data to the database
// so we can begin firing off some queries, so first, we'll start a new transaction.
aConn.begin();
// The SNARL API provides fluent objects for adding & removing data from a database. Here we'll use the
// [Adder](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/Adder.html) to read in an N3 file
// from disk containing the 10k triples SP2B dataset. Actually, for RDF data coming from a stream or from
// disk, we'll use the helper class [IO](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/IO.html)
// for this task. `IO` will automatically close the stream once the data has been read.
aConn.add().io()
.format(RDFFormat.N3)
.stream(new FileInputStream("data/sp2b_10k.n3"));
// You're not restricted to adding, or removing, data from a file. You can create `Model` objects
// containing information you want to add or remove from the database and make the modification wit
// that graph. Here we'll create a new Model and add a statement that we want added to our database.
Model aGraph = Models2.newModel(Values.statement(Values.iri("urn:subj"),
Values.iri("urn:pred"),
Values.iri("urn:obj")));
Resource aContext = Values.iri("urn:test:context");
// With our newly created `Graph`, we can easily add that to the database as well. You can also
// easily specify the context the data should be added to. This will insert all of the statements
// in the `Graph` into the given context.
aConn.add().graph(aGraph, aContext);
// Now that we're done adding data to the database, we can go ahead and commit the transaction.
aConn.commit();
// Removing data from a database is just as easy. Again, we need to start a transaction before making any changes.
aConn.begin();
// Now we'll use the [Remover](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/Remover.html) to
// remove some data from the database. `Remover` has a very similar API to `Adder`, so this code should look
// somewhat familiar. It has many of the same methods as `Adder`, the only difference is that they'll cause
// the triples to be removed instead of added.
aConn.remove().io()
.format(RDFFormat.N3)
.file(Paths.get("data/remove_data.nt"));
// Lastly, we'll commit the changes.
aConn.commit();
// A SNARL connection provides [parameterized queries](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/Query.html)
// which you can use to easily build and execute SPARQL queries against the database. First, let's create a simple
// query that will get all of the statements in the database.
SelectQuery aQuery = aConn.select("select * where { ?s ?p ?o }");
// But getting *all* the statements is kind of silly, so let's actually specify a limit, we only want 10 results.
aQuery.limit(10);
// We can go ahead and execute this query which will give us a result set. Once we have our result set, we can do
// something interesting with the results.
TupleQueryResult aResult = aQuery.execute();
try {
System.out.println("The first ten results...");
QueryResultIO.write(aResult, TextTableQueryResultWriter.FORMAT, System.out);
}
finally {
// *Always* close your result sets, they hold resources which need to be released.
aResult.close();
}
// `Query` objects are easily parameterized; so we can bind the "s" variable in the previous query with a specific value.
// Queries should be managed via the parameterized methods, rather than created by concatenating strings together,
// because that is not only more readable, it helps avoid SPARQL injection attacks.
IRI aURI = Values.iri("http://localhost/publications/articles/Journal1/1940/Article1");
aQuery.parameter("s", aURI);
// Now that we've bound 's' to a specific value, we're not going to pull down the entire database with our query
// so we can go head and remove the limit and get all the results.
aQuery.limit(SelectQuery.NO_LIMIT);
// We've made our modifications, so we can re-run the query to get a new result set and see the difference in the results.
aResult = aQuery.execute();
System.out.println("\nNow a particular slice...");
try {
QueryResultIO.write(aResult, TextTableQueryResultWriter.FORMAT, System.out);
}
finally {
// Again, *close* your result sets.
aResult.close();
}
// The previous query was just getting the statements in which the value of `aURI` is the subject. We can get the
// same results just as easily via the [Getter](http://docs.stardog.com/java/snarl/com/complexible/stardog/api/Getter.html)
// interface. `Getter` is designed to make it easy to list statements matching specific criteria; it's analogous to
// `listStatements` or `match` in the Jena & Sesame APIs respectively.
//
// So here we'll create a `Getter` to obtain the list of statements with `aURI` as the subject. If we print those
// out we'll see that we've retrieved the same results as the query we just ran.
System.out.println("\nOr you can use a getter to do the same thing...");
aConn.get().subject(aURI)
.statements()
.forEach(System.out::println);
// `Getter` objects are parameterizable just like `Query`, so you can easily modify and re-use them to change
// what slice of the database you'll retrieve.
Getter aGetter = aConn.get();
// We created a new `Getter`, if we iterated over its results now, we'd iterate over the whole database; not ideal. So
// we will bind the predicate to `rdf:type` and now if we call any of the iteration methods on the `Getter` we'd only
// pull back statements whose predicate is `rdf:type`
aGetter.predicate(RDF.TYPE);
// We can also bind the subject and get a specific type statement, in this case, we'll get all the type triples
// for *this* individual. In our example, that'll be a single triple.
aGetter.subject(aURI);
System.out.println("\nJust a single statement now...");
aGetter.statements()
.forEach(System.out::println);
// `Getter` objects are stateful, so we can remove the filter on the predicate position by setting it back to null.
aGetter.predicate(null);
// Subject is still bound to the value of `aURI` so we can use the `graph` method of `Getter` to get a graph of all
// the triples where `aURI` is the subject, effectively performing a basic describe query.
aGraph = aGetter.statements().collect(Models2.toModel());
System.out.println("\nFinally, the same results as earlier, but as a graph...");
ModelIO.write(aGraph, new OutputStreamWriter(System.out), RDFFormat.TURTLE);
}
}
finally {
// We're done with the example, so we need to make sure we shut down the server we started.
aServer.stop();
}
}
}
aConn.get().subject(aURI)
.statements()
.forEach(System.out::println);
// `Getter` objects are parameterizable just like `Query`, so you can easily modify and re-use them to change
// what slice of the database you'll retrieve.
Getter aGetter = aConn.get();
// We created a new `Getter`, if we iterated over its results now, we'd iterate over the whole database; not ideal. So
// we will bind the predicate to `rdf:type` and now if we call any of the iteration methods on the `Getter` we'd only
// pull back statements whose predicate is `rdf:type`
aGetter.predicate(RDF.TYPE);
// We can also bind the subject and get a specific type statement, in this case, we'll get all the type triples
// for *this* individual. In our example, that'll be a single triple.
aGetter.subject(aURI);
System.out.println("\nJust a single statement now...");
aGetter.statements()
.forEach(System.out::println);
// `Getter` objects are stateful, so we can remove the filter on the predicate position by setting it back to null.
aGetter.predicate(null);
// Subject is still bound to the value of `aURI` so we can use the `graph` method of `Getter` to get a graph of all
// the triples where `aURI` is the subject, effectively performing a basic describe query.
aGraph = aGetter.statements().collect(Models2.toModel());
System.out.println("\nFinally, the same results as earlier, but as a graph...");
ModelIO.write(aGraph, new OutputStreamWriter(System.out), RDFFormat.TURTLE);
SelectQuery aQuery = aConn.select("select * where { ?s ?p ?o }");
// But getting *all* the statements is kind of silly, so let's actually specify a limit, we only want 10 results.
aQuery.limit(10);
// We can go ahead and execute this query which will give us a result set. Once we have our result set, we can do
// something interesting with the results.
TupleQueryResult aResult = aQuery.execute();
try {
System.out.println("The first ten results...");
QueryResultIO.write(aResult, TextTableQueryResultWriter.FORMAT, System.out);
}
finally {
// *Always* close your result sets, they hold resources which need to be released.
aResult.close();
}
// `Query` objects are easily parameterized; so we can bind the "s" variable in the previous query with a specific value.
// Queries should be managed via the parameterized methods, rather than created by concatenating strings together,
// because that is not only more readable, it helps avoid SPARQL injection attacks.
IRI aURI = Values.iri("http://localhost/publications/articles/Journal1/1940/Article1");
aQuery.parameter("s", aURI);
// Now that we've bound 's' to a specific value, we're not going to pull down the entire database with our query
// so we can go head and remove the limit and get all the results.
aQuery.limit(SelectQuery.NO_LIMIT);
// We've made our modifications, so we can re-run the query to get a new result set and see the difference in the results.
aResult = aQuery.execute();
System.out.println("\nNow a particular slice...");
try {
QueryResultIO.write(aResult, TextTableQueryResultWriter.FORMAT, System.out);
}
finally {
// Again, *close* your result sets.
aResult.close();
}
// first start a transaction
aConn.begin();
aConn.remove().io()
.format(RDFFormat.N3)
.file(Paths.get("data/remove_data.nt"));
// and commit the change
aConn.commit();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment