Saturday, June 4, 2011

Jena and DateTime

Before you start storing timestamp literals in your triple store, consider the value of typed literals.  Typed literals can be easily converted to their native language type, in this case - java.util.Calendar.  Furthermore, SPARQL lets you do things like compare and filter on date values. 

Here is a quick JUnit test to illustrate using Jena to create/read triples with dateTime typed literals, as well as using ARQ to query for dateTime literals.

package testjena;
import static org.junit.Assert.*;
import org.junit.Test
import org.junit.Before;
import com.hp.hpl.jena.query.ResultSetFormatter;
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.ResultSet;
import com.hp.hpl.jena.rdf.model.Literal;
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;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.rdf.model.RDFNode;
class TestDateTime {
@Test
public void testJenaDateTime() {
Model model = ModelFactory.createDefaultModel();
Resource resource = model.createResource("http://example.com/resource/test");
Property property = model.createProperty("http://example.com/prop/test");
Calendar cal = GregorianCalendar.getInstance();
Literal value = model.createTypedLiteral(cal);
resource.addProperty(property, value);
/**
* Results in:
*
* Subject: <http://example.com/resource/test>
* Predicate: <http://example.com/prop/test>
* Object: "2011-06-04T19:16:58.869Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>
*
*/
/**
* First, let's use ARQ to retrieve the date via a SPARQL query
*/
String sparql = "SELECT ?s ?p ?o WHERE { ?s ?p ?o }";
Query query = QueryFactory.create(sparql);
QueryExecution qe = QueryExecutionFactory.create(query, model);
Date result;
try {
ResultSet rs = qe.execSelect();
for ( ; rs.hasNext(); ) {
QuerySolution sol = rs.nextSolution();
RDFNode resultNode = sol.get("o");
// traverse the to the date - must be careful you know what you want
// as if these aren't types as dateTime, you'll wind up with nulls to check
result = resultNode.asLiteral().getValue().asCalendar().getTime()
}
}
finally {
qe.close();
}
System.out.println("Resulting date: " + result);
/**
* Now let's try that again, but with using the Jena Model API
*/
Statement stmt = resource.getProperty(property);
Literal resultLiteral = stmt.getLiteral();
Date resultDate = resultLiteral.getValue().asCalendar().getTime();
assertEquals(resultDate, result);
}
}


Some notes on the SPARQL (not shown above):
- A dateTime literal can be used in SORT expressions, e.g. ORDER BY ASC(?date)
- A dateTime literal can be used in FILTER expressions with comparisons such as FILTER ( ?date >= "$someDateTime"^^xsd:dateTime
- Note that in SPARQL, you explicitly type the literal. You should define a PREFIX with xsd: so you can use the short hand

Using xsd:dateTime is a good choice because the API translates to java.util.Calendar, of which you can easily do things like get your hands on a java.util.Date, automatically handle time zones, etc.

1 comment:

  1. Thank you , this is help me to make literal Date time ,,,

    ReplyDelete