Sequences plugin¶
What’s in this document?
What the plugin does¶
The Sequences plugin provides transactional sequences for GraphDB. A sequence is a long counter that can be atomically incremented in a transaction to provide incremental IDs.
To deploy it, please follow the GitHub instructions.
Usage¶
The plugin supports multiple concurrent sequences where each sequence is identified by an IRI chosen by the user.
Creating a sequence¶
Choose an IRI for your sequence, for example http://example.com/my/seq1
. Insert the following triple to create a sequence whose next value will be 1:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
INSERT DATA {
my:seq1 seq:create []
}
You can also create a sequence by providing the starting value, for example to create a sequence whose next value will be 10
:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
INSERT DATA {
my:seq1 seq:create 10
}
When using the GraphDB cluster, you might get the following exception if the repository existed before registering the plugin: Update would affect a disabled plugin: sequences
. You can enable the plugin with:
INSERT DATA { [] <http://www.ontotext.com/owlim/system#startplugin> "sequences".}
Using a sequence¶
Processing sequence values on the client¶
In this scenario, new and current sequence values can be retrieved on the client where they can be used to generate new data that can be added to GraphDB in the same transaction. For a workaround in the cluster, see here.
Note
This scenario is not supported in a cluster as transactions in the cluster currently cannot see the changes caused by the active transaction. This will be fixed in GraphDB 10.
Using the below examples will not work inside the GraphDB Workbench as they require a single transaction.
To use any sequence, you must first start a transaction and then prepare the sequences for use by executing the following update:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
INSERT DATA {
[] seq:prepare []
}
Then you can request new values from any sequence by running a query like this (for the sequence http://example.com/my/seq1
):
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
SELECT ?next {
my:seq1 seq:nextValue ?next
}
To query the last new value without incrementing the counter, you can use a query like this:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
SELECT ?current {
my:seq1 seq:currentValue ?current
}
Use the obtained values to construct IRIs, assign IDs, or any other use case.
Using sequence values only on the server¶
In this scenario, new and current sequence values are available only within the execution context of a SPARQL INSERT update. New data using the sequence values can be generated by the same INSERT and added to GraphDB.
The following example prepares the sequences for use and inserts some new data using the sequence http://example.com/my/seq1
where the subject of the newly inserted data is created from a value obtained from the sequence.
The example will work both in:
the GraphDB cluster - as new sequence values do not need to be exposed to the client.
the GraphDB Workbench - as it performs everything in a single transaction by separating individual operations using a semicolon.
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
# Prepares sequences for use
INSERT DATA {
[] seq:prepare []
};
# Obtains a new value from the sequence and creates an IRI based on it,
# then inserts new triples using that IRI
INSERT {
?subject rdfs:label "This is my new document" ;
a my:Type1
} WHERE {
my:seq1 seq:nextValue ?next
BIND(IRI(CONCAT("http://example.com/my-data/test/", STR(?next))) as ?subject)
};
# Retrieves the last obtained value, recreates the same IRI,
# and adds more data using the same IRI
INSERT {
?subject rdfs:comment ?comment ;
} WHERE {
my:seq1 seq:currentValue ?current
BIND(IRI(CONCAT("http://example.com/my-data/test/", STR(?current))) as ?subject)
BIND(CONCAT("The document ID is ", STR(?current)) as ?comment)
}
After that, commit the transaction.
Dropping a sequence¶
Dropping a sequence is similar to creating it. For example, to drop the sequence http://example.com/my/seq1
, execute this:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
INSERT DATA {
my:seq1 seq:drop []
}
Resetting a sequence¶
In some cases, you might want to reset an existing sequence such that its next value will be a different number. Resetting is equivalent to dropping and recreating the sequence.
To reset a sequence such that its next value will be 1
, execute this update:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
INSERT DATA {
my:seq1 seq:reset []
}
You can also reset a sequence by providing the starting value. For example, to reset a sequence such that its next value will be 10
, execute:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#>
PREFIX my: <http://example.com/my/>
INSERT DATA {
my:seq1 seq:reset 10
}
Workaround for using sequence values on the client with the cluster¶
If you need to process your sequence values on the client in a GraphDB 9.x cluster environment, you can create a single-node (i.e., not part of a cluster) worker repository to provide the sequences. It is most convenient to have that repository on the same GraphDB instance as your primary master repository.
Let’s call the master repository where you will store your data master1
and the second worker repository where you will create and use your sequences seqrepo1
.
Managing sequences¶
Execute all create, drop, and reset statements in seqrepo1
.
The examples below assume that you have created a sequence http://example.com/my/seq1
.
Using sequences on the client¶
First, you need to obtain one or more new sequence values from the repository
seqrepo1
:Start a transaction in
seqrepo1
.Prepare the sequences for use by executing this in the same transaction:
PREFIX seq: <http://www.ontotext.com/plugins/sequences#> INSERT DATA { [] seq:prepare [] }
Obtain one or more new sequence values from the sequence
http://example.com/my/seq1
:PREFIX seq: <http://www.ontotext.com/plugins/sequences#> PREFIX my: <http://example.com/my/> SELECT ?next { my:seq1 seq:nextValue ?next }
Commit the transaction in
seqrepo1
.
Then you can process the obtained values on the client, generate new data, and insert it into the master repository
master1
:Start a transaction in
master1
.Insert data using the obtained sequence values.
Commit the transaction in
master1
.
Handling backups¶
To always ensure data consistency with backups, follow this order:
Backup
Backup the master repository
master1
first.Backup the sequence repository
seqrepo1
second.
Restore
Restore the sequence repository
seqrepo1
first.Restore the master repository
master1
second.
An alternative would be to not back up the seqrepo1
repository but simply recreate the repository and the sequence (or reset the sequence) with the next potential sequence value from the master1
repository. Here is a sample query that retrieves the next potential value (which is equal to the last used value + 1):
PREFIX ent: <http://www.ontotext.com/owlim/entity#>
PREFIX my: <http://example.com/my/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?nextValue WHERE {
?type a my:Type1;
ent:id ?id .
BIND(xsd:int(REPLACE(STR(?type), "http://example.com/my-data/test/", "")) + 1 as ?nextValue)
}
ORDER BY DESC(?id)
LIMIT 1
Note that this example assumes that sequence values were used to generate IRIs, and IRIs with higher values were used for the first time after IRIs with lower values were used.