-->

Querying named RDF graphs in TDB using tdbquery

2020-04-26 04:06发布

问题:

I am trying to query my newly created TDB database use the tdbquery program. However, I am having a hard time writing a query that targets the correct named graph. I am doing the following:

First a create a new dataset and add a name graph called "facts"

Dataset dataset = TDBFactory.createDataset("/tdb/");
dataset.begin(ReadWrite.WRITE) ;

try {
    Model facts = RDFDataMgr.loadModel("lineitem.ttl") ;
    dataset.addNamedModel("facts", facts);
    dataset.commit();
    TDB.sync(dataset);
    dataset.end();

} finally {
    dataset.close();
}

When I query all graphs in my TDB database it looks fine.

./tdbquery --loc /tdb/ "SELECT * { GRAPH ?g { ?s ?p ?o } }"

--------------------------------------------------
| s         | p           | o          | g       |
==================================================
| <fact1>   | <predicate> | <nation>   | <facts> |
| <fact2>   | <predicate> | <region>   | <facts> |
--------------------------------------------------

If I try to query the named graph I do not find and triples.

./tdbquery -v --loc /tdb/ "SELECT * { GRAPH <facts> { ?s ?p ?o } }"
OR
./tdbquery -v --loc /tdb/ "SELECT * FROM NAMED <facts> WHERE { ?s ?p ?o }"

-------------
| s | p | o |
=============
-------------

When I look at the algebra version of the query I see that the context (the graph) in my quad is wrong.

INFO  exec                 :: ALGEBRA
(quadpattern (quad <file:///usr/local/apache-jena-2.12.1/bin/facts> ?s ?p ?o))

I know that the quad pattern should be: (quad ?s ?p ?o)

How do I query a named graph in a TDB database?

Regards

回答1:

When I look at the algebra version of the query I see that the context (the graph) in my quad is wrong.

INFO  exec                 :: ALGEBRA
(quadpattern (quad <file:///usr/local/apache-jena-2.12.1/bin/facts> ?s ?p ?o))

I know that the quad pattern should be: (quad ?s ?p ?o)

No its correct (if not what you expect)

A quadpattern searches against quads and so includes 4 fields the first of which is the name of the graph to be searched

And this is where your problem lies, graph names are URIs but you only provided facts as the name which is treated as a relative URI and as such subject to resolution which may differ in different parts of the system.

In your example the query parser uses the working directory as the Base URI leading to the strange graph name you see in the algebra plan.

You can see exactly what graph names are in the TDB store by issuing the following query:

SELECT ?g WHERE { GRAPH ?g { } }

If you get an absolute URI back then you can specify that directly in your original query, if you do not then there is no way to query for it from the command line.

Fixing your Issue

Don't use relative URIs wherever possible. If you do want to use them then don't use them without specifying a base URI explicitly

So in your code where you load the data make sure you give an absolute URI to the graph e.g.

dataset.addNamedModel("http://example.org/facts", facts);

And if you do want to be able to use relative URIs to refer to your graph in your queries use an appropriate BASE declaration so the URI is resolved as you want it e.g.

./tdbquery -v --loc /tdb/ "BASE <http://example.org/> SELECT * { GRAPH <facts> { ?s ?p ?o } }"


回答2:

The problem here is that you have put a relative URI graph name into the data. RDF is define to work with absolute URIs (i.e start with "http:" or some other URI-scheme name).

Try

RDFDataMgr.write(System.out, dataset, Lang.NQUADS)

to see more clearly what's in the dataset. The output of tdbquery may invoke URI shorteners so some of your data has absolute URIs and some relative but it looks the same in the text format.

When "SELECT * { GRAPH { ?s ?p ?o } }" is parsed, just like if you read data from a file, relative URIs are resolved - the base URI is where the code is running so you get file:///usr/local/apache-jena-2.12.1/bin/facts

Try dataset.addNamedModel("http://example/facts", facts);

PS 1

Model m = dataset.getNamedModel("http://example/facts") ;
m.read("lineitem.ttl") ;

PS 2 sync() isn't necessary if you use transactions