blob: 9f0afc95f185e5820be6d46d4b37a237c73d0288 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.accumulo.core.client.Connector;
import org.apache.commons.lang3.Validate;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.NativeCodeLoader;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.rya.accumulo.AccumuloRdfConfiguration;
import org.apache.rya.accumulo.AccumuloRyaDAO;
import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
import org.apache.rya.api.domain.RyaStatement;
import org.apache.rya.api.domain.RyaType;
import org.apache.rya.api.domain.RyaURI;
import org.apache.rya.api.domain.StatementMetadata;
import org.apache.rya.api.persist.RyaDAOException;
import org.apache.rya.indexing.accumulo.ConfigUtils;
import org.apache.rya.indexing.statement.metadata.matching.StatementMetadataNode;
import org.apache.rya.indexing.statement.metadata.matching.StatementMetadataOptimizer;
import org.apache.rya.sail.config.RyaSailFactory;
import org.eclipse.rdf4j.model.vocabulary.XMLSchema;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.MalformedQueryException;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.QueryResultHandlerException;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResultHandler;
import org.eclipse.rdf4j.query.TupleQueryResultHandlerException;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.parser.ParsedQuery;
import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
import org.eclipse.rdf4j.sail.Sail;
import org.eclipse.rdf4j.sail.SailException;
public class StatementMetadataExample {
private static final Logger log = Logger.getLogger(StatementMetadataExample.class);
private AccumuloRyaDAO dao;
private Sail sail;
private SailRepository repository;
private SailRepositoryConnection conn;
public StatementMetadataExample(AccumuloRdfConfiguration conf) throws Exception {
Connector aConn = ConfigUtils.getConnector(conf);
dao = new AccumuloRyaDAO();
dao.setConnector(aConn);
dao.init();
sail = RyaSailFactory.getInstance(conf);
repository = new SailRepository(sail);
conn = repository.getConnection();
}
public static void main(final String[] args) throws Exception {
setLogger();
StatementMetadataExample example = new StatementMetadataExample(getConf());
example.example1();
example.example2();
example.example3();
example.example4();
example.close();
}
/**
* This example demonstrates how a reified query can be used to return
* metadata. In the example below, the query returns all the places that Joe
* works at along with the people that created the triples containing those locations
* and the dates that those triples were created on.
*
* @throws Exception
*/
private void example1() throws Exception {
String query1 = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX owl: <http://www.w3.org/2002/07/owl#> \n"
+ "SELECT ?x ?y ?z \n"
+ "WHERE {\n"
+ "_:blankNode rdf:type owl:Annotation. \n"
+ "_:blankNode owl:annotatedSource <http://Joe>. \n"
+ "_:blankNode owl:annotatedProperty <http://worksAt>. \n"
+ "_:blankNode owl:annotatedTarget ?x. \n"
+ "_:blankNode <http://createdBy> ?y. \n"
+ "_:blankNode <http://createdOn> ?z }\n";
StatementMetadata metadata1 = new StatementMetadata();
metadata1.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata1.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02"));
RyaStatement statement1 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("CoffeeShop"), new RyaURI("http://context"), "", metadata1);
StatementMetadata metadata2 = new StatementMetadata();
metadata2.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata2.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04"));
RyaStatement statement2 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("HardwareStore"), new RyaURI("http://context"), "", metadata2);
StatementMetadata metadata3 = new StatementMetadata();
metadata3.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Fred"));
metadata3.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08"));
RyaStatement statement3 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("Library"), new RyaURI("http://context"), "", metadata3);
// add statements for querying
dao.add(statement1);
dao.add(statement2);
dao.add(statement3);
System.out.println("**************************************************************************");
System.out.println(" RUNNING EXAMPLE 1");
System.out.println("**************************************************************************");
System.out.println("");
// issue query - 3 results expected
query(query1, 3);
// delete statements to run next example
dao.delete(Arrays.asList(statement1, statement2, statement3).iterator(), getConf());
}
/**
* This example demonstrates how a reified query can be used to return
* metadata and that a query can contain a mix of reified metadata triple
* patterns and non-reified triple patterns. In the query below, all patterns
* containing _:blankNode in the subject will be grouped into a
* {@link StatementMetadataNode}, so the resulting query plan will consist
* of this metadata node joined along the variable ?x
* with the non-reified pattern ?x <http://locatedWithin> <http://UnitedState>.
* In the example below, the query returns all locations that Doug
* travels to in the UnitedStates and the timeStamp of the triples containing
* that information. This example further demonstrates that any number
* of registered metadata properties can be queried using the contextual metadata index.
*
* @throws Exception
*/
private void example2() throws Exception {
String query2 = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX owl: <http://www.w3.org/2002/07/owl#> \n"
+ "SELECT ?x ?y \n" + "WHERE {\n"
+ "_:blankNode rdf:type owl:Annotation. \n"
+ "_:blankNode owl:annotatedSource <http://Doug>. \n"
+ "_:blankNode owl:annotatedProperty <http://travelsTo>. \n"
+ "_:blankNode owl:annotatedTarget ?x. \n"
+ "?x <http://locatedWithin> <http://UnitedStates> . \n"
+ "_:blankNode <http://hasTimeStamp> ?y }\n";
StatementMetadata metadata = new StatementMetadata();
metadata.addMetadata(new RyaURI("http://hasTimeStamp"), new RyaType(XMLSchema.TIME, "09:30:10.5"));
RyaStatement statement1 = new RyaStatement(new RyaURI("http://Doug"), new RyaURI("http://travelsTo"),
new RyaURI("http://NewMexico"), new RyaURI("http://context"), "", metadata);
RyaStatement statement2 = new RyaStatement(new RyaURI("http://NewMexico"), new RyaURI("http://locatedWithin"),
new RyaType("http://UnitedStates"), new RyaURI("http://context"), "", new StatementMetadata());
// add statements for querying
dao.add(statement1);
dao.add(statement2);
System.out.println("**************************************************************************");
System.out.println(" RUNNING EXAMPLE 2");
System.out.println("**************************************************************************");
System.out.println("");
// issue query - 1 results expected
query(query2, 1);
// delete statements to run next example
dao.delete(Arrays.asList(statement1, statement2).iterator(), getConf());
}
/**
* In addition to returning metadata, this example demonstrates how a
* reified query can be used to return only those triples matching certain
* metadata criteria. The query below returns only those triples containing Joe's
* work location that were created on 2017-02-04. To filter by metadata property, simply set the
* value for the property to a fixed constant ('2017-02-04'^^xsd:date is set for the property
* http://createdOn in the query below).
*
* @throws Exception
*/
private void example3() throws Exception {
String query3 = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX owl: <http://www.w3.org/2002/07/owl#> \n"
+ "SELECT ?x ?y \n"
+ "WHERE {\n"
+ "_:blankNode rdf:type owl:Annotation. \n"
+ "_:blankNode owl:annotatedSource <http://Joe>. \n"
+ "_:blankNode owl:annotatedProperty <http://worksAt>. \n"
+ "_:blankNode owl:annotatedTarget ?x. \n"
+ "_:blankNode <http://createdBy> ?y. \n"
+ "_:blankNode <http://createdOn> '2017-02-04'^^xsd:date }\n";
StatementMetadata metadata1 = new StatementMetadata();
metadata1.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata1.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02"));
RyaStatement statement1 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("CoffeeShop"), new RyaURI("http://context"), "", metadata1);
StatementMetadata metadata2 = new StatementMetadata();
metadata2.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata2.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04"));
RyaStatement statement2 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("HardwareStore"), new RyaURI("http://context"), "", metadata2);
StatementMetadata metadata3 = new StatementMetadata();
metadata3.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Fred"));
metadata3.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08"));
RyaStatement statement3 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("Library"), new RyaURI("http://context"), "", metadata3);
// add statements for querying
dao.add(statement1);
dao.add(statement2);
dao.add(statement3);
System.out.println("**************************************************************************");
System.out.println(" RUNNING EXAMPLE 3");
System.out.println("**************************************************************************");
System.out.println("");
// issue query - 1 result expected
query(query3, 1);
// delete statements to run next example
dao.delete(Arrays.asList(statement1, statement2, statement3).iterator(), getConf());
}
/**
*
* This example demonstrates the ability to join across two differnt StatementMetadataNodes.
* The query below consists of triple patterns with _:blankNode1 as the subject and patterns
* with _:blankNode2 as the subject. Each of these groups of patterns will be used to form
* a @link{StatementMetadataNode} to efficiently query for the underlying triples and metadata.
* The effective query plan of the following query will consist of two StatementMetaData nodes
* that will be joined on the variables ?x and ?y -- the values of owl:annotatedTarget and the
* metadata property http://createdBy. So the query below will return the work locations that Joe
* and Bob have in common that appear in triples created by the same person, in addition to the dates
* that each triple was created on.
*
* @throws Exception
*/
private void example4() throws Exception {
String query4 = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX owl: <http://www.w3.org/2002/07/owl#> \n"
+ "SELECT ?x ?y ?z ?a \n" + "WHERE {\n"
+ "_:blankNode1 rdf:type owl:Annotation. \n"
+ "_:blankNode1 owl:annotatedSource <http://Joe>. \n"
+ "_:blankNode1 owl:annotatedProperty <http://worksAt>. \n"
+ "_:blankNode1 owl:annotatedTarget ?x. \n"
+ "_:blankNode1 <http://createdBy> ?y. \n"
+ "_:blankNode1 <http://createdOn> ?z. \n"
+ "_:blankNode2 rdf:type owl:Annotation. \n"
+ "_:blankNode2 owl:annotatedSource <http://Bob>. \n"
+ "_:blankNode2 owl:annotatedProperty <http://worksAt>. \n"
+ "_:blankNode2 owl:annotatedTarget ?x. \n"
+ "_:blankNode2 <http://createdBy> ?y. \n"
+ "_:blankNode2 <http://createdOn> ?a }\n";
StatementMetadata metadata1 = new StatementMetadata();
metadata1.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata1.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02"));
RyaStatement statement1 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("CoffeeShop"), new RyaURI("http://context"), "", metadata1);
StatementMetadata metadata2 = new StatementMetadata();
metadata2.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata2.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04"));
RyaStatement statement2 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("HardwareStore"), new RyaURI("http://context"), "", metadata2);
StatementMetadata metadata3 = new StatementMetadata();
metadata3.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Fred"));
metadata3.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08"));
RyaStatement statement3 = new RyaStatement(new RyaURI("http://Joe"), new RyaURI("http://worksAt"),
new RyaType("Library"), new RyaURI("http://context"), "", metadata3);
StatementMetadata metadata4 = new StatementMetadata();
metadata4.addMetadata(new RyaURI("http://createdBy"), new RyaURI("http://Dave"));
metadata4.addMetadata(new RyaURI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-04-16"));
RyaStatement statement4 = new RyaStatement(new RyaURI("http://Bob"), new RyaURI("http://worksAt"),
new RyaType("HardwareStore"), new RyaURI("http://context"), "", metadata4);
// add statements for querying
dao.add(statement1);
dao.add(statement2);
dao.add(statement3);
dao.add(statement4);
System.out.println("**************************************************************************");
System.out.println(" RUNNING EXAMPLE 4");
System.out.println("**************************************************************************");
System.out.println("");
// issue query - 1 result expected
query(query4, 1);
// delete statements to run next example
dao.delete(Arrays.asList(statement1, statement2, statement3, statement4).iterator(), getConf());
}
public void query(String query, int expected) throws Exception {
prettyPrintQuery(query);
prettyPrintQueryPlan(query);
CountingResultHandler resultHandler = new CountingResultHandler();
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, query);
tupleQuery.evaluate(resultHandler);
Validate.isTrue(expected == resultHandler.getCount());
}
private static AccumuloRdfConfiguration getConf() {
AccumuloRdfConfiguration conf;
Set<RyaURI> propertySet = new HashSet<RyaURI>(Arrays.asList(new RyaURI("http://createdBy"),
new RyaURI("http://createdOn"), new RyaURI("http://hasTimeStamp")));
conf = new AccumuloRdfConfiguration();
conf.setDisplayQueryPlan(false);
conf.setBoolean(ConfigUtils.USE_MOCK_INSTANCE, true);
conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya_");
conf.set(ConfigUtils.CLOUDBASE_USER, "root");
conf.set(ConfigUtils.CLOUDBASE_PASSWORD, "");
conf.set(ConfigUtils.CLOUDBASE_INSTANCE, "instance");
conf.set(ConfigUtils.CLOUDBASE_AUTHS, "");
conf.setUseStatementMetadata(true);
conf.setStatementMetadataProperties(propertySet);
return conf;
}
public void close() {
try {
System.out.println("Closing SailRepositoryConnection");
conn.close();
System.out.println("Shutting down SailRepository");
repository.shutDown();
System.out.println("Shutting down Sail.");
sail.shutDown();
dao.destroy();
} catch (RyaDAOException | RepositoryException | SailException e) {
System.out.println("Unable to cleanly shut down all resources.");
e.printStackTrace();
System.exit(0);
}
}
private void prettyPrintQuery(String query) {
System.out.println("=================== SPARQL QUERY ============================");
for (String str : query.split("\\r?\\n")) {
System.out.println(str);
}
System.out.println("=================== END SPARQL QUERY ========================");
System.out.println("");
}
private void prettyPrintQueryPlan(String query) throws MalformedQueryException {
SPARQLParser parser = new SPARQLParser();
ParsedQuery pq = parser.parseQuery(query, null);
TupleExpr exp = pq.getTupleExpr();
new StatementMetadataOptimizer(getConf()).optimize(exp,null,null);
System.out.println("=================== RYA SPARQL QUERY PLAN ===================");
for (String str : exp.toString().split("\\r?\\n")) {
System.out.println(str);
}
System.out.println("=================== END RYA QUERY PLAN ======================");
}
private static void setLogger() {
Logger.getLogger(Configuration.class).setLevel(Level.ERROR);
Logger.getLogger(NativeCodeLoader.class).setLevel(Level.ERROR);
Logger.getLogger(RyaSailFactory.class).setLevel(Level.ERROR);
}
private static class CountingResultHandler implements TupleQueryResultHandler {
private int count = 0;
public int getCount() {
return count;
}
@Override
public void startQueryResult(final List<String> arg0) throws TupleQueryResultHandlerException {
}
@Override
public void handleSolution(final BindingSet arg0) throws TupleQueryResultHandlerException {
if (count == 0) {
System.out.println("");
System.out.println("==================== QUERY RESULTS ==========================");
}
System.out.println(arg0);
count++;
}
@Override
public void endQueryResult() throws TupleQueryResultHandlerException {
System.out.println("==================== END QUERY RESULTS ======================");
System.out.println("");
System.out.println("");
System.out.println("");
}
@Override
public void handleBoolean(final boolean arg0) throws QueryResultHandlerException {
}
@Override
public void handleLinks(final List<String> arg0) throws QueryResultHandlerException {
}
}
}