-
-
Save pchampin/ab3d01d2c3c245042dc5 to your computer and use it in GitHub Desktop.
from rdflib import BNode, URIRef | |
from rdflib.plugins.stores.sparqlstore import SPARQLUpdateStore, _node_to_sparql, _node_from_result, SPARQL_NS | |
from uuid import uuid4 | |
def _virtuoso_compatible_generator(): | |
return unicode(uuid4().int % 2**61) | |
# monkey patch BNode to make it virtuoso compatible | |
BNode.__new__.func_defaults = (None, _virtuoso_compatible_generator, 'b') | |
def _virtuoso_node_to_sparql(node): | |
if isinstance(node, BNode): | |
return '<nodeID://{}>'.format(node) | |
else: | |
return node.n3() | |
def _virtuoso_node_from_result(element): | |
if element.tag == '{%s}bnode' % SPARQL_NS: | |
return BNode(element.text[9:]) | |
else: | |
return _node_from_result(element) | |
class VSPARQLStore(SPARQLUpdateStore): | |
def __init__(self, endpoint, username, password, **kwargs): | |
SPARQLUpdateStore.__init__(self, endpoint, endpoint, | |
node_to_sparql=_virtuoso_node_to_sparql, | |
node_from_result=_virtuoso_node_from_result, | |
**kwargs) | |
self.setHTTPAuth('digest') | |
self.setCredentials(username, password) | |
if __name__ == "__main__": | |
from rdflib import Namespace, Graph, Literal | |
from rdflib.collection import Collection | |
EX = Namespace('http://example.org/') | |
store = VSPARQLStore('http://localhost:8890/sparql-auth', 'dba', 'dba') | |
g = Graph(store, EX.g) | |
g.remove((None, None, None)) | |
print(len(g)) | |
bn = BNode() | |
g.add((EX.s, EX.pb, bn)) | |
g.add((bn, EX.pb, Literal("foo"))) | |
lh = BNode() | |
g.add((EX.s, EX.pl, lh)) | |
lst = Collection(g, lh, map(Literal, [1,2,3])) | |
print(len(g)) | |
print(g.serialize(format="turtle")) | |
g.remove((None, None, None)) |
Unfortunetaly, both solutions do not work, because of the very problems you envisioned in your comments.
Indeed, Virtuoso only accept up to 19 decimal digits with nodeID:// (and even then, some numbers are too big...).
Ok, I found a way to get rid of the global mapping table (revision 2).
It involves an ugly hack (monkeypatching the default parameters of BNode.__new__
), and is not 100% robust (it will break with BNodes created with an explicit ID, for example those generated by some parsers). So I have mixed feelings about it.
... you seem to like living in the danger zone 😄
Monkeypatching obviously isn't that optimal, but to be honest i currently don't see a better way to do this (so being able to also configure BNode creation from a SPARQLStore in a way that doesn't have the potential to break things outside of it) ...
so, suggestions welcome, but till then 👍
hmmm, i'm thinking about ways to get rid of that mapping dict, which would work if we could re-create the right BNode from the SPARQL result...
i'm not entirely sure if virtuoso lets us use non integer variants, that would be easiest...
if that doesn't work one could think about using the uuid int rep of the BNode... this only works for BNodes without specified identifier though:
but i suspect virtuoso nodeIDs not to be 128 bit long...