aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2021-01-30 10:46:23 +0000
committerFederico Igne <federico.igne@cs.ox.ac.uk>2021-01-30 10:48:29 +0000
commitd04e2839689c4291afb4beb9a1913bb38fac1cd1 (patch)
tree365e5ea2ef138e83ff46ecce72c716de6686e78e
parent87b180f1de0e1c30a4624e546825b77c2edf9bbe (diff)
downloadRSAComb-d04e2839689c4291afb4beb9a1913bb38fac1cd1.tar.gz
RSAComb-d04e2839689c4291afb4beb9a1913bb38fac1cd1.zip
Introduce a better system to handle command line input
-rwxr-xr-xrun_tests.bash20
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala200
2 files changed, 160 insertions, 60 deletions
diff --git a/run_tests.bash b/run_tests.bash
index 17cbf01..92e0223 100755
--- a/run_tests.bash
+++ b/run_tests.bash
@@ -32,6 +32,8 @@ print_help() {
32 echo " -q | --queries <path>:" 32 echo " -q | --queries <path>:"
33 echo " path to a folder containing SPARQL query files to be" 33 echo " path to a folder containing SPARQL query files to be"
34 echo " executed against the ontology and data." 34 echo " executed against the ontology and data."
35 echo " -j | --jar <path>:"
36 echo " path to the fat jar to be executed."
35 echo " -p | --prefix <path>:" 37 echo " -p | --prefix <path>:"
36 echo " provides a folder to prefix to the output files." 38 echo " provides a folder to prefix to the output files."
37 echo " Defaults to './results'." 39 echo " Defaults to './results'."
@@ -43,6 +45,7 @@ print_help() {
43ONTOLOGY="" 45ONTOLOGY=""
44DATA="" 46DATA=""
45QUERIES="" 47QUERIES=""
48JAR=""
46PREFIX="./results" 49PREFIX="./results"
47 50
48while [[ $# -gt 0 ]] 51while [[ $# -gt 0 ]]
@@ -72,6 +75,14 @@ do
72 print_help && \ 75 print_help && \
73 exit 2 76 exit 2
74 ;; 77 ;;
78 -j|--jar)
79 shift
80 JAR="$1"
81 [ ! -r "$JAR" ] && \
82 msg_error "Unable to read jar '$JAR'" && \
83 print_help && \
84 exit 2
85 ;;
75 -p|--prefix) 86 -p|--prefix)
76 shift 87 shift
77 PREFIX="$1" 88 PREFIX="$1"
@@ -104,12 +115,17 @@ done
104 print_help && \ 115 print_help && \
105 exit 3 116 exit 3
106 117
118[ -z "$JAR" ] && \
119 msg_error "Use -j | --jar to provide a jar file" && \
120 print_help && \
121 exit 3
107 122
108DATAS=`\ls $DATA/*` 123DATAS=`\ls $DATA/*`
109mkdir -p "$PREFIX" 124mkdir -p "$PREFIX"
110for QUERY in "$QUERIES"/*.sparql 125for QUERY in "$QUERIES"/query*.sparql
111do 126do
112 sbt "run $QUERY $ONTOLOGY $DATAS" 2>&1 | tee "$PREFIX/answers_$(basename $QUERY .sparql).txt" 127 #sbt "run $QUERY $ONTOLOGY $DATAS" 2>&1 | tee "$PREFIX/answers_$(basename $QUERY .sparql).txt"
128 java -cp ./lib/JRDFox.jar:"$JAR" uk.ac.ox.cs.rsacomb.RSAComb -q "$QUERY" "$ONTOLOGY" "$DATA"/* 2>&1 | tee "$PREFIX/answers_$(basename $QUERY .sparql).txt"
113done 129done
114 130
115OUTPUT="$PREFIX/results.csv" 131OUTPUT="$PREFIX/results.csv"
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 bf96a31..909cfdd 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
@@ -10,6 +10,106 @@ import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery
10import util.{Logger, RDFoxUtil, RSA} 10import util.{Logger, RDFoxUtil, RSA}
11import sparql.ConjunctiveQuery 11import sparql.ConjunctiveQuery
12 12
13case class RSAOption[+T](opt: T) {
14 def get[T]: T = opt.asInstanceOf[T]
15}
16
17object RSAConfig {
18 type Config = Map[Symbol, RSAOption[Any]]
19
20 private implicit def toRSAOption[T](opt: T) = RSAOption[T](opt)
21
22 /** Help message */
23 private val help: String = """
24 rsacomb - combined approach for CQ answering for RSA ontologies.
25
26 USAGE
27 rsacomb [OPTIONS] <ontology> [<data> ...]
28
29 -h | -? | --help
30 print this help message
31
32 --rsacheck-only
33 only perform the RSA check without performing any query answering.
34
35 -q <file> | --query <file>
36 path to a file containing a single SPARQL query
37
38 <ontology>
39 file containing the ontology
40
41 <data>
42 one or more data files
43
44 """
45
46 /** Default config values */
47 private val default = Map(
48 'rsacheckonly -> RSAOption[Boolean](false)
49 )
50
51 /** Utility to exit the program with a custom message on stderr.
52 *
53 * The program will exit with error code 1 after printing the help
54 * message.
55 *
56 * @param msg message printed to stderr.
57 */
58 private def exit(msg: String): Nothing = {
59 System.err.println(msg)
60 System.err.println()
61 System.err.println(help)
62 sys.exit(1)
63 }
64
65 /** Parse arguments with default options
66 *
67 * @param args arguments list
68 */
69 def parse(args: List[String]): Config = parse(args, default)
70
71 /** Parse arguments
72 *
73 * @param args arguments list
74 * @param config default configuration
75 */
76 def parse(args: List[String], config: Config): Config = {
77 args match {
78 case flag @ ("-h" | "-?" | "--help") :: _ => {
79 println(help)
80 sys.exit(0)
81 }
82 case "--rsacheck-only" :: tail =>
83 parse(tail, config ++ Map('rsacheckonly -> true))
84 case flag @ ("-q" | "--query") :: _query :: tail => {
85 val query = new File(_query)
86 if (!query.isFile)
87 exit(s"'$query' is not a valid filename.")
88 parse(tail, config ++ Map('query -> query))
89 }
90 case _ontology :: _data => {
91 val ontology = new File(_ontology)
92 val data = _data.map(new File(_))
93 (ontology :: data) foreach { (file) =>
94 if (!file.isFile)
95 exit(s"'$file' is not a valid filename.")
96 }
97 finalise(config ++ Map('ontology -> ontology, 'data -> data))
98 }
99 case a => exit(s"Invalid sequence of arguments '${a.mkString(" ")}'.")
100 }
101 }
102
103 /** Perform final checks on parsed options */
104 private def finalise(config: Config): Config = {
105 // Query file is mandatory unless only the RSA check is required.
106 if (!config('rsacheckonly).get[Boolean] && !config.contains('query))
107 exit(s"Query file was not provided.")
108
109 config
110 }
111}
112
13/** Entry point of the program. 113/** Entry point of the program.
14 * 114 *
15 * The executable expects a SPARQL query and a non-empty sequence of 115 * The executable expects a SPARQL query and a non-empty sequence of
@@ -24,72 +124,56 @@ import sparql.ConjunctiveQuery
24 */ 124 */
25object RSAComb extends App { 125object RSAComb extends App {
26 126
27 val help: String = """ 127 val config = RSAConfig.parse(args.toList)
28 rsacomb - combined approach for CQ answering for RSA ontologies.
29
30 USAGE
31 rsacomb <query> <ontology> [...]
32
33 where
34 - query: path to a file containing a single SPARQL query
35 - ontology: one or more ontology files
36
37 """
38
39 if (args.length < 2) {
40 println(help)
41 sys.exit;
42 }
43
44 val queryPath = new File(args(0))
45 val ontoPaths = args.drop(1).map(new File(_))
46
47 if (!queryPath.isFile || !ontoPaths.forall(_.isFile)) {
48 println("The provided arguments are not regular files.\n\n")
49 println(help)
50 sys.exit;
51 }
52 128
53 val ontology = RSAOntology(ontoPaths: _*) 129 val ontology =
130 RSAOntology(config('ontology).get[File], config('data).get[List[File]]: _*)
54 if (ontology.isRSA) { 131 if (ontology.isRSA) {
55 132
56 Logger print "Ontology is RSA!" 133 Logger print "Ontology is RSA!"
57 134
58 val query = RDFoxUtil.loadQueryFromFile(queryPath.getAbsoluteFile) 135 if (!config('rsacheckonly).get[Boolean]) {
59 136 val query =
60 ConjunctiveQuery.parse(query) match { 137 RDFoxUtil.loadQueryFromFile(config('query).get[File].getAbsoluteFile)
61 case Some(query) => { 138
62 val answers = ontology ask query 139 ConjunctiveQuery.parse(query) match {
63 Logger.print(s"$answers", Logger.QUIET) 140 case Some(query) => {
64 Logger print s"Number of answers: ${answers.length} (${answers.lengthWithMultiplicity})" 141 val answers = ontology ask query
65 142 Logger.print(s"$answers", Logger.QUIET)
66 /* Additional DEBUG information */ 143 Logger print s"Number of answers: ${answers.length} (${answers.lengthWithMultiplicity})"
67 if (Logger.level >= Logger.DEBUG) { 144
68 /* Unfiltered rules */ 145 // /* Additional DEBUG information */
69 val unfiltered = ontology askUnfiltered query 146 // if (Logger.level >= Logger.DEBUG) {
70 unfiltered map { u => 147 // /* Unfiltered rules */
71 Logger print s"Number of unfiltered answers: ${u.length} (${u.map(_._1).sum})." 148 // val unfiltered = ontology askUnfiltered query
72 149 // unfiltered map { u =>
73 /* Spurious answers */ 150 // Logger print s"Number of unfiltered answers: ${u.length} (${u.map(_._1).sum})."
74 val spurious = { 151
75 val variables = query.variables.length 152 // /* Spurious answers */
76 val sp = RDFoxUtil.buildDescriptionQuery("SP", variables) 153 // val spurious = {
77 ontology.queryDataStore(query, sp, RSA.Prefixes) 154 // val variables = query.variables.length
78 } 155 // val sp = RDFoxUtil.buildDescriptionQuery("SP", variables)
79 spurious map { s => 156 // ontology.queryDataStore(query, sp, RSA.Prefixes)
80 Logger print s"Number of spurious answers: ${s.length} (${s.map(_._1).sum})" 157 // }
81 158 // spurious map { s =>
82 /* Spurious/unfiltered percentage */ 159 // Logger print s"Number of spurious answers: ${s.length} (${s.map(_._1).sum})"
83 val perc = 160
84 if (u.length > 0) (s.length / u.length.toFloat) * 100 else 0 161 // /* Spurious/unfiltered percentage */
85 Logger print s"Percentage of spurious answers: $perc%" 162 // val perc =
86 } 163 // if (u.length > 0) (s.length / u.length.toFloat) * 100 else 0
87 } 164 // Logger print s"Percentage of spurious answers: $perc%"
165 // }
166 // }
167 // }
88 } 168 }
169 case None =>
170 throw new RuntimeException("Submitted query is not conjunctive")
89 } 171 }
90 case None =>
91 throw new RuntimeException("Submitted query is not conjunctive")
92 } 172 }
93 173
174 } else {
175
176 Logger print "Ontology is not RSA!"
177
94 } 178 }
95} 179}