Table of contents
Introduction
This document is an introduction to Elda, an implementation of the Linked Data API (LDA). The LDA allows you to have a configurable, REST-style interface to a store containing RDF data. This makes it easier for developers used to using common web technologies such as JavaScript and JSON to access your data, and display it in a web browser.
Elda is a Java implementation of the LDA specification, and was developed by Epimorphics Ltd. Elda is licensed under an open-source Apache License.
A quick introduction to running Elda
Before we go on to explain more of what Elda is doing and how you can customise it, let's get an instance of Elda running and see what it can do.
The easiest route to starting Elda is to use the pre-packaged Java .jar
file that you can download from
http://repository.epimorphics.com/com/epimorphics/lda/elda-standalone/1.2.31/elda-standalone-1.2.31.jar
.
You can start the file from the command line.
java -jar elda-standalone-$VERSION.jar
where $VERSION
denotes the version number of the Elda you downloaded, such as
1.2.31.
If your system permits, double-clicking on the file in
your preferred file browser may also work.
At this point, you may see a large number of log messages as Elda starts, and then you should be able to view the starting page in a web browser: http://localhost:8080/standalone/hello/games. This should display a page similar to:
What just happened?
Contained within the standalone Elda version is a small RDF dataset about board games. The
example configuration
provides an API for viewing the contents of this dataset through simple
web URLs. http://localhost:8080/standalone/hello/games
lists the first page of board games that are in the example data: the
different games appear as entries in the Search Results section on
the left.
By default, the list is presented in HTML format, which is nice for people to read, but not so good for programs to process. The format names on the top-right of the window are clickable to select a different format, e.g. by clicking the ttl link, the BoardGame resources will be shown as RDF Turtle.
The right-hand column of the page has links to the individal items on the left, links to allow sorting on the different properties the items may have, and links for adjusting the view by adding or removing properties from it; these are more useful for bigger examples with more items and properties to experiment with.
How did it happen?
When Elda is presented with a URL, it uses it to select an
endpoint. From the details of the URL path
(/games
in this case) and its query parameters
(none in this case), it constructs a SPARQL query which
selects one or more items (here, games) from the
RDF dataset. It then constructs a view of (some of the)
properties of those items, and then renders that view
into one of the possible formats, sending that rendering back
to whatever sent the query.
This example displays all available properties.
Decisions about which datasets to display, which end-points (i.e., URL patterns) display which resources, how resources are displayed, and other design choices are all encoded in the LDA configuration file. The LDA specification describes in detail what goes in a configuration file. The configuration file itself uses RDF to encode these configuration choices, and is typically written in the Turtle syntax, as it is relatively readable and compact. Elda comes with various pre-built examples which may help you to get started with building your own specs. Ultimately, it is the configuration file which specifies how Elda URLs are turned into queries against the underlying store, and how the results of those queries are presented back to your users.
The cribsheet gives a terse overview of the meaning of the LDA query parameters and configuration properties.
Summary of LDA capabilities
- filters. Query parameters can specify that items must have specified ranges of values for some property in order to be selected. Endpoints can have some filters, e.g. that the item has a particular type, pre-loaded.
- views. Endpoints can specify, and query parameters modify, which properties of the selected items are to be displayed.
- formats. The items and their properties can be rendered in different formats, including HTML, XML, JSON, RDF/XML, and Turtle.
- data sources. Data can be fetched from any SPARQL endpoint. For convenience in testing, Elda also allows data to be fetched from a local file.
- metadata. The rendered response includes metadata such as the SPARQL queries used to select items and fetch their properties.
- text search. For suitably-configured SPARQL endpoints, Elda can exploit free text queries that can search for text fragments or use AND, OR, and NOT to control the search.
- velocity templates. You can choose to write a new format for an Elda instance using Velocity templates. (This feature is experimental; feedback is welcome.)
- statistics. Elda can present statistics about the queries that it has received either in HTML or (experimentally) using JMX. The statistics include the number of queries and the amount of data transferred.
- configuration display.
The path
/api-config
for a running Elda presents all the endpoints that are available for it and details of their configuration.
Tutorial
We will now work through some of Elda's capabilities in slightly more detail. See the reference page for more comprehensive and detailed descriptions.
Prerequisites
Elda is written in Java (using the Jena RDF toolkit), so you will need Java installed on your system.
The default demonstration setup for Elda has examples that use the
data.gov.uk
data accessible from the SPARQL endpoint
http://education.data.gov.uk/sparql/education/query
.
To run those examples, you will need to have open web access.
Downloading and starting Elda
There are two ways to get Elda: either by downloading the pre-compiled
runnable demo .jar
file, or by checking out the source code
from its GitHub project and then compiling the Java source.
The runnable .jar
can be downloaded from the
[MAVEN reference here] downloads page.
Choose the most recent version unless you have good reason not to.
If you want to explore the Elda code and have git installed, you can copy the Elda repository:
git clone https://github.com/epimorphics/elda.git
To compile the code, you will also need Apache Maven:
mvn clean package
After compiling, the runnable .jar
file will be in
./elda-standalone/target/elda-standalone.war
.
Alternatively, you can start the Jetty web server that is supplied with
Elda by running the following command from the elda-standalone
sub-directory:
java -jar start.jar
If you can't use port 8080
Your computer may already be using port 8080 for some local service. In that case, you can start Elda from the command line (this wont' work when double-clicking in a file manager) with:
java -jar standalone.jar -Djetty.port=NNNNor, if you're starting from the unzipped Elda directory,
java -Djetty.port=NNNN -jar start.jar
where NNNN is the port of your choice. Note: the -D
comes after standalone.jar
, but before start.jar
.
To change the port number without having to
supply a -Djetty.port
command line option
every time, in the Elda directory edit the
configuration file etc/jetty.xml
and change the line:
<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
to:
<Set name="port"><SystemProperty name="jetty.port" default="NNNN"/></Set>
where NNNN is the port number of your choice.
Built-in example datasets and configurations
Elda comes pre-packaged with some example configurations and an example dataset. The sample URLs in the table below should all work if you have Elda running on your local computer, on port 8080:
description | config file | sample URLs |
---|---|---|
one-template games example, local SPARQL endpoint. | hello-world.ttl | |
two-template games example, local SPARQL endpoint. | hello-again-world.ttl | |
one-template education example, external SPARQL endpoint. | tiny-education.ttl | |
multi-template education example, external SPARQL endpoint. | mini-education.ttl | |
full education example, external SPARQL endpoint. | full-education.ttl |
...
|
old education example [for comparison], external SPARQ endpoint. | old-education.ttl |
Games example -- web page
Let's look a little at the two-template games example, standalone/again
.
(Refer to the cribsheet for a summary of the action of Elda's query parameters.)
The page http://localhost:8080/standalone/again/games shows us the properties (as in the example data file) of several boardgames. This HTML view allows you to explore the dataset. For example, A Brief History of the World has publication date 2009. Clicking the magnifying-glass icon on that line restricts the results to only those with that publication date -- as it happens, no others. And we see (from the URL bar) that the URL of this page has had a publicationDate=2009 query parameter added.
Going back and clicking the less-than sign shows instead will show games whose publication date is the same as, or less recent than, A Brief History of the World. Similarly, going back and clicking the greater-than sign will show games no older than A Brief History of the World. In both cases, the URL changes to show the applied filter, which also appears in the Filter box in the column on the right.
Similarly you can play with the value of players
,
eg clicking on the magnifying class for players 4 will
restrict the display to only games that have a 4-player option.
And, of course, you can apply two (or more) filters at once.
In the right-hand column, the Sortby box contains the names
of the properties that are displayed. Clicking on an arrow will
change the order of the items by sorting according to the value
of the predicate: the default is to sort by the label of the
item, but you could choose publication date
or
designed by
, or both together. players
,
being multi-valued, isn't really a good sorting candidate.
Games example -- configuration
We'll talk briefly through the LDA specification used for the games example.
# # A hello-world config. # # Assorted prefix declarations. Some of them are for the structuring # of the API config, others are for the vocabulary definitions. # @prefix api: <http://purl.org/linked-data/api/vocab#> . @prefix dct: <http://purl.org/dc/terms/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . # The elda namespace/prefix is for Elda extensions to the LDA specification. @prefix elda: <http://www.epimorphics.com/vocabularies/lda#> . # Prefix for example-local entities. @prefix hello: <http://localhost:8080/elda/vocabulary/>.
The prefixes declared here make the configuration more concise and are used in the result model from the LDA query.
# --------------------------------------------------------------------- # API config hello:hello-world-again a api:API ; rdfs:label "Hello World example #2 -- games"@en
hello:hello-world-again
is declared as an API.
The label is used as a title in /api-config.
# Name the SPARQL endpoint which supplies the data we present ; api:sparqlEndpoint <local:data/example-data.ttl>
The SPARQL endpoint for this API is a local file. (This is an Elda extension to the LDA for testing and demonstration purposes.)
; api:defaultViewer api:labelledDescribeViewer
The default view for this API is the built-in
labelledDescribeViewer
, which fetches all the
properties of the item using a SPARQL DESCRIBE and also fetches
the labels of all the resource values this finds.
; api:viewer [a api:Viewer; api:name "none"; api:properties ""]
This defines a new view called none which shows no
properties at all. This can be useful as a starting-point
when building a view on the URL using the query parameter
_properties=
.
; api:variable [ api:name "_resourceRoot" ; api:value "http://localhost:8080/standalone/lda-assets/" ]
The special variable _resourceRoot
is used by Elda
as the base URI for assets needed for the HTML rendering of results.
; api:endpoint hello:publishers, hello:games
These are two endpoints for this API, hello:games
and hello:publishers
.
; api:formatter [ a api:XsltFormatter ; api:name "html" ; api:mimeType "text/html; charset=utf-8" ; api:stylesheet "lda-assets/xslt/result-osm-trimmed.xsl" ] .
Elda's default HTML formatter is crude, so we define a new
formatter for the name html
which is an XSLT formatter
producing UTF-8 endcoded text/html
and using the
stylesheet result-osm-trimmed.xsl
.
# Endpoint definitions hello:publishers a api:ListEndpoint ; rdfs:label "Publishers" ; api:uriTemplate "/publishers" ; api:selector [api:filter "type=Publisher"; api:sort "label"] ; api:defaultViewer api:labelledDescribeViewer .
This is the publishers endpoint. It will show only items of type hello:Publisher, sort them by their label (which will be the publisher name), and view them with the labelledDescribe viewer.
hello:games a api:ListEndpoint ; rdfs:label "Games" ; api:uriTemplate "/games" ; api:selector [api:filter "type=BoardGame"; api:sort "label"] ; api:defaultViewer api:labelledDescribeViewer .
Similarly, this is the games endpoint, selecting only items of type hello:BoardGame and sorting them by their label.
The rest of the configuration defines property and class
shortnames and other important attributes. The resouces
(classes and proeprties both) that are of interest are those
of type rdf:Property
, owl:ObjectProperty
,
owl:DatatypeProperty
, rdfs:Class
, and
owl:Class
.
hello:BoardGame a rdfs:Class ; rdfs:label "Board Game" ; api:label "BoardGame" .
The class hello:BoardGame
has shortname
BoardGame, as defined by its api:label
;
this is what allows it to appear in the endpoint filter
type=BoardGame
.
hello:players a rdf:Property ; api:label "players" ; rdfs:range xsd:int .
hello:players
has shortname players, which
is what allows you to use eg players
as
the name of a query parameter. Defining its range to be
xsd:int
means (eg) that the 2 in the query
parameter players=2
is interpreted as an integer
and not a string.
hello:Publisher a rdfs:Class ; api:label "Publisher" .
Similarly to BoardGame
.
dct:publisher a rdf:Property ; api:label "publishes" .
Declares that the shortname of dct:publisher
is
publishes.
rdfs:label a rdf:Property ; api:multiValued true ; api:label "label" .
Declares that rdfs:label
has shortname label
and that it is always to be presented in the JSON rendering as
having an array of label values, even if there's only one.
rdf:type a rdf:Property ; api:multiValued true ; rdfs:range rdfs:Class ; api:label "type" .
Declares that rdf:type
has shortname type,
should have its JSON-rendered values appear as an array, and has
a range of rdfs:Class
, which means that for a query
parameter type=SPOO
, SPOO is interpreted as being
the shortname of some resource rather than a literal string.
hello:designed-by a rdf:Property ; api:label "designedBy" .
Declares that hello:designed-by
has shortname
designedBy. (Note that the HTML renderer shows property
shortnamesin the display translated by turning camelCase
like designedBy into space-separated words like
designed by.)
hello:designer-of a rdf:Property ; api:label "designerOf" .
The shortname of hello:designer-of
is designerOf.
hello:pubDate a rdf:Property ; api:label "publicationDate" ; rdfs:range xsd:integer .
And finally, the shortname of hello:pubDate
is
publicationDate and its value is interpreted as an
integer.
That concludes our example LDA specification. For more details on LDA configurations, see the Linked Data API (LDA) and the Elda reference material. Also see the other API configurations mentioned above.
Using other LDA specifications
From the command line
To use different LDA specifications, use the system property
elda.spec
. Like the port number, it can be set
as part of launching the elda jar or when launching the jetty
start jar:
java -jar standalone.jar -Delda.spec=SPECS
or (in the Elda directory):
java -Delda.spec=SPECS -jar start.jar
where SPECS is one or more LDA specification files separated by commas.
If you use elda.spec
, then Elda ignores the
default specification (the education LDA) wired into it.
By editing web.xml
To change the specification used without having to use
a -Delda.spec
command line option every time, edit the
Elda webapps/elda/WEB-INF/web.xml
. Find the
servlet configuration
<servlet> <servlet-name>loader-init</servlet-name> <servlet-class>com.epimorphics.lda.routing.Loader</servlet-class> <init-param> <param-name>com.epimorphics.api.initialSpecFile</param-name> <param-value>assorted specs here</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
Replace the assorted specs here with the name of the LDA
specification files you wish to load, separated by commas.
Spaces and newlines are ignored. (For more explanation of
the structure of the web.xml
file, see
the reference documentation).
Fancy HTML formatting using XSLT stylesheets
The default formatter supplied by Elda is a very simple HTML formatter showing the properties and their values of the selected items. Elda also ships with a renderer that uses XSLT (and Javascript at the client end) to produce pages with additional controls and a richer appearance. To use this as your html renderer, add:
; api:formatter [a api:XsltFormatter ; api:name 'html' ; api:stylesheet 'xslt/result-osm.xsl' ; api:mimeType 'text/html' ]
to your API root in your configuration file and arrange that the webapps/elda directory contents are served as static files.
Alternative data sources
Querying a local file
If the remote SPARQL endpoint is slow, not yet fully configured, or plain unimplemented, you might want to set up a local endpoint using a tool like Fuseki. But it's also possible for Elda to query a local RDF file.
Edit your spec file, which will look something like the education spec suplied with Elda:
spec:api a api:API ; rdfs:label "Edubase API"@en; api:maxPageSize 50; api:defaultPageSize 10 ; api:sparqlEndpoint <http://education.data.gov.uk/sparql/education/query> ; api:endpoint spec:schools , spec:schoolsPrimary , spec:schoolsSecondary , spec:schoolsPrimaryDistrict , spec:schoolsSecondaryDistrict .
Replace the endpoint URI with local:content-name, where content-name is the name of the RDF source you wish to query. When Elda issues queries to a local: endpoint, it loads (and remembers) the contents and queries those directly.
Usually the content-name is a file name. It is resolved against the webapps context path (ie the directory from which it serves files). If there is no such file, then the content-name is treated as a URL and its contents fetched. If that fails, then the content is searched for along the webapps classpath. In all of these cases, the fetched content is loaded into memory as an RDF model and all queries to the endpoint are answered by this model.
(The name-lookup functionality is supplied by the underlying Jena
FileManager
class; for more details, see the Jena
documentation currently at openjena.org.)
Using a local TDB datasource [obsolescent]
As an alternative to setting up a local SPARQL endpoint,
or using a local: file, you can instead use a local
Jena TDB
database. To do so you will need to modify the web.xml
webapp configuration file and supply an additional init-param
for the loader-init
servlet. You can do this in
two ways:
<init-param> <param-name>com.epimorphics.api.TDB-base-directory</param-name> <param-value>tdb-directory</param-value> </init-param>
Replace tdb-directory with the path to your chosen TDB directory. Note that the path is relative to the webapps directory – your best choice is to use an absolute path.
Warning. If the directory does not contain any TDB files, TDB will create a new empty dataset in it. This is usually not what you want, since all queries will return no answers, so Elda will report an error during setup.
The alternative form:
<init-param> <param-name>com.epimorphics.api.dataStoreDirectory</param-name> <param-value>datastore-directory</param-value> </init-param>
specifies datastore-directory as a directory containing a TDB directory named tdb. The same warnings as above apply. (This form exists because Elda can do limited LARQ indexing and in that case the datastore directory will have a larq subdirectory for the LARQ indexes.)
Having specified a TDB directory, you can now edit your spec's sparqlEndpoint declaration, which in the education example looks like:
spec:api a api:API ; rdfs:label "Edubase API"@en; api:maxPageSize 50; api:defaultPageSize 10 ; api:sparqlEndpoint <http://services.data.gov.uk/education/sparql> ; api:endpoint spec:schools , spec:schoolsPrimary , spec:schoolsSecondary , spec:schoolsPrimaryDistrict , spec:schoolsSecondaryDistrict .
Replace the services URI with tdb:model-name, where model-name is the name of your endpoint model inside the TDB store.
Notes
Feedback
Elda aims to provide a complete implementation of the Linked Data API. Problems with Elda should be reported to the linked data API discussion group (note: you will need a google account to use this group).
Current issues can be seen on the Elda issues list .