rdfquery + sparql update + edit in place

17 views
Skip to first unread message

melvincarvalho

unread,
Aug 16, 2009, 4:54:34 PM8/16/09
to rdfQuery
Hi All

I'm working on a little project to provide read/write ability to an
(arbitrary) RDFa page using RDFQuery and SPARQL Update (SPARUL).

I was wondering if you might have any insights on, a good way of going
about it.

Here's the concept:

1. A standard page is marked up in RDFa

2. I use the following library to turn an RDFa element (say span) into
an input box via "edit in place"

http://code.google.com/p/jquery-in-place-editor/source/browse/trunk/src/jquery.editinplace.js?spec=svn5&r=5

3. I then use RDFQuery to work out what the triples were before, and
what the triples are after, and generate the appropriate SPARUL

4. The page itself is a datawiki which accepts SPARUL via HTTP POST,
which can be sent via jquery

5. The back end script updates the triple store, and triggers a reload
or a client side update of the data

5. Similar techniques are used for adding and delete (though edit is
probably the trickiest)

I have most of (1)-(6) in place, but was curious as whether there's a
good way of achieving (3) it to go from RDFa to SPARUL using
RDFQuery.

Hope that makes sense

Thanks
Melvin

Jeni Tennison

unread,
Aug 16, 2009, 5:15:26 PM8/16/09
to rdfq...@googlegroups.com
Hi Melvin,

On 16 Aug 2009, at 21:54, melvincarvalho wrote:
> I'm working on a little project to provide read/write ability to an
> (arbitrary) RDFa page using RDFQuery and SPARQL Update (SPARUL).
>
> I was wondering if you might have any insights on, a good way of going
> about it.

> [snip]


> 3. I then use RDFQuery to work out what the triples were before, and
> what the triples are after, and generate the appropriate SPARUL

> [snip]


> I have most of (1)-(6) in place, but was curious as whether there's a
> good way of achieving (3) it to go from RDFa to SPARUL using
> RDFQuery.


You can do this by:

1. creating a rdfQuery object containing the triples before any
editing takes place, using something like:

var before = $('html').rdf().databank;

2. creating another rdfQuery object containing the triples after the
edits are done, using something like:

var after = $('html').rdf().databank;

3. creating the SPARUL using normal Javascript string manipulation.
You can find out which triples have been removed and added using the
$.rdf.databank.except() method, and you can use the fact that the
string value of a triple uses the same representation as is expected
in SPARQL. So I think you can just do something like:

var sparul = 'DELETE DATA { ';
before
.except(after)
.triples()
.each(function () {
sparul += this + ' ';
})
sparul += '} INSERT DATA { ';
after
.except(before)
.triples()
.each(function () {
sparul += this + ' ';
})
sparul += '}';

Let us know whether that works for you, and whether there's anything
that you think rdfQuery could do to make what you're doing easier.

Cheers,

Jeni
--
Jeni Tennison
http://www.jenitennison.com

Melvin Carvalho

unread,
Aug 18, 2009, 6:27:15 AM8/18/09
to rdfq...@googlegroups.com
Thanks so much for the swift response!

This works brilliantly, I'll post a link here when my little rdfquery
project is working.

james

unread,
Sep 18, 2009, 4:43:15 PM9/18/09
to rdfQuery
Hi Jeni and Melvin,

I have been working on a similar challenge, but one that involves
BNodes. The script below anchors the BNodes to all connected URIs and
Literals. I am posting it here for suggestions on how to improve its
speed.

var stored = readRDF()
form.submit(function(){
var revised = readRDF()
var removed = $.rdf.databank([])
stored.except(revised).triples().each(function(){
addBoundedDescription(this, stored, removed)
})
var added = $.rdf.databank([])
revised.except(stored).triples().each(function(){
addBoundedDescription(this, revised, added)
})
// create the query here with removed and added
})

function addBoundedDescription(triple, store, description) {
var size = description.size()
description.add(triple)
if (description.size() > size) {
if (triple.subject.type == "bnode") {
var bnode = triple.subject
store.triples().each(function(){
if (this.object.value == bnode.value) {
addBoundedDescription(this, store, description)
}
})
}
if (triple.object.type == "bnode") {
var bnode = triple.object
store.triples().each(function(){
if (this.subject.value == bnode.value) {
addBoundedDescription(this, store, description)
}
})
}
}
}

Thanks,
James
--
James Leigh Services Inc.
http://www.leighnet.ca/
http://jamesrdf.blogspot.com/

Jeni Tennison

unread,
Sep 18, 2009, 6:01:49 PM9/18/09
to rdfq...@googlegroups.com
James,


I don't know if it would help you any, but the
$.rdf.databank.describe() method creates a simple concise bounded
description [1] of whatever subject you pass to it. So you could, I
think, do something like:

removed = stored.except(revised);
removed
.where('?s ?p ?o')
.each(function () {
stored
.describe(this.s)
.each(function () {
removed.add(this);
});
})

This would be speeded up if you didn't iterate over all the triples --
if you only iterated once per subject. You can do that with the new
group() method which is in the trunk version of the code but not
currently released. I think this might work:

removed = stored.except(revised);
removed
.where('?s ?p ?o')
.group('s')
.each(function () {
stored
.describe(this.s)
.each(function () {
removed.add(this);
});
})

but it might not; looks like group() returns an array rather than a
jQuery object, which makes things rather less elegant. I'll change that.

In general you will be better off using the rdfQuery methods for
locating items within a databank than iterating over the databank
triples. rdfQuery uses indexes on the databank and a Rete algorithm to
help speed up searches over the databank (though you won't benefit
from the latter when you're only doing a couple of searches).

For example, instead of:

> var bnode = triple.object
> store.triples().each(function(){
> if (this.subject.value == bnode.value) {
> addBoundedDescription(this, store, description)
> }
> })


you should do something like:

var bnode = triple.subject;
$.rdf({databank: store})
.where(bnode + ' ?p ?o')
.each(function (i, bindings, triples) {
addBoundedDescription(triples[0], store, description);
});

All code untested and written whilst mildly intoxicated. Good luck!
Let us know how you get on, and if anything can be made simpler for you.

Cheers,

Jeni

[1]: http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF#Simple_Concise_Bounded_Description

james

unread,
Sep 22, 2009, 10:04:12 AM9/22/09
to rdfQuery
Hi Jeni,

Can you explain what this code is doing (within the init function)? It
represents a significant percentage of the process time for me.

if (this.filterExp !== undefined) {
if (!$.isFunction(this.filterExp)) {
registerQuery(this.databank, this);
this.alphaMemory = findMatches(this.databank.triples(),
this.filterExp);
}
}

It is called from the where call in this function I wrote.

function getObjects(subj, pred, store) {
return $.rdf({databank: store}).where(subj + " <" + pred + "> ?
obj").map(function(i, bindings) {
return bindings['obj']
})
}

Jeni Tennison

unread,
Sep 22, 2009, 10:38:33 AM9/22/09
to rdfq...@googlegroups.com
James,


It's doing the filtering itself. It looks like you're not using the
trunk version of rdfQuery; there, I've updated findMatches to use the
indexes within the databank much better, so you might find a
performance improvement if you move to trunk.

If you're calling getObjects repeatedly, iterating over different
predicates on the same subject, you *might* find it more efficient to
use two steps like:

return $.rdf({ databank: store })
.about(subj)
.where(subj + ' <' + pred + '> ?obj')
.map(function () { return this.obj; });

Cheers,

Jeni

Reply all
Reply to author
Forward
0 new messages