| |
| /* |
| * 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.RyaIRI; |
| 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 RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata1.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02")); |
| |
| RyaStatement statement1 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("CoffeeShop"), new RyaIRI("http://context"), "", metadata1); |
| |
| StatementMetadata metadata2 = new StatementMetadata(); |
| metadata2.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata2.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04")); |
| |
| RyaStatement statement2 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("HardwareStore"), new RyaIRI("http://context"), "", metadata2); |
| |
| StatementMetadata metadata3 = new StatementMetadata(); |
| metadata3.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Fred")); |
| metadata3.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08")); |
| |
| RyaStatement statement3 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("Library"), new RyaIRI("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 RyaIRI("http://hasTimeStamp"), new RyaType(XMLSchema.TIME, "09:30:10.5")); |
| |
| RyaStatement statement1 = new RyaStatement(new RyaIRI("http://Doug"), new RyaIRI("http://travelsTo"), |
| new RyaIRI("http://NewMexico"), new RyaIRI("http://context"), "", metadata); |
| RyaStatement statement2 = new RyaStatement(new RyaIRI("http://NewMexico"), new RyaIRI("http://locatedWithin"), |
| new RyaType("http://UnitedStates"), new RyaIRI("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 RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata1.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02")); |
| |
| RyaStatement statement1 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("CoffeeShop"), new RyaIRI("http://context"), "", metadata1); |
| |
| StatementMetadata metadata2 = new StatementMetadata(); |
| metadata2.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata2.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04")); |
| |
| RyaStatement statement2 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("HardwareStore"), new RyaIRI("http://context"), "", metadata2); |
| |
| StatementMetadata metadata3 = new StatementMetadata(); |
| metadata3.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Fred")); |
| metadata3.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08")); |
| |
| RyaStatement statement3 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("Library"), new RyaIRI("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 RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata1.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-01-02")); |
| |
| RyaStatement statement1 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("CoffeeShop"), new RyaIRI("http://context"), "", metadata1); |
| |
| StatementMetadata metadata2 = new StatementMetadata(); |
| metadata2.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata2.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-02-04")); |
| |
| RyaStatement statement2 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("HardwareStore"), new RyaIRI("http://context"), "", metadata2); |
| |
| StatementMetadata metadata3 = new StatementMetadata(); |
| metadata3.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Fred")); |
| metadata3.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-03-08")); |
| |
| RyaStatement statement3 = new RyaStatement(new RyaIRI("http://Joe"), new RyaIRI("http://worksAt"), |
| new RyaType("Library"), new RyaIRI("http://context"), "", metadata3); |
| |
| StatementMetadata metadata4 = new StatementMetadata(); |
| metadata4.addMetadata(new RyaIRI("http://createdBy"), new RyaIRI("http://Dave")); |
| metadata4.addMetadata(new RyaIRI("http://createdOn"), new RyaType(XMLSchema.DATE, "2017-04-16")); |
| |
| RyaStatement statement4 = new RyaStatement(new RyaIRI("http://Bob"), new RyaIRI("http://worksAt"), |
| new RyaType("HardwareStore"), new RyaIRI("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<RyaIRI> propertySet = new HashSet<RyaIRI>(Arrays.asList(new RyaIRI("http://createdBy"), |
| new RyaIRI("http://createdOn"), new RyaIRI("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 { |
| } |
| } |
| } |