Running Ripple

Joshua Shinavier edited this page Dec 31, 2016 · 22 revisions

Getting the software

There are several ways to get going with Ripple:

Download

The quickest way to get a standalone distribution of Ripple is to download the latest release. After downloading, unpack the archive and navigate into the ripple directory.

Build from source

The Ripple implementation is hosted here on GitHub. To build the latest:

  1. check out the source code:
git clone git://github.com/joshsh/ripple.git
  1. navigate into the top-level directory
cd ripple
  1. build with Maven:
mvn clean install

Import with Maven

To import Ripple into another (Java- and Maven-based) project, add the following to your Maven POM:

        <dependency>
            <groupId>net.fortytwo.ripple</groupId>
            <artifactId>ripple-demo</artifactId>
            <version>1.5</version>
        </dependency>

Notes:

  1. this imports the ripple-demo module, which in turn depends on most of the other Ripple modules, including LinkedDataSail and the Ripple command line. If you don't need everything, you can substitute the artifactId with the name of another module such as ripple-sesame (RDF-based model and query engine, but no command line and no Linked Data), or even ripple-core (Ripple core primitives, support for pipes and filters). For Blueprints support, import ripple-blueprints.
  2. even if you don't use Maven, you can still get the Ripple JARs from the Maven Central repository, here.

The Ripple command line

To start the Ripple command line interpreter:

  1. get or build a Ripple distribution, as above
  2. cd into the ripple/ripple-demo directory
  3. execute the script ./ripple.sh
  4. from here, you can evaluate expressions and issue commands. For example, type 2 3 add. See Commands for more information.
  5. to exit Ripple, type @quit

Configuration

There are a number of Ripple configuration properties which are specific to the command line interface, all of which have to do with the RDF triple store which Ripple connects to and the data which is read from and written to it.

Be default, Ripple uses an instance of LinkedDataSail on top of a Sesame MemoryStore to collect the Linked Data that you stumble upon. That configuration looks like this:

net.fortytwo.ripple.demo.sailType = net.fortytwo.linkeddata.sail.LinkedDataSail
net.fortytwo.ripple.demo.linkedDataSailBaseSail = org.openrdf.sail.memory.MemoryStore

When Ripple quits, the cache of aggregated Linked Data is lost. For a longer-lived application, you can use a persistent triple store such as NativeStore as the storage layer for LinkedDataSail. E.g.

net.fortytwo.ripple.demo.sailType = net.fortytwo.linkeddata.sail.LinkedDataSail
net.fortytwo.ripple.demo.linkedDataSailBaseSail = org.openrdf.sail.nativerdf.NativeStore
net.fortytwo.ripple.demo.nativeStoreDirectory = /Users/lebot/Desktop/ripple-store 

The nativeStoreDirectory property indicates the local directory in which the cached RDF data is to be stored. When you quit Ripple, the cache will remain in that directory, and will be available in subsequent sessions. Make sure to exit Ripple with @quit instead of killing the process, so that Ripple can shut down the triple store properly.

The easiest way to get these properties into Ripple is to put them into a file and pass the file name to ripple.sh:

./ripple.sh desktop-native-store.properties

... where the config file is similar to the above (but perhaps contains additional properties), e.g.

# Aggregate linked RDF data on the fly.
net.fortytwo.ripple.demo.sailType = net.fortytwo.linkeddata.sail.LinkedDataSail

# Use Sesame NativeStore for persistent storage of aggregated data.
net.fortytwo.ripple.demo.linkedDataSailBaseSail = org.openrdf.sail.nativerdf.NativeStore
net.fortytwo.ripple.demo.nativeStoreDirectory = /Users/lebot/Desktop/ripple-store 

# invoke with ./ripple.sh this-file.properties

When you don't specify a required property, Ripple falls back on its default configuration.

Embedded Ripple

Apart from using Ripple interactively, at the command line, you can also plug in to Ripple at various levels through its Java API. The following will show you how to set up a basic "query pipe" which will accept expressions in Ripple syntax and output streams of query results.

Initializing Ripple

If you're happy with Ripple's default configuration (see above), you can skip this step. However, if you have any custom settings to apply, you need to call Ripple.initialize before making any other API calls. This method accepts Java Properties objects which contain your configuration properties. I.e.

Properties config = ...
Ripple.initialize(config);

Creating a Sail

Ripple uses a Sesame Sail to store programs and to interact with RDF data. If you're not interested in RDF data per se, you can just use a temporary, in-memory store:

Sail sail = new MemoryStore();
sail.initialize();

If you have a particular RDF triple store to connect to, you can use an appropriate Sail implementation, such as NativeStore or Blueprints Sail.

A special Sail built for Ripple is LinkedDataSail, which provides a view of the Web of Data. This is the Sail implementation which is used by default when you start up the Ripple command line. E.g.

// The base Sail is for storage
Sail baseSail = new MemoryStore();
baseSail.initialize();

// LDS is for fetching data and managing caching metadata
LinkedDataSail sail = new LinkedDataSail(baseSail);
sail.initialize();

The Sail(s) should be shut down gracefully before the program exits:

sail.shutDown();
baseSail.shutDown();

Creating a Model

Ripple uses the Model interface as a gateway between the RDF data store and the native Ripple environment of stacks and streams. Most of the things you can do in Ripple involve a ModelConnection, which provides transactional access to the Model.

There is currently one Model implementation, SesameModel, which is based on the Sesame API. This is why you need the Sail you created above:

Model model = new SesameModel(sail);

Always call shutDown on the Model before termination of the program, i.e.

model.shutDown();

Creating a QueryEngine

A QueryEngine adds the core functionality of the Ripple language on top of the Model. It contains a Lexicon, which manages programs and namespaces, and a StackEvaluator, which evaluates programs. It also allows you to execute Commands.

QueryEngine qe = new QueryEngine(model);

Ripple uses a lazy, open-world style of program evaluation by default, but you can pass in an alternative evaluator to the QueryEngine constructor.

Query pipes

The last layer of API you need in order to evaluate Ripple expressions is a QueryPipe, which is constructed with two arguments: the QueryEngine created above, and a handler, or Sink, for query results. You push program expressions into the QueryPipe using the put method, and the results flow from the other end of the pipe into the sink. Results arrive at any time and in any order, depending on your Model and StackEvaluator, as well as on the program itself.

If you're using a synchronous style of evaluation and all you want to do is to collect results and then iterate through them, you can use a Collector:

Collector<RippleList, RippleException> c = new Collector<RippleList, RippleException>();
QueryPipe p = new QueryPipe(qe, c);

Tying it all together

Below is a complete example of a query pipe over Linked Data. Also see the Demo source code for an interactive example which loads a custom configuration.

public static void main(String[] args) throws Exception {
    Sail baseSail = new MemoryStore();
    baseSail.initialize();

    LinkedDataSail sail = new LinkedDataSail(baseSail);
    sail.initialize();

    Model model = new SesameModel(sail);
    QueryEngine qe = new QueryEngine(model);

    Collector<RippleList, RippleException> c = new Collector<RippleList, RippleException>();
    QueryPipe p = new QueryPipe(qe, c);

    p.put("10 sqrt.");

    for (RippleList l : c) {
        System.out.println(l);
    }
    c.clear();

    p.put("@prefix foaf: <http://xmlns.com/foaf/0.1/>");
    p.put("@list dan: <http://danbri.org/foaf.rdf#danbri>");
    p.put(":dan. foaf:knows. foaf:name.");

    for (RippleList l : c) {
        System.out.println(l);
    }

    model.shutDown();
    sail.shutDown();
    baseSail.shutDown();
}

The output looks as follows:

(3.1622776601683795)
(-3.1622776601683795)
("Dean Jackson")
("Mr Benn")
("Jim Ley")
("Edd Dumbill")
("Martin Poulter")
("Libby Miller")
[...]

What is next

  • Understand the features of Ripple's Commands