diff options
| author | Federico Igne <git@federicoigne.com> | 2021-09-30 12:32:25 +0100 |
|---|---|---|
| committer | Federico Igne <git@federicoigne.com> | 2021-09-30 12:32:25 +0100 |
| commit | 1ef8a2502532dd1736c1e3d6a1ff78ed6b8b643c (patch) | |
| tree | eb3471b39e10f667650dbb415eb5d366465fa0c8 /src/main/scala | |
| parent | 95a2e9e85e1783e1bf2b50ae37bd9eab003a6ca8 (diff) | |
| download | RSAComb-1ef8a2502532dd1736c1e3d6a1ff78ed6b8b643c.tar.gz RSAComb-1ef8a2502532dd1736c1e3d6a1ff78ed6b8b643c.zip | |
Refactor query answering to use named graphs
Diffstat (limited to 'src/main/scala')
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 { | |||
| 96 | * @param query the query to derive the filtering program | 96 | * @param query the query to derive the filtering program |
| 97 | * @return the filtering program for the given query | 97 | * @return the filtering program for the given query |
| 98 | */ | 98 | */ |
| 99 | def filteringProgram(query: ConjunctiveQuery): FilteringProgram = | 99 | def filteringProgram( |
| 100 | graph: String, | ||
| 101 | query: ConjunctiveQuery | ||
| 102 | ): FilteringProgram = | ||
| 100 | Logger.timed( | 103 | Logger.timed( |
| 101 | FilteringProgram(FilterType.REVISED)(query), | 104 | FilteringProgram(FilterType.REVISED)(query), |
| 102 | "Generating filtering program", | 105 | "Generating filtering program", |
| @@ -496,76 +499,131 @@ class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) | |||
| 496 | def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = | 499 | def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = |
| 497 | this.self(axiom) | this.cycle(axiom) | 500 | this.self(axiom) | this.cycle(axiom) |
| 498 | 501 | ||
| 499 | def ask(queries: Seq[ConjunctiveQuery]): Seq[ConjunctiveQueryAnswers] = ??? | 502 | /** Returns the answers to a collection of queries |
| 500 | |||
| 501 | /** Returns the answers to a query | ||
| 502 | * | 503 | * |
| 503 | * @param query query to execute | 504 | * @param queries a sequence of conjunctive queries to answer. |
| 504 | * @return a collection of answers | 505 | * @return a collection of answers for each query. |
| 505 | */ | 506 | */ |
| 506 | def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( | 507 | def ask(queries: Seq[ConjunctiveQuery]): Seq[ConjunctiveQueryAnswers] = { |
| 507 | { | 508 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) |
| 508 | val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) | 509 | val canonNamedGraph = "http://cs.ox.ac.uk/isg/RSAComb#CanonicalModel" |
| 509 | val canon = this.canonicalModel | 510 | // Create a new NamedGraph for the canonical model |
| 510 | val filter = RSAOntology.filteringProgram(query) | 511 | data.createTupleTable(canonNamedGraph, Map("type" -> "named-graph").asJava) |
| 511 | 512 | ||
| 512 | /* Upload data from data file */ | 513 | /* Upload data from data file */ |
| 513 | RDFoxUtil.addData(data, datafiles: _*) | 514 | RDFoxUtil.addData(canonNamedGraph, data, datafiles: _*) |
| 514 | 515 | /* Top / equality axiomatization */ | |
| 515 | RDFoxUtil printStatisticsFor data | 516 | RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) |
| 516 | 517 | /* Generate `named` predicates */ | |
| 517 | /* Top / equality axiomatization */ | 518 | RDFoxUtil.addFacts( |
| 518 | RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) | 519 | canonNamedGraph, |
| 519 | 520 | data, | |
| 520 | /* Generate `named` predicates */ | 521 | (individuals ++ literals) map RSA.Named |
| 521 | RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named) | 522 | ) |
| 522 | data.evaluateUpdate( | 523 | data.evaluateUpdate( |
| 523 | null, // the base IRI for the query (if null, a default is used) | 524 | null, // the base IRI for the query (if null, a default is used) |
| 524 | RSA.Prefixes, | 525 | RSA.Prefixes, |
| 525 | "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }", | 526 | s""" |
| 526 | new java.util.HashMap[String, String] | 527 | INSERT { |
| 527 | ) | 528 | GRAPH <$canonNamedGraph> { ?X a rsa:Named } |
| 528 | 529 | } WHERE { | |
| 529 | /* Add canonical model */ | 530 | GRAPH <$canonNamedGraph> { ?X a owl:Thing } |
| 530 | Logger print s"Canonical model rules: ${canon.rules.length}" | 531 | } |
| 531 | RDFoxUtil.addRules(data, canon.rules) | 532 | """, |
| 532 | 533 | new java.util.HashMap[String, String] | |
| 533 | Logger print s"Canonical model facts: ${canon.facts.length}" | 534 | ) |
| 534 | RDFoxUtil.addFacts(data, canon.facts) | ||
| 535 | 535 | ||
| 536 | RDFoxUtil printStatisticsFor data | 536 | /* Add canonical model */ |
| 537 | Logger print s"Canonical model rules: ${this.canonicalModel.rules.length}" | ||
| 538 | RDFoxUtil.addRules(data, this.canonicalModel.rules) | ||
| 537 | 539 | ||
| 538 | //{ | 540 | Logger print s"Canonical model facts: ${this.canonicalModel.facts.length}" |
| 539 | // import java.io.{PrintStream, FileOutputStream, File} | 541 | RDFoxUtil.addFacts(canonNamedGraph, data, this.canonicalModel.facts) |
| 540 | // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog")) | ||
| 541 | // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl")) | ||
| 542 | // RDFoxUtil.export(data, rules1, facts1) | ||
| 543 | // val rules2 = new PrintStream(new File("rules2-q34.dlog")) | ||
| 544 | // rules2.print(filter.rules.mkString("\n")) | ||
| 545 | //} | ||
| 546 | 542 | ||
| 547 | /* Add filtering program */ | 543 | queries map { query => |
| 548 | Logger print s"Filtering program rules: ${filter.rules.length}" | 544 | { |
| 549 | RDFoxUtil.addRules(data, filter.rules) | 545 | val filterNamedGraph = |
| 546 | s"http://cs.ox.ac.uk/isg/RSAComb#Filter${query.id}" | ||
| 547 | val filter = RSAOntology.filteringProgram(filterNamedGraph, query) | ||
| 548 | /* Add filtering program */ | ||
| 549 | Logger print s"Filtering program rules: ${filter.rules.length}" | ||
| 550 | RDFoxUtil.addRules(data, filter.rules) | ||
| 550 | 551 | ||
| 551 | RDFoxUtil printStatisticsFor data | 552 | // We remove the rules, should we drop the tuple table as well? |
| 553 | data.clearRulesAxiomsExplicateFacts() | ||
| 552 | 554 | ||
| 553 | /* Gather answers to the query */ | 555 | /* Gather answers to the query */ |
| 554 | val answers = { | ||
| 555 | val ans = filter.answerQuery | ||
| 556 | RDFoxUtil | 556 | RDFoxUtil |
| 557 | .submitQuery(data, ans, RSA.Prefixes) | 557 | .submitQuery(data, filter.answerQuery, RSA.Prefixes) |
| 558 | .map(new ConjunctiveQueryAnswers(query, query.variables, _)) | 558 | .map(new ConjunctiveQueryAnswers(query, query.variables, _)) |
| 559 | .get | 559 | .get |
| 560 | } | 560 | } |
| 561 | } | ||
| 562 | } | ||
| 561 | 563 | ||
| 562 | RDFoxUtil.closeConnection(server, data) | 564 | //def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( |
| 563 | 565 | // { | |
| 564 | answers | 566 | // val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) |
| 565 | }, | 567 | // val canon = this.canonicalModel |
| 566 | "Answers computation", | 568 | // val filter = RSAOntology.filteringProgram(query) |
| 567 | Logger.DEBUG | 569 | |
| 568 | ) | 570 | // /* Upload data from data file */ |
| 571 | // RDFoxUtil.addData(data, datafiles: _*) | ||
| 572 | |||
| 573 | // RDFoxUtil printStatisticsFor data | ||
| 574 | |||
| 575 | // /* Top / equality axiomatization */ | ||
| 576 | // RDFoxUtil.addRules(data, topAxioms ++ equalityAxioms) | ||
| 577 | |||
| 578 | // /* Generate `named` predicates */ | ||
| 579 | // RDFoxUtil.addFacts(data, (individuals ++ literals) map RSA.Named) | ||
| 580 | // data.evaluateUpdate( | ||
| 581 | // null, // the base IRI for the query (if null, a default is used) | ||
| 582 | // RSA.Prefixes, | ||
| 583 | // "INSERT { ?X a rsa:Named } WHERE { ?X a owl:Thing }", | ||
| 584 | // new java.util.HashMap[String, String] | ||
| 585 | // ) | ||
| 586 | |||
| 587 | // /* Add canonical model */ | ||
| 588 | // Logger print s"Canonical model rules: ${canon.rules.length}" | ||
| 589 | // RDFoxUtil.addRules(data, canon.rules) | ||
| 590 | |||
| 591 | // Logger print s"Canonical model facts: ${canon.facts.length}" | ||
| 592 | // RDFoxUtil.addFacts(data, canon.facts) | ||
| 593 | |||
| 594 | // RDFoxUtil printStatisticsFor data | ||
| 595 | |||
| 596 | // //{ | ||
| 597 | // // import java.io.{PrintStream, FileOutputStream, File} | ||
| 598 | // // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog")) | ||
| 599 | // // val facts1 = new FileOutputStream(new File("facts1-lubm200.ttl")) | ||
| 600 | // // RDFoxUtil.export(data, rules1, facts1) | ||
| 601 | // // val rules2 = new PrintStream(new File("rules2-q34.dlog")) | ||
| 602 | // // rules2.print(filter.rules.mkString("\n")) | ||
| 603 | // //} | ||
| 604 | |||
| 605 | // /* Add filtering program */ | ||
| 606 | // Logger print s"Filtering program rules: ${filter.rules.length}" | ||
| 607 | // RDFoxUtil.addRules(data, filter.rules) | ||
| 608 | |||
| 609 | // RDFoxUtil printStatisticsFor data | ||
| 610 | |||
| 611 | // /* Gather answers to the query */ | ||
| 612 | // val answers = { | ||
| 613 | // val ans = filter.answerQuery | ||
| 614 | // RDFoxUtil | ||
| 615 | // .submitQuery(data, ans, RSA.Prefixes) | ||
| 616 | // .map(new ConjunctiveQueryAnswers(query, query.variables, _)) | ||
| 617 | // .get | ||
| 618 | // } | ||
| 619 | |||
| 620 | // RDFoxUtil.closeConnection(server, data) | ||
| 621 | |||
| 622 | // answers | ||
| 623 | // }, | ||
| 624 | // "Answers computation", | ||
| 625 | // Logger.DEBUG | ||
| 626 | //) | ||
| 569 | 627 | ||
| 570 | /** Query the RDFox data store used for query answering. | 628 | /** Query the RDFox data store used for query answering. |
| 571 | * | 629 | * |
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] { | |||
| 46 | */ | 46 | */ |
| 47 | trait FilteringProgram { | 47 | trait FilteringProgram { |
| 48 | 48 | ||
| 49 | /** Named graph used for filtering process */ | ||
| 50 | val graph: String | ||
| 51 | |||
| 49 | /** Query from which the filtering program is generated */ | 52 | /** Query from which the filtering program is generated */ |
| 50 | val query: ConjunctiveQuery | 53 | val query: ConjunctiveQuery |
| 51 | 54 | ||
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 { | |||
| 36 | * | 36 | * |
| 37 | * @param query CQ to be converted into logic rules. | 37 | * @param query CQ to be converted into logic rules. |
| 38 | */ | 38 | */ |
| 39 | def apply(query: ConjunctiveQuery): FilteringProgram = | 39 | def apply(graph: String, query: ConjunctiveQuery): FilteringProgram = |
| 40 | new NaiveFilteringProgram(query) | 40 | new NaiveFilteringProgram(graph, query) |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | /** Filtering Program generator | 43 | /** Filtering Program generator |
| @@ -47,7 +47,7 @@ object NaiveFilteringProgram { | |||
| 47 | * | 47 | * |
| 48 | * Instances can be created using the companion object. | 48 | * Instances can be created using the companion object. |
| 49 | */ | 49 | */ |
| 50 | class NaiveFilteringProgram(val query: ConjunctiveQuery) | 50 | class NaiveFilteringProgram(val graph: String, val query: ConjunctiveQuery) |
| 51 | extends FilteringProgram { | 51 | extends FilteringProgram { |
| 52 | 52 | ||
| 53 | /** Extends capabilities of | 53 | /** Extends capabilities of |
| @@ -321,5 +321,6 @@ class NaiveFilteringProgram(val query: ConjunctiveQuery) | |||
| 321 | r9 :: List()) map RDFoxUtil.reify | 321 | r9 :: List()) map RDFoxUtil.reify |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | val answerQuery = RDFoxUtil.buildDescriptionQuery("Ans", query.answer.size) | 324 | val answerQuery = |
| 325 | RDFoxUtil.buildDescriptionQuery(graph, "Ans", query.answer.size) | ||
| 325 | } | 326 | } |
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) | |||
| 422 | s""" | 422 | s""" |
| 423 | SELECT $answer | 423 | SELECT $answer |
| 424 | WHERE { | 424 | WHERE { |
| 425 | ?K a rsa:Ans . | 425 | GRAPH <$graph> { ?K a rsa:Ans } . |
| 426 | TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $answer $bounded ?K } . | 426 | TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $answer $bounded ?K } . |
| 427 | } | 427 | } |
| 428 | """ | 428 | """ |
| 429 | } else { | 429 | } else { |
| 430 | "ASK { ?X a rsa:Ans }" | 430 | s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" |
| 431 | } | 431 | } |
| 432 | } | 432 | } |
| 433 | 433 | ||
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 { | |||
| 124 | def addRules(data: DataStoreConnection, rules: Seq[Rule]): Unit = | 124 | def addRules(data: DataStoreConnection, rules: Seq[Rule]): Unit = |
| 125 | Logger.timed( | 125 | Logger.timed( |
| 126 | if (rules.length > 0) { | 126 | if (rules.length > 0) { |
| 127 | data.importData( | 127 | data addRules rules |
| 128 | UpdateType.ADDITION, | 128 | // data.importData( |
| 129 | RSA.Prefixes, | 129 | // UpdateType.ADDITION, |
| 130 | rules | 130 | // RSA.Prefixes, |
| 131 | .map(_.toString(Prefixes.s_emptyPrefixes)) | 131 | // rules |
| 132 | .mkString("\n") | 132 | // .map(_.toString(Prefixes.s_emptyPrefixes)) |
| 133 | ) | 133 | // .mkString("\n") |
| 134 | // ) | ||
| 134 | }, | 135 | }, |
| 135 | s"Loading ${rules.length} rules", | 136 | s"Loading ${rules.length} rules", |
| 136 | Logger.DEBUG | 137 | Logger.DEBUG |
| @@ -141,10 +142,15 @@ object RDFoxUtil { | |||
| 141 | * @param data datastore connection | 142 | * @param data datastore connection |
| 142 | * @param facts collection of facts to be added to the data store | 143 | * @param facts collection of facts to be added to the data store |
| 143 | */ | 144 | */ |
| 144 | def addFacts(data: DataStoreConnection, facts: Seq[TupleTableAtom]): Unit = | 145 | def addFacts( |
| 146 | graph: String, | ||
| 147 | data: DataStoreConnection, | ||
| 148 | facts: Seq[TupleTableAtom] | ||
| 149 | ): Unit = | ||
| 145 | Logger.timed( | 150 | Logger.timed( |
| 146 | if (facts.length > 0) { | 151 | if (facts.length > 0) { |
| 147 | data.importData( | 152 | data.importData( |
| 153 | graph, | ||
| 148 | UpdateType.ADDITION, | 154 | UpdateType.ADDITION, |
| 149 | RSA.Prefixes, | 155 | RSA.Prefixes, |
| 150 | facts | 156 | facts |
| @@ -161,14 +167,10 @@ object RDFoxUtil { | |||
| 161 | * @param data datastore connection. | 167 | * @param data datastore connection. |
| 162 | * @param files sequence of files to upload. | 168 | * @param files sequence of files to upload. |
| 163 | */ | 169 | */ |
| 164 | def addData(data: DataStoreConnection, files: File*): Unit = | 170 | def addData(graph: String, data: DataStoreConnection, files: File*): Unit = |
| 165 | Logger.timed( | 171 | Logger.timed( |
| 166 | files.foreach { | 172 | files.foreach { |
| 167 | data.importData( | 173 | data.importData(graph, UpdateType.ADDITION, RSA.Prefixes, _) |
| 168 | UpdateType.ADDITION, | ||
| 169 | RSA.Prefixes, | ||
| 170 | _ | ||
| 171 | ) | ||
| 172 | }, | 174 | }, |
| 173 | "Loading data files", | 175 | "Loading data files", |
| 174 | Logger.DEBUG | 176 | Logger.DEBUG |
| @@ -315,11 +317,13 @@ object RDFoxUtil { | |||
| 315 | * compatible with RDFox engine. This helper allows to build a query | 317 | * compatible with RDFox engine. This helper allows to build a query |
| 316 | * to gather all instances of an internal predicate | 318 | * to gather all instances of an internal predicate |
| 317 | * | 319 | * |
| 320 | * @param graph named graph to query for the provided predicate | ||
| 318 | * @param pred name of the predicate to describe. | 321 | * @param pred name of the predicate to describe. |
| 319 | * @param arity arity of the predicate. | 322 | * @param arity arity of the predicate. |
| 320 | * @return a string containing a SPARQL query. | 323 | * @return a string containing a SPARQL query. |
| 321 | */ | 324 | */ |
| 322 | def buildDescriptionQuery( | 325 | def buildDescriptionQuery( |
| 326 | graph: String, | ||
| 323 | pred: String, | 327 | pred: String, |
| 324 | arity: Int | 328 | arity: Int |
| 325 | ): String = { | 329 | ): String = { |
| @@ -328,12 +332,12 @@ object RDFoxUtil { | |||
| 328 | s""" | 332 | s""" |
| 329 | SELECT $variables | 333 | SELECT $variables |
| 330 | WHERE { | 334 | WHERE { |
| 331 | ?K a rsa:$pred. | 335 | GRAPH <$graph> { ?K a rsa:$pred }. |
| 332 | TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $variables ?K } . | 336 | TT <http://oxfordsemantic.tech/RDFox#SKOLEM> { $variables ?K } . |
| 333 | } | 337 | } |
| 334 | """ | 338 | """ |
| 335 | } else { | 339 | } else { |
| 336 | "ASK { ?X a rsa:Ans }" | 340 | s"ASK { GRAPH <$graph> { ?X a rsa:Ans } }" |
| 337 | } | 341 | } |
| 338 | } | 342 | } |
| 339 | 343 | ||
