diff options
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala | 186 | ||||
| -rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 55 | ||||
| -rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala | 98 |
3 files changed, 121 insertions, 218 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala index db52793..678a5fa 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala | |||
| @@ -46,9 +46,7 @@ object RSAComb extends App { | |||
| 46 | sys.exit; | 46 | sys.exit; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | /* Create RSA object from generic OWLOntology | 49 | /* TODO: It might be required to check if the ontology in input is |
| 50 | * | ||
| 51 | * TODO: It might be required to check if the ontology in input is | ||
| 52 | * Horn-ALCHOIQ. At the moment we are assuming this is always the | 50 | * Horn-ALCHOIQ. At the moment we are assuming this is always the |
| 53 | * case. | 51 | * case. |
| 54 | */ | 52 | */ |
| @@ -56,183 +54,13 @@ object RSAComb extends App { | |||
| 56 | val ontology = RSAOntology(ontoPath) | 54 | val ontology = RSAOntology(ontoPath) |
| 57 | if (ontology.isRSA) { | 55 | if (ontology.isRSA) { |
| 58 | 56 | ||
| 59 | /* Load query */ | 57 | /** Read SPARQL query from file */ |
| 60 | val query = """ | 58 | val source = io.Source.fromFile(queryPath.getAbsoluteFile) |
| 61 | PREFIX : <http://example.com/rsa_example.owl#> | 59 | val query = source.getLines mkString "\n" |
| 62 | 60 | source.close() | |
| 63 | SELECT ?X | ||
| 64 | WHERE { | ||
| 65 | ?X a :D ; | ||
| 66 | :R ?Y . | ||
| 67 | ?Y :S ?Z . | ||
| 68 | ?Z a :D . | ||
| 69 | } | ||
| 70 | """ | ||
| 71 | 61 | ||
| 72 | /* Compute answers to query */ | 62 | /* Compute answers to query */ |
| 73 | ConjunctiveQuery(query) match { | 63 | val answers = ConjunctiveQuery(query).map(ontology ask _) |
| 74 | case Some(query) => { | 64 | answers map (_.toString) foreach println |
| 75 | |||
| 76 | import implicits.JavaCollections._ | ||
| 77 | |||
| 78 | // Open connection to RDFox | ||
| 79 | val (server, data) = RDFoxHelpers.openConnection("AnswerComputation") | ||
| 80 | |||
| 81 | { | ||
| 82 | println("\nQuery") | ||
| 83 | println(query) | ||
| 84 | } | ||
| 85 | |||
| 86 | val canon = ontology.canonicalModel | ||
| 87 | data.addRules(canon.rules) | ||
| 88 | val filter = ontology.filteringProgram(query) | ||
| 89 | data.addRules(filter.rules) | ||
| 90 | |||
| 91 | { | ||
| 92 | println("\nCanonical Model rules:") | ||
| 93 | canon.rules.foreach(println) | ||
| 94 | println("\nFiltering rules") | ||
| 95 | filter.rules.foreach(println) | ||
| 96 | } | ||
| 97 | |||
| 98 | // Retrieve answers | ||
| 99 | println("\nAnswers:") | ||
| 100 | val ans = | ||
| 101 | RDFoxHelpers.queryInternalPredicate(data, "Ans", filter.answer.length) | ||
| 102 | println(ans) | ||
| 103 | |||
| 104 | /* DEBUG: adding additional checks | ||
| 105 | */ | ||
| 106 | { | ||
| 107 | import suffix.{Forward, Backward} | ||
| 108 | |||
| 109 | val arity = filter.answer.length + filter.bounded.length | ||
| 110 | |||
| 111 | println("\nIndividuals:") | ||
| 112 | ontology.individuals.foreach(println) | ||
| 113 | |||
| 114 | println("\nThings:") | ||
| 115 | val things = RDFoxHelpers.submitQuery( | ||
| 116 | data, | ||
| 117 | """ | ||
| 118 | PREFIX owl: <http://www.w3.org/2002/07/owl#> | ||
| 119 | |||
| 120 | SELECT ?X { | ||
| 121 | ?X a owl:Thing | ||
| 122 | } | ||
| 123 | """ | ||
| 124 | ) | ||
| 125 | println(things) | ||
| 126 | |||
| 127 | println("\nNAMEDs:") | ||
| 128 | val named = RDFoxHelpers.submitQuery( | ||
| 129 | data, | ||
| 130 | """ | ||
| 131 | SELECT ?X { | ||
| 132 | ?X a rsa:Named | ||
| 133 | } | ||
| 134 | """, | ||
| 135 | RSA.Prefixes | ||
| 136 | ) | ||
| 137 | println(named) | ||
| 138 | |||
| 139 | println("\nNIs:") | ||
| 140 | val nis = RDFoxHelpers.submitQuery( | ||
| 141 | data, | ||
| 142 | """ | ||
| 143 | SELECT ?X { | ||
| 144 | ?X a rsa:NI | ||
| 145 | } | ||
| 146 | """, | ||
| 147 | RSA.Prefixes | ||
| 148 | ) | ||
| 149 | println(nis) | ||
| 150 | |||
| 151 | // ID instances | ||
| 152 | println("\nIDs:") | ||
| 153 | val ids = RDFoxHelpers.queryInternalPredicate( | ||
| 154 | data, | ||
| 155 | "ID", | ||
| 156 | arity + 2 | ||
| 157 | ) | ||
| 158 | println(ids) | ||
| 159 | |||
| 160 | println("\nCongruent:") | ||
| 161 | val equivs = RDFoxHelpers.submitQuery( | ||
| 162 | data, | ||
| 163 | """ | ||
| 164 | SELECT ?X ?Y { | ||
| 165 | ?X rsa:congruent ?Y | ||
| 166 | } | ||
| 167 | """, | ||
| 168 | RSA.Prefixes | ||
| 169 | ) | ||
| 170 | println(equivs) | ||
| 171 | |||
| 172 | // Unfiltered answers | ||
| 173 | println("\nPossible answers:") | ||
| 174 | val qms = RDFoxHelpers.queryInternalPredicate( | ||
| 175 | data, | ||
| 176 | "QM", | ||
| 177 | arity | ||
| 178 | ) | ||
| 179 | println(qms) | ||
| 180 | |||
| 181 | // Cycle detected | ||
| 182 | println("\nCycle detection:") | ||
| 183 | val aqf = RDFoxHelpers.queryInternalPredicate( | ||
| 184 | data, | ||
| 185 | "AQ" :: Forward, | ||
| 186 | arity + 2 | ||
| 187 | ) | ||
| 188 | val aqb = RDFoxHelpers.queryInternalPredicate( | ||
| 189 | data, | ||
| 190 | "AQ" :: Backward, | ||
| 191 | arity + 2 | ||
| 192 | ) | ||
| 193 | println(aqf) | ||
| 194 | println(aqb) | ||
| 195 | |||
| 196 | // Forks detected | ||
| 197 | println("\nForks:") | ||
| 198 | val fk = RDFoxHelpers.queryInternalPredicate( | ||
| 199 | data, | ||
| 200 | "FK", | ||
| 201 | arity | ||
| 202 | ) | ||
| 203 | println(fk) | ||
| 204 | |||
| 205 | // Spurious answers | ||
| 206 | println("\nSpurious answers") | ||
| 207 | val sp = RDFoxHelpers.queryInternalPredicate( | ||
| 208 | data, | ||
| 209 | "SP", | ||
| 210 | arity | ||
| 211 | ) | ||
| 212 | println(sp) | ||
| 213 | } | ||
| 214 | |||
| 215 | // Close connection to RDFox | ||
| 216 | RDFoxHelpers.closeConnection(server, data) | ||
| 217 | } | ||
| 218 | case None => {} | ||
| 219 | } | ||
| 220 | } | 65 | } |
| 221 | } | 66 | } |
| 222 | |||
| 223 | /* Notes: | ||
| 224 | * | ||
| 225 | * To establish a connection with a local RDFox instance, do the | ||
| 226 | * following: | ||
| 227 | * | ||
| 228 | * ``` | ||
| 229 | * val serverConnection : ServerConnection = ConnectionFactory.newServerConnection("rdfox:local", "", "") | ||
| 230 | * serverConnection.createDataStore("test","seq",new HashMap()) | ||
| 231 | * val dataStoreConnection : DataStoreConnection = serverConnection.newDataStoreConnection("test") | ||
| 232 | * dataStoreConnection.importData( | ||
| 233 | * UpdateType.ADDITION, | ||
| 234 | * Prefixes.s_emptyPrefixes, | ||
| 235 | * new File("./path/to/file") | ||
| 236 | * ) | ||
| 237 | * ``` | ||
| 238 | */ | ||
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 9640ccc..56fbac3 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | package uk.ac.ox.cs.rsacomb | 1 | package uk.ac.ox.cs.rsacomb |
| 2 | 2 | ||
| 3 | /* Java imports */ | 3 | /* Java imports */ |
| 4 | import java.{util => ju} | ||
| 4 | import java.util.HashMap | 5 | import java.util.HashMap |
| 5 | import java.util.stream.{Collectors, Stream} | 6 | import java.util.stream.{Collectors, Stream} |
| 6 | import java.io.File | 7 | import java.io.File |
| @@ -48,8 +49,8 @@ import org.semanticweb.owlapi.model.OWLObjectInverseOf | |||
| 48 | 49 | ||
| 49 | import uk.ac.ox.cs.rsacomb.converter.{RDFoxAxiomConverter, SkolemStrategy} | 50 | import uk.ac.ox.cs.rsacomb.converter.{RDFoxAxiomConverter, SkolemStrategy} |
| 50 | import uk.ac.ox.cs.rsacomb.implicits.RSAAxiom | 51 | import uk.ac.ox.cs.rsacomb.implicits.RSAAxiom |
| 51 | import uk.ac.ox.cs.rsacomb.suffix.{Empty, Forward, Backward, Inverse} | 52 | import uk.ac.ox.cs.rsacomb.suffix._ |
| 52 | import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery | 53 | import uk.ac.ox.cs.rsacomb.sparql._ |
| 53 | import uk.ac.ox.cs.rsacomb.util.{RDFoxHelpers, RSA} | 54 | import uk.ac.ox.cs.rsacomb.util.{RDFoxHelpers, RSA} |
| 54 | 55 | ||
| 55 | object RSAOntology { | 56 | object RSAOntology { |
| @@ -256,8 +257,8 @@ class RSAOntology(val ontology: OWLOntology) extends RSAAxiom { | |||
| 256 | ): Graph[Resource, UnDiEdge] = { | 257 | ): Graph[Resource, UnDiEdge] = { |
| 257 | val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }" | 258 | val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }" |
| 258 | val answers = RDFoxHelpers.submitQuery(data, query, RSA.Prefixes).get | 259 | val answers = RDFoxHelpers.submitQuery(data, query, RSA.Prefixes).get |
| 259 | var edges: List[UnDiEdge[Resource]] = answers.map { | 260 | var edges: Seq[UnDiEdge[Resource]] = answers.map { |
| 260 | case n1 :: n2 :: _ => UnDiEdge(n1, n2) | 261 | case Seq(n1, n2) => UnDiEdge(n1, n2) |
| 261 | } | 262 | } |
| 262 | Graph(edges: _*) | 263 | Graph(edges: _*) |
| 263 | } | 264 | } |
| @@ -291,6 +292,52 @@ class RSAOntology(val ontology: OWLOntology) extends RSAAxiom { | |||
| 291 | .filterNot(_.getInverseProperty.isOWLTopObjectProperty()) | 292 | .filterNot(_.getInverseProperty.isOWLTopObjectProperty()) |
| 292 | } | 293 | } |
| 293 | 294 | ||
| 295 | /** Returns the answers to a query | ||
| 296 | * | ||
| 297 | * @param query query to execute | ||
| 298 | * @return a collection of answers | ||
| 299 | */ | ||
| 300 | def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = { | ||
| 301 | import implicits.JavaCollections._ | ||
| 302 | val (server, data) = RDFoxHelpers.openConnection("AnswerComputation") | ||
| 303 | data.addRules(this.canonicalModel.rules) | ||
| 304 | data.addRules(this.filteringProgram(query).rules) | ||
| 305 | new ConjunctiveQueryAnswers( | ||
| 306 | query.boolean, | ||
| 307 | queryInternalPredicate(data, "Ans", query.answer.size) | ||
| 308 | ) | ||
| 309 | } | ||
| 310 | |||
| 311 | /** Returns instances of a reified predicate | ||
| 312 | * | ||
| 313 | * Predicated with arity higher than 2 are internally reified to be | ||
| 314 | * compatible with RDFox engine. This helper queries for predicate | ||
| 315 | * instances and returns a set of un-reified answers. | ||
| 316 | * | ||
| 317 | * @param data open datastore connection to RDFox | ||
| 318 | * @param pred name of the predicate | ||
| 319 | * @param arity arity of the predicate | ||
| 320 | * @param opts additional options to RDFox | ||
| 321 | * @return a collection of instances of the given predicate | ||
| 322 | */ | ||
| 323 | private def queryInternalPredicate( | ||
| 324 | data: DataStoreConnection, | ||
| 325 | pred: String, | ||
| 326 | arity: Int, | ||
| 327 | opts: ju.Map[String, String] = new ju.HashMap[String, String]() | ||
| 328 | ): Seq[Seq[Resource]] = { | ||
| 329 | val query = | ||
| 330 | if (arity > 0) { | ||
| 331 | (0 until arity).mkString("SELECT ?X", " ?X", "\n") + | ||
| 332 | (0 until arity) | ||
| 333 | .map(i => s"?S rsa:${pred :: Nth(i)} ?X$i .") | ||
| 334 | .mkString("WHERE {\n", "\n", "\n}") | ||
| 335 | } else { | ||
| 336 | s"ASK { ?X a rsa:$pred }" | ||
| 337 | } | ||
| 338 | RDFoxHelpers.submitQuery(data, query, RSA.Prefixes).get | ||
| 339 | } | ||
| 340 | |||
| 294 | def self(axiom: OWLSubClassOfAxiom): Set[Term] = { | 341 | def self(axiom: OWLSubClassOfAxiom): Set[Term] = { |
| 295 | // Assuming just one role in the signature of a T5 axiom | 342 | // Assuming just one role in the signature of a T5 axiom |
| 296 | val role = axiom.objectPropertyExpressionsInSignature(0) | 343 | val role = axiom.objectPropertyExpressionsInSignature(0) |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala index 5b85436..43e5d28 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | package uk.ac.ox.cs.rsacomb.util | 1 | package uk.ac.ox.cs.rsacomb.util |
| 2 | 2 | ||
| 3 | import java.util.{Map => JMap, HashMap => JHashMap} | ||
| 4 | import java.io.StringReader | 3 | import java.io.StringReader |
| 5 | import tech.oxfordsemantic.jrdfox.Prefixes | 4 | import tech.oxfordsemantic.jrdfox.Prefixes |
| 6 | import tech.oxfordsemantic.jrdfox.client.{ | 5 | import tech.oxfordsemantic.jrdfox.client.{ |
| @@ -12,32 +11,52 @@ import tech.oxfordsemantic.jrdfox.formats.SPARQLParser | |||
| 12 | import tech.oxfordsemantic.jrdfox.logic.expression.Resource | 11 | import tech.oxfordsemantic.jrdfox.logic.expression.Resource |
| 13 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery | 12 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery |
| 14 | 13 | ||
| 15 | import uk.ac.ox.cs.rsacomb.suffix.Nth | 14 | /** A collection of helper methods for RDFox */ |
| 16 | |||
| 17 | object RDFoxHelpers { | 15 | object RDFoxHelpers { |
| 18 | 16 | ||
| 17 | /** Type alias for a collection of answers to a | ||
| 18 | * [[tech.oxfordsemantic.jrdfox.logic.sparql.statement.Query]]. | ||
| 19 | */ | ||
| 20 | private type QueryAnswers = Seq[Seq[Resource]] | ||
| 21 | private def QueryAnswers() = List.empty[Seq[Resource]] | ||
| 22 | |||
| 23 | /** Type alias for <option => value> RDFox options. */ | ||
| 24 | private type RDFoxOpts = java.util.Map[String, String] | ||
| 25 | private def RDFoxOpts() = new java.util.HashMap[String, String]() | ||
| 26 | |||
| 27 | /** Setup a new local connection with RDFox. | ||
| 28 | * | ||
| 29 | * @param dataStore data store identifier | ||
| 30 | * @param opts additional options to RDFox | ||
| 31 | * @return a tuple with the newly opened server and data store | ||
| 32 | * connections. | ||
| 33 | * | ||
| 34 | * @see [[uk.ac.ox.cs.rsacomb.util.RDFoxHelpers.closeConnection | ||
| 35 | * RDFoxHelpers.closeConnection]] for | ||
| 36 | * details on how to close an open connection. | ||
| 37 | */ | ||
| 19 | def openConnection( | 38 | def openConnection( |
| 20 | dataStore: String, | 39 | dataStore: String, |
| 21 | opts: JMap[String, String] = new JHashMap[String, String]() | 40 | opts: RDFoxOpts = RDFoxOpts() |
| 22 | ): (ServerConnection, DataStoreConnection) = { | 41 | ): (ServerConnection, DataStoreConnection) = { |
| 23 | /* Create local server connection | ||
| 24 | */ | ||
| 25 | val serverUrl = "rdfox:local" | 42 | val serverUrl = "rdfox:local" |
| 26 | val role = "" | 43 | val role = "" |
| 27 | val password = "" | 44 | val password = "" |
| 28 | val server = | 45 | val server = |
| 29 | ConnectionFactory.newServerConnection(serverUrl, role, password) | 46 | ConnectionFactory.newServerConnection(serverUrl, role, password) |
| 30 | |||
| 31 | /* Create datastore connection | ||
| 32 | */ | ||
| 33 | // parameters.put("owl-in-rdf-support", "relaxed") | ||
| 34 | // parameters.put("equality", "noUNA") | ||
| 35 | server.createDataStore(dataStore, "par-complex-nn", opts) | 47 | server.createDataStore(dataStore, "par-complex-nn", opts) |
| 36 | val data = server.newDataStoreConnection(dataStore) | 48 | val data = server.newDataStoreConnection(dataStore) |
| 37 | |||
| 38 | (server, data) | 49 | (server, data) |
| 39 | } | 50 | } |
| 40 | 51 | ||
| 52 | /** Parse a SELECT query from a string in SPARQL format. | ||
| 53 | * | ||
| 54 | * @param query the string containing the SPARQL query | ||
| 55 | * @param prefixes additional prefixes for the query. It defaults to | ||
| 56 | * an empty set. | ||
| 57 | * @return a [[tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery SelectQuery]] | ||
| 58 | * if the input string is a SELECT query, none otherwise. | ||
| 59 | */ | ||
| 41 | def parseSelectQuery( | 60 | def parseSelectQuery( |
| 42 | query: String, | 61 | query: String, |
| 43 | prefixes: Prefixes = new Prefixes() | 62 | prefixes: Prefixes = new Prefixes() |
| @@ -52,13 +71,22 @@ object RDFoxHelpers { | |||
| 52 | } | 71 | } |
| 53 | } | 72 | } |
| 54 | 73 | ||
| 74 | /** Execute a query over a given datastore connection. | ||
| 75 | * | ||
| 76 | * @param data RDFox datastore connection. | ||
| 77 | * @param query a | ||
| 78 | * [[tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery SelectQuery]] | ||
| 79 | * to be executed. | ||
| 80 | * @param opts additional options to RDFox. | ||
| 81 | * @returns a collection of answers to the query. | ||
| 82 | */ | ||
| 55 | def submitSelectQuery( | 83 | def submitSelectQuery( |
| 56 | data: DataStoreConnection, | 84 | data: DataStoreConnection, |
| 57 | query: SelectQuery, | 85 | query: SelectQuery, |
| 58 | opts: JMap[String, String] = new JHashMap[String, String]() | 86 | opts: RDFoxOpts = RDFoxOpts() |
| 59 | ): List[List[Resource]] = { | 87 | ): QueryAnswers = { |
| 60 | val cursor = data.createCursor(query, opts) | 88 | val cursor = data.createCursor(query, opts) |
| 61 | var answers: List[List[Resource]] = List() | 89 | var answers = QueryAnswers() |
| 62 | var mul = cursor.open() | 90 | var mul = cursor.open() |
| 63 | while (mul > 0) { | 91 | while (mul > 0) { |
| 64 | val answer = | 92 | val answer = |
| @@ -70,32 +98,32 @@ object RDFoxHelpers { | |||
| 70 | answers | 98 | answers |
| 71 | } | 99 | } |
| 72 | 100 | ||
| 101 | /** Execute a query over a given datastore connection. | ||
| 102 | * | ||
| 103 | * @param data RDFox datastore connection. | ||
| 104 | * @param query a string representing a SPARQL query. | ||
| 105 | * @param prefixes additional prefixes for the query. It defaults to | ||
| 106 | * an empty set. | ||
| 107 | * @param opts additional options to RDFox. | ||
| 108 | * @returns a collection of answers to the query if the input query | ||
| 109 | * is a SELECT query, none otherwise. | ||
| 110 | */ | ||
| 73 | def submitQuery( | 111 | def submitQuery( |
| 74 | data: DataStoreConnection, | 112 | data: DataStoreConnection, |
| 75 | query: String, | 113 | query: String, |
| 76 | prefixes: Prefixes = new Prefixes(), | 114 | prefixes: Prefixes = new Prefixes(), |
| 77 | opts: JMap[String, String] = new JHashMap[String, String]() | 115 | opts: RDFoxOpts = RDFoxOpts() |
| 78 | ): Option[List[List[Resource]]] = | 116 | ): Option[QueryAnswers] = |
| 79 | parseSelectQuery(query, prefixes).map(submitSelectQuery(data, _, opts)) | 117 | parseSelectQuery(query, prefixes).map(submitSelectQuery(data, _, opts)) |
| 80 | 118 | ||
| 81 | def queryInternalPredicate( | 119 | /** Close an open connection to RDFox. |
| 82 | data: DataStoreConnection, | 120 | * |
| 83 | pred: String, | 121 | * @param server server connection |
| 84 | arity: Int, | 122 | * @param data data store connections |
| 85 | opts: JMap[String, String] = new JHashMap[String, String]() | 123 | * |
| 86 | ): List[List[Resource]] = { | 124 | * @see [[uk.ac.ox.cs.rsacomb.util.RDFoxHelpers.openConnection RDFoxHelpers.openConnection]] |
| 87 | var query = "SELECT" | 125 | * for details on how to create a new connection with RDFox. |
| 88 | for (i <- 0 until arity) { | 126 | */ |
| 89 | query ++= s" ?X$i" | ||
| 90 | } | ||
| 91 | query ++= " WHERE {" | ||
| 92 | for (i <- 0 until arity) { | ||
| 93 | query ++= s" ?S rsa:${pred :: Nth(i)} ?X$i ." | ||
| 94 | } | ||
| 95 | query ++= " }" | ||
| 96 | submitQuery(data, query, RSA.Prefixes, opts).get | ||
| 97 | } | ||
| 98 | |||
| 99 | def closeConnection( | 127 | def closeConnection( |
| 100 | server: ServerConnection, | 128 | server: ServerConnection, |
| 101 | data: DataStoreConnection | 129 | data: DataStoreConnection |
