Reputation: 313
I am currently writing a service which creates new items (data) by user input. To save these items in a RDF Graph Store (currently using Sesame via Sparql 1.1), I need to add a subject URI to the data. My approach is to use a number that is incremented for each new item. So e.g.:
<http://example.org/item/15> dct:title "Example Title" .
<http://example.org/item/16> dct:title "Other Item" .
What's the best approach to get an incremented number for new items (like auto incement in MySQL/MongoDB) via Sparql? Or to issue some data and the endpoint autmatically creates a URI by a template (like done for blank nodes). But I don't want to use blank nodes as subjects for these items. Is there a better solution than using an incremented number? My users don't care about the the URI.... and I don't want to handle collisions like created by hashing the data and using the hash as part of the subject.
Upvotes: 3
Views: 2049
Reputation: 786
If you maintain a designated counter during updates, then something along these lines will do it,
fisrt insert a counter into your dataset
insert data {
graph <urn:counters> {<urn:Example> <urn:count> 1 }
}
then a typical update should looks like:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
delete {
#remove the old value of the counter
graph <urn:counters> {<urn:Example> <urn:count> ?old}
}
insert {
#update the new value of the counter
graph <urn:counters> {<urn:Example> <urn:count> ?new}
# add your new data using the constructed IRI
GRAPH <http://example.com> {
?id dct:title "Example Title" ;
a <http://example.org/ontology/Example> .
} .
} where {
# retrieve the counter
graph <urn:counters> {<urn:Example> <urn:count> ?old}
# compute the new value
bind(?old+1 as ?new)
#construct the IRI
bind(IRI(concat("http://example.org/item/", str(?old))) as ?id)
}
Upvotes: 3
Reputation: 9482
You said you are open to other options than an auto-incremented number. One good alternative is to use UUIDs.
If you don't care at all what the URI looks like, you can use the UUID
function:
INSERT {
?uri dct:title "Example Title"
}
WHERE {
BIND (UUID() AS ?uri)
}
This will generate URIs like <urn:uuid:b9302fb5-642e-4d3b-af19-29a8f6d894c9>
.
If you'd rather have HTTP URIs in your own namespace, you can use strUUID
:
INSERT {
?uri dct:title "Example Title"
}
WHERE {
BIND (IRI(CONCAT("http://example.org/item/", strUUID())) AS ?uri)
}
This will generate URIs like http://example.org/item/73cd4307-8a99-4691-a608-b5bda64fb6c1
.
UUIDs are pretty good. Collision risk is negligible. The functions are part of the SPARQL standard. The only downside really is that they are long and ugly.
Upvotes: 2
Reputation: 654
Assuming the class of your items is http://example.org/ontology/Example
, the query becomes the following. Note: items must be inserted one by one, as only one new URI is computed at each transaction.
PREFIX dct: <http://purl.org/dc/terms/>
INSERT {
GRAPH <http://example.com> {
?id dct:title "Example Title" ;
a <http://example.org/ontology/Example> .
} .
} WHERE {
SELECT ?id WHERE {
{
SELECT (count(*) AS ?c) WHERE {
GRAPH <http://example.com> { ?s a <http://example.org/ontology/Example> }
}
}
BIND(IRI(CONCAT("http://example.org/item/", STR(?c))) AS ?id)
}
}
(Tested with GraphDB 8.4.0 using RDF4J 2.2.2)
Upvotes: 2