From 1ef8a2502532dd1736c1e3d6a1ff78ed6b8b643c Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Thu, 30 Sep 2021 12:32:25 +0100 Subject: Refactor query answering to use named graphs --- .../scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 176 ++++++++++++++------- .../ox/cs/rsacomb/filtering/FilteringProgram.scala | 3 + .../rsacomb/filtering/NaiveFilteringProgram.scala | 9 +- .../filtering/RevisedFilteringProgram.scala | 4 +- .../scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala | 38 +++-- 5 files changed, 148 insertions(+), 82 deletions(-) diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala index 8e05f3a..6e9a119 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala @@ -96,7 +96,10 @@ object RSAOntology { * @param query the query to derive the filtering program * @return the filtering program for the given query */ - def filteringProgram(query: ConjunctiveQuery): FilteringProgram = + def filteringProgram( + graph: String, + query: ConjunctiveQuery + ): FilteringProgram = Logger.timed( FilteringProgram(FilterType.REVISED)(query), "Generating filtering program", @@ -496,76 +499,131 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = this.self(axiom) | this.cycle(axiom) - def ask(queries: Seq[ConjunctiveQuery]): Seq[ConjunctiveQueryAnswers] = ??? - - /** Returns the answers to a query + /** Returns the answers to a collection of queries * - * @param query query to execute - * @return a collection of answers + * @param queries a sequence of conjunctive queries to answer. + * @return a collection of answers for each query. */ - def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( - { - val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) - val canon = this.canonicalModel - val filter = RSAOntology.filteringProgram(query) - - /* Upload data from data file */ - RDFoxUtil.addData(data, datafiles: _*) - - RDFoxUtil printStatisticsFor data - - /* Top / equality axiomatization */ - RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) - - /* Generate `named` predicates */ - RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named) - data.evaluateUpdate( - null, // the base IRI for the query (if null, a default is used) - RSA.Prefixes, - "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }", - new java.util.HashMap[String, String] - ) - - /* Add canonical model */ - Logger print s"Canonical model rules: ${canon.rules.length}" - RDFoxUtil.addRules(data, canon.rules) - - Logger print s"Canonical model facts: ${canon.facts.length}" - RDFoxUtil.addFacts(data, canon.facts) + def ask(queries: Seq[ConjunctiveQuery]): Seq[ConjunctiveQueryAnswers] = { + val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) + val canonNamedGraph = "http://cs.ox.ac.uk/isg/RSAComb#CanonicalModel" + // Create a new NamedGraph for the canonical model + data.createTupleTable(canonNamedGraph, Map("type" -> "named-graph").asJava) + + /* Upload data from data file */ + RDFoxUtil.addData(canonNamedGraph, data, datafiles: _*) + /* Top / equality axiomatization */ + RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) + /* Generate `named` predicates */ + RDFoxUtil.addFacts( + canonNamedGraph, + data, + (individuals ++ literals) map RSA.Named + ) + data.evaluateUpdate( + null, // the base IRI for the query (if null, a default is used) + RSA.Prefixes, + s""" + INSERT { + GRAPH <$canonNamedGraph> { ?X a rsa:Named } + } WHERE { + GRAPH <$canonNamedGraph> { ?X a owl:Thing } + } + """, + new java.util.HashMap[String, String] + ) - RDFoxUtil printStatisticsFor data + /* Add canonical model */ + Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}" + RDFoxUtil.addRules(data, this.canonicalModel.rules) - //{ - // import java.io.{PrintStream, FileOutputStream, File} - // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog")) - // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl")) - // RDFoxUtil.export(data, rules1, facts1) - // val rules2 = new PrintStream(new File("rules2-q34.dlog")) - // rules2.print(filter.rules.mkString("\n")) - //} + Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" + RDFoxUtil.addFacts(canonNamedGraph, data, this.canonicalModel.facts) - /* Add filtering program */ - Logger print s"Filtering program rules: ${filter.rules.length}" - RDFoxUtil.addRules(data, filter.rules) + queries map { query => + { + val filterNamedGraph = + s"http://cs.ox.ac.uk/isg/RSAComb#Filter${query.id}" + val filter = RSAOntology.filteringProgram(filterNamedGraph, query) + /* Add filtering program */ + Logger print s"Filtering program rules: ${filter.rules.length}" + RDFoxUtil.addRules(data, filter.rules) - RDFoxUtil printStatisticsFor data + // We remove the rules, should we drop the tuple table as well? + data.clearRulesAxiomsExplicateFacts() - /* Gather answers to the query */ - val answers = { - val ans = filter.answerQuery + /* Gather answers to the query */ RDFoxUtil - .submitQuery(data, ans, RSA.Prefixes) + .submitQuery(data, filter.answerQuery, RSA.Prefixes) .map(new ConjunctiveQueryAnswers(query, query.variables, _)) .get } + } + } - RDFoxUtil.closeConnection(server, data) - - answers - }, - "Answers computation", - Logger.DEBUG - ) + //def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( + // { + // val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) + // val canon = this.canonicalModel + // val filter = RSAOntology.filteringProgram(query) + + // /* Upload data from data file */ + // RDFoxUtil.addData(data, datafiles: _*) + + // RDFoxUtil printStatisticsFor data + + // /* Top / equality axiomatization */ + // RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) + + // /* Generate `named` predicates */ + // RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named) + // data.evaluateUpdate( + // null, // the base IRI for the query (if null, a default is used) + // RSA.Prefixes, + // "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }", + // new java.util.HashMap[String, String] + // ) + + // /* Add canonical model */ + // Logger print s"Canonical model rules: ${canon.rules.length}" + // RDFoxUtil.addRules(data, canon.rules) + + // Logger print s"Canonical model facts: ${canon.facts.length}" + // RDFoxUtil.addFacts(data, canon.facts) + + // RDFoxUtil printStatisticsFor data + + // //{ + // // import java.io.{PrintStream, FileOutputStream, File} + // // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog")) + // // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl")) + // // RDFoxUtil.export(data, rules1, facts1) + // // val rules2 = new PrintStream(new File("rules2-q34.dlog")) + // // rules2.print(filter.rules.mkString("\n")) + // //} + + // /* Add filtering program */ + // Logger print s"Filtering program rules: ${filter.rules.length}" + // RDFoxUtil.addRules(data, filter.rules) + + // RDFoxUtil printStatisticsFor data + + // /* Gather answers to the query */ + // val answers = { + // val ans = filter.answerQuery + // RDFoxUtil + // .submitQuery(data, ans, RSA.Prefixes) + // .map(new ConjunctiveQueryAnswers(query, query.variables, _)) + // .get + // } + + // RDFoxUtil.closeConnection(server, data) + + // answers + // }, + // "Answers computation", + // Logger.DEBUG + //) /** Query the RDFox data store used for query answering. * diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala index 2774cb1..d6ad8c5 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/FilteringProgram.scala @@ -46,6 +46,9 @@ object FilteringProgram extends Versioned[FilterType] { */ trait FilteringProgram { + /** Named graph used for filtering process */ + val graph: String + /** Query from which the filtering program is generated */ val query: ConjunctiveQuery diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala index 45dd867..3d9717c 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/NaiveFilteringProgram.scala @@ -36,8 +36,8 @@ object NaiveFilteringProgram { * * @param query CQ to be converted into logic rules. */ - def apply(query: ConjunctiveQuery): FilteringProgram = - new NaiveFilteringProgram(query) + def apply(graph: String, query: ConjunctiveQuery): FilteringProgram = + new NaiveFilteringProgram(graph, query) } /** Filtering Program generator @@ -47,7 +47,7 @@ object NaiveFilteringProgram { * * Instances can be created using the companion object. */ -class NaiveFilteringProgram(val query: ConjunctiveQuery) +class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) extends FilteringProgram { /** Extends capabilities of @@ -321,5 +321,6 @@ class NaiveFilteringProgram(val query: ConjunctiveQuery) r9 :: List()) map RDFoxUtil.reify } - val answerQuery = RDFoxUtil.buildDescriptionQuery("Ans", query.answer.size) + val answerQuery = + RDFoxUtil.buildDescriptionQuery(graph, "Ans", query.answer.size) } diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala index 4a4e65c..5d11369 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/filtering/RevisedFilteringProgram.scala @@ -422,12 +422,12 @@ class RevisedFilteringProgram(val query: ConjunctiveQuery) s""" SELECT $answer WHERE { - ?K a rsa:Ans . + GRAPH <$graph> { ?K a rsa:Ans } . TT { $answer $bounded ?K } . } """ } else { - "ASK { ?X a rsa:Ans }" + s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" } } diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala index 620d2dd..6f5ff31 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxUtil.scala @@ -124,13 +124,14 @@ object RDFoxUtil { def addRules(data: DataStoreConnection, rules: Seq[Rule]): Unit = Logger.timed( if (rules.length > 0) { - data.importData( - UpdateType.ADDITION, - RSA.Prefixes, - rules - .map(_.toString(Prefixes.s_emptyPrefixes)) - .mkString("\n") - ) + data addRules rules + // data.importData( + // UpdateType.ADDITION, + // RSA.Prefixes, + // rules + // .map(_.toString(Prefixes.s_emptyPrefixes)) + // .mkString("\n") + // ) }, s"Loading ${rules.length} rules", Logger.DEBUG @@ -141,10 +142,15 @@ object RDFoxUtil { * @param data datastore connection * @param facts collection of facts to be added to the data store */ - def addFacts(data: DataStoreConnection, facts: Seq[TupleTableAtom]): Unit = + def addFacts( + graph: String, + data: DataStoreConnection, + facts: Seq[TupleTableAtom] + ): Unit = Logger.timed( if (facts.length > 0) { data.importData( + graph, UpdateType.ADDITION, RSA.Prefixes, facts @@ -161,14 +167,10 @@ object RDFoxUtil { * @param data datastore connection. * @param files sequence of files to upload. */ - def addData(data: DataStoreConnection, files: File*): Unit = + def addData(graph: String, data: DataStoreConnection, files: File*): Unit = Logger.timed( files.foreach { - data.importData( - UpdateType.ADDITION, - RSA.Prefixes, - _ - ) + data.importData(graph, UpdateType.ADDITION, RSA.Prefixes, _) }, "Loading data files", Logger.DEBUG @@ -315,11 +317,13 @@ object RDFoxUtil { * compatible with RDFox engine. This helper allows to build a query * to gather all instances of an internal predicate * + * @param graph named graph to query for the provided predicate * @param pred name of the predicate to describe. * @param arity arity of the predicate. * @return a string containing a SPARQL query. */ def buildDescriptionQuery( + graph: String, pred: String, arity: Int ): String = { @@ -328,12 +332,12 @@ object RDFoxUtil { s""" SELECT $variables WHERE { - ?K a rsa:$pred. - TT { $variables ?K } . + GRAPH <$graph> { ?K a rsa:$pred }. + TT { $variables ?K } . } """ } else { - "ASK { ?X a rsa:Ans }" + s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" } } -- cgit v1.2.3