-->

Adding age (integer literals) to Jena RDF triples,

2019-06-11 11:21发布

问题:

I'm trying to learn the basics of working with Jena and RDF Triples. Also working with an Oracle database, so following their guide I have some sample programs running, such as Example7-18 SPARQL OPTIONAL Query. The example works fine as written. It allows for matching queries such as

where {?s <u:parentOf> ?o}

where {<u:John> <u:parentOf> <u:Mary>}

What I'd like to do is give John, Mary and Jill an age each, so that I can query and filter on age as described in SPARQL By Example: The Cheat Sheet, page 10:

A . B . FILTER ( …expr… )

where {?s <u:parentOf> ?o . ?o <u:isAge> ?a . filter ( ?a < 20 ) }

With the current code for triples I can only add strings/URI Nodes, and although I could make a triple such as <u:John> <u:isAge> <u:35>, I cannot filter and make comparisons with, e.g., the < operator on that age, so it is not very useful.

I've been looking around for a while now and I suspect that doing this is very simple but code samples have been hard to find.

回答1:

Note that you want an object like "35"^^xsd:int or "35^^xsd:integer, which are literals, not <u:35> which is a (perhaps malformed) URI. The example is, in my opinion, doing things in a somewhat unusual way, and according to the documentation, it's using some deprecated methods. At any rate, you can see that its creating URI nodes with methods from the Node class (a factory class):

Node.createURI("u:John")
Node.createURI("u:parentOf")
Node.createURI("u:Mary")

There are five createLiteral methods in the Node class, and you could use createLiteral(String lex, RDFDatatype dtype) to create a literal with a datatype. That method is deprecated though, and you really should be using one of the methods from NodeFactory instead.

All that said, I don't know if there's any reason that the example uses the graph interface for creating triples rather than the Model interface. You've already got a model from:

ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName);

and this task is much easier to do if you use the Model interface, where you have methods like createTypedLiteral so that you can simply call createTypedLiteral(30) and get back a suitable literal. Here's an example:

import java.math.BigInteger;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;

public class CreateAndQueryExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // You should be able to replace this with the Oracle model 
        // producing code.
        Model model = ModelFactory.createDefaultModel();

        Resource john = model.createResource( "urn:ex:John" );
        Resource mary = model.createResource( "urn:ex:Mary" );
        Property age = model.createProperty( "urn:ex:age" );

        // Using Model.add method
        model.add( john, age, model.createTypedLiteral( new BigInteger( "25" )));  // "25"^^xsd:integer
        // model.add( john, age, model.createTypedLiteral( 25 ));                  // "25"^^xsd:int
        // model.add( john, age, model.createTypedLiteral( 25l ));                 // "25"^^xsd:long

        // Using the Resource.addProperty method
        mary.addProperty( age, model.createTypedLiteral( new BigInteger( "35" )));

        Query query = QueryFactory.create( "select * where { ?s <urn:ex:age> ?age . filter ( ?age < 30 ) }" );
        QueryExecution exec = QueryExecutionFactory.create( query, model );
        ResultSetFormatter.out( exec.execSelect() );
    }
}
-----------------------
| s             | age |
=======================
| <urn:ex:John> | 25  |
-----------------------