diff options
Diffstat (limited to 'src/uk/ac/ox/cs/pagoda/query')
| -rw-r--r-- | src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java | 30 | ||||
| -rw-r--r-- | src/uk/ac/ox/cs/pagoda/query/QueryRecord.java | 141 |
2 files changed, 92 insertions, 79 deletions
diff --git a/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java b/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java index 78aced1..9a9d0de 100644 --- a/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java +++ b/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java | |||
| @@ -16,14 +16,10 @@ import java.lang.reflect.Type; | |||
| 16 | import java.util.HashMap; | 16 | import java.util.HashMap; |
| 17 | import java.util.Map; | 17 | import java.util.Map; |
| 18 | import java.util.StringTokenizer; | 18 | import java.util.StringTokenizer; |
| 19 | import java.util.regex.Matcher; | ||
| 20 | import java.util.regex.Pattern; | ||
| 21 | 19 | ||
| 22 | public class AnswerTuple { | 20 | public class AnswerTuple { |
| 23 | 21 | ||
| 24 | public static final String SEPARATOR = "\t"; | 22 | public static final String SEPARATOR = "\t"; |
| 25 | static final Pattern owlLiteralRegex = | ||
| 26 | Pattern.compile("^\"(?<lexicalForm>[^@]+(@(?<langTag>.+))?)\"(^^<(?<dataType>.+)>)?$"); | ||
| 27 | String m_str = null; | 23 | String m_str = null; |
| 28 | GroundTerm[] m_tuple; | 24 | GroundTerm[] m_tuple; |
| 29 | 25 | ||
| @@ -158,32 +154,36 @@ public class AnswerTuple { | |||
| 158 | String tuplesString = json.getAsJsonPrimitive().getAsString(); | 154 | String tuplesString = json.getAsJsonPrimitive().getAsString(); |
| 159 | // StringTokenizer tokenizer = new StringTokenizer(tuplesString, SEPARATOR); | 155 | // StringTokenizer tokenizer = new StringTokenizer(tuplesString, SEPARATOR); |
| 160 | StringTokenizer tokenizer = new StringTokenizer(tuplesString); | 156 | StringTokenizer tokenizer = new StringTokenizer(tuplesString); |
| 161 | GroundTerm[] terms = new GroundTerm[tokenizer.countTokens()]; | 157 | int tokensCount = tokenizer.countTokens(); |
| 158 | GroundTerm[] terms = new GroundTerm[tokensCount]; | ||
| 162 | 159 | ||
| 163 | // TODO test parsing | 160 | // TODO test parsing |
| 164 | for (int i = 0; i < tokenizer.countTokens(); i++) { | 161 | for(int i = 0; i < tokensCount; i++) { |
| 165 | String token = tokenizer.nextToken(); | 162 | String token = tokenizer.nextToken(); |
| 166 | if (token.charAt(0) == '<') { | 163 | if (token.charAt(0) == '<') { |
| 167 | terms[i] = uk.ac.ox.cs.JRDFox.model.Individual.create(token.substring(1,token.length()-1)); | 164 | terms[i] = uk.ac.ox.cs.JRDFox.model.Individual.create(token.substring(1,token.length()-1)); |
| 168 | } | 165 | } |
| 169 | else if (token.charAt(0) == '"') { | 166 | else if (token.charAt(0) == '"') { |
| 170 | Matcher matcher = owlLiteralRegex.matcher(token); | 167 | Datatype datatype; |
| 171 | if(matcher.matches()) { | 168 | String lexicalForm; |
| 172 | String lexicalForm = matcher.group("lexicalForm"); | 169 | if(token.contains("^^")) { |
| 173 | String dataTypeIRI = matcher.group("dataType"); | 170 | String[] lexicalFormAndType = token.split("^^"); |
| 174 | Datatype dataType; | 171 | lexicalForm = lexicalFormAndType[0]; |
| 175 | if(dataTypeIRI == null || dataTypeIRI.isEmpty()) dataType = Datatype.RDF_PLAIN_LITERAL; | 172 | datatype = Datatype.value(lexicalFormAndType[1]); |
| 176 | else dataType = uk.ac.ox.cs.JRDFox.model.Datatype.value(dataTypeIRI); | ||
| 177 | terms[i] = uk.ac.ox.cs.JRDFox.model.Literal.create(lexicalForm, dataType); | ||
| 178 | } | 173 | } |
| 179 | else { | 174 | else { |
| 180 | throw new IllegalArgumentException("The given json does not represent a valid AnswerTuple"); | 175 | lexicalForm = token.substring(1, token.length() - 1); |
| 176 | // TODO check | ||
| 177 | // datatype = token.contains("@") ? Datatype.RDF_PLAIN_LITERAL : Datatype.XSD_STRING; | ||
| 178 | datatype = Datatype.XSD_STRING; | ||
| 181 | } | 179 | } |
| 180 | terms[i] = uk.ac.ox.cs.JRDFox.model.Literal.create(lexicalForm, datatype); | ||
| 182 | } | 181 | } |
| 183 | else { | 182 | else { |
| 184 | terms[i] = uk.ac.ox.cs.JRDFox.model.BlankNode.create(token); | 183 | terms[i] = uk.ac.ox.cs.JRDFox.model.BlankNode.create(token); |
| 185 | } | 184 | } |
| 186 | } | 185 | } |
| 186 | |||
| 187 | return new AnswerTuple(terms); | 187 | return new AnswerTuple(terms); |
| 188 | } | 188 | } |
| 189 | } | 189 | } |
diff --git a/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java b/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java index 742b7da..516a461 100644 --- a/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java +++ b/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java | |||
| @@ -135,74 +135,16 @@ public class QueryRecord extends Disposable { | |||
| 135 | return updateUpperBoundAnswers(answerTuples, false); | 135 | return updateUpperBoundAnswers(answerTuples, false); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | public boolean updateUpperBoundAnswers(AnswerTuples answerTuples, boolean toCheckAux) { | 138 | public boolean checkUpperBoundAnswers(AnswerTuples answerTuples) { |
| 139 | if(isDisposed()) throw new DisposedException(); | 139 | if(isDisposed()) throw new DisposedException(); |
| 140 | 140 | ||
| 141 | if(!(answerTuples instanceof RDFoxAnswerTuples)) { | 141 | return updateUpperBoundAnswers(answerTuples, true, false); |
| 142 | String msg = "The upper bound must be computed by RDFox!"; | 142 | } |
| 143 | Utility.logError(msg); | ||
| 144 | throw new IllegalArgumentException(msg); | ||
| 145 | } | ||
| 146 | |||
| 147 | RDFoxAnswerTuples rdfoxAnswerTuples = (RDFoxAnswerTuples) answerTuples; | ||
| 148 | |||
| 149 | Set<AnswerTuple> candidateGapAnswerTuples = new HashSet<AnswerTuple>(); | ||
| 150 | AnswerTuple tuple; | ||
| 151 | for(; rdfoxAnswerTuples.isValid(); rdfoxAnswerTuples.moveNext()) { | ||
| 152 | tuple = rdfoxAnswerTuples.getTuple(); | ||
| 153 | if(isBottom() || !tuple.hasAnonymousIndividual()) | ||
| 154 | if((!toCheckAux || !tuple.hasAuxPredicate()) && !soundAnswerTuples.contains(tuple)) | ||
| 155 | candidateGapAnswerTuples.add(tuple); | ||
| 156 | } | ||
| 157 | |||
| 158 | /*** START: debugging ***/ | ||
| 159 | if(PagodaProperties.isDebuggingMode()) { | ||
| 160 | if(rdfoxAnswerTuples.getArity() != getAnswerVariables().length) | ||
| 161 | throw new IllegalArgumentException( | ||
| 162 | "The arity of answers (" + rdfoxAnswerTuples.getArity() + ") " + | ||
| 163 | "is different from the number of answer variables (" + | ||
| 164 | getAnswerVariables().length + ")"); | ||
| 165 | |||
| 166 | Set<AnswerTuple> namedAnswerTuples = new HashSet<>(); | ||
| 167 | rdfoxAnswerTuples.reset(); | ||
| 168 | for(; rdfoxAnswerTuples.isValid(); rdfoxAnswerTuples.moveNext()) { | ||
| 169 | tuple = rdfoxAnswerTuples.getTuple(); | ||
| 170 | // if(isBottom() || !tuple.hasAnonymousIndividual()) { | ||
| 171 | namedAnswerTuples.add(tuple); | ||
| 172 | // } | ||
| 173 | } | ||
| 174 | HashSet<AnswerTuple> difference = new HashSet<>(soundAnswerTuples); | ||
| 175 | difference.removeAll(namedAnswerTuples); | ||
| 176 | if(!difference.isEmpty()) | ||
| 177 | throw new IllegalArgumentException("The upper bound does not contain the lower bound! Missing answers: " + difference | ||
| 178 | .size()); | ||
| 179 | } | ||
| 180 | /*** END: debugging ***/ | ||
| 181 | |||
| 182 | boolean update; | ||
| 183 | if(gapAnswerTuples == null) { | ||
| 184 | gapAnswerTuples = candidateGapAnswerTuples; | ||
| 185 | update = true; | ||
| 186 | } | ||
| 187 | else { | ||
| 188 | update = gapAnswerTuples.retainAll(candidateGapAnswerTuples); | ||
| 189 | } | ||
| 190 | |||
| 191 | if(update) | ||
| 192 | Utility.logInfo("Upper bound answers updated: " + getNumberOfAnswers()); | ||
| 193 | else | ||
| 194 | Utility.logInfo("Upper bound answers unchanged"); | ||
| 195 | 143 | ||
| 196 | return update; | 144 | public boolean updateUpperBoundAnswers(AnswerTuples answerTuples, boolean toCheckAux) { |
| 145 | if(isDisposed()) throw new DisposedException(); | ||
| 197 | 146 | ||
| 198 | // boolean update = false; | 147 | return updateUpperBoundAnswers(answerTuples, toCheckAux, true); |
| 199 | // for(Iterator<AnswerTuple> iter = gapAnswerTuples.iterator(); iter.hasNext(); ) { | ||
| 200 | // tuple = iter.next(); | ||
| 201 | // if(!candidateGapAnswerTuples.contains(tuple)) { | ||
| 202 | // iter.remove(); | ||
| 203 | // update = true; | ||
| 204 | // } | ||
| 205 | // } | ||
| 206 | } | 148 | } |
| 207 | 149 | ||
| 208 | public int getNumberOfAnswers() { | 150 | public int getNumberOfAnswers() { |
| @@ -713,6 +655,77 @@ public class QueryRecord extends Disposable { | |||
| 713 | return Objects.hash(queryText, soundAnswerTuples); | 655 | return Objects.hash(queryText, soundAnswerTuples); |
| 714 | } | 656 | } |
| 715 | 657 | ||
| 658 | private boolean updateUpperBoundAnswers(AnswerTuples answerTuples, boolean toCheckAux, boolean _check_containment) { | ||
| 659 | if(!(answerTuples instanceof RDFoxAnswerTuples)) { | ||
| 660 | String msg = "The upper bound must be computed by RDFox!"; | ||
| 661 | Utility.logError(msg); | ||
| 662 | throw new IllegalArgumentException(msg); | ||
| 663 | } | ||
| 664 | |||
| 665 | RDFoxAnswerTuples rdfoxAnswerTuples = (RDFoxAnswerTuples) answerTuples; | ||
| 666 | |||
| 667 | Set<AnswerTuple> candidateGapAnswerTuples = new HashSet<AnswerTuple>(); | ||
| 668 | AnswerTuple tuple; | ||
| 669 | for(; rdfoxAnswerTuples.isValid(); rdfoxAnswerTuples.moveNext()) { | ||
| 670 | tuple = rdfoxAnswerTuples.getTuple(); | ||
| 671 | if(isBottom() || !tuple.hasAnonymousIndividual()) | ||
| 672 | if((!toCheckAux || !tuple.hasAuxPredicate()) && !soundAnswerTuples.contains(tuple)) | ||
| 673 | candidateGapAnswerTuples.add(tuple); | ||
| 674 | } | ||
| 675 | |||
| 676 | /*** START: debugging ***/ | ||
| 677 | if(PagodaProperties.isDebuggingMode() && _check_containment) { | ||
| 678 | if(rdfoxAnswerTuples.getArity() != getAnswerVariables().length) | ||
| 679 | throw new IllegalArgumentException( | ||
| 680 | "The arity of answers (" + rdfoxAnswerTuples.getArity() + ") " + | ||
| 681 | "is different from the number of answer variables (" + | ||
| 682 | getAnswerVariables().length + ")"); | ||
| 683 | |||
| 684 | Set<AnswerTuple> namedAnswerTuples = new HashSet<>(); | ||
| 685 | rdfoxAnswerTuples.reset(); | ||
| 686 | int numberOfAnswers = 0; | ||
| 687 | for(; rdfoxAnswerTuples.isValid(); rdfoxAnswerTuples.moveNext()) { | ||
| 688 | tuple = rdfoxAnswerTuples.getTuple(); | ||
| 689 | // if(isBottom() || !tuple.hasAnonymousIndividual()) { | ||
| 690 | namedAnswerTuples.add(tuple); | ||
| 691 | // } | ||
| 692 | numberOfAnswers++; | ||
| 693 | } | ||
| 694 | Utility.logDebug("The number of answers returned by an upper bound: " + numberOfAnswers); | ||
| 695 | HashSet<AnswerTuple> difference = new HashSet<>(soundAnswerTuples); | ||
| 696 | difference.removeAll(namedAnswerTuples); | ||
| 697 | if(!difference.isEmpty()) | ||
| 698 | throw new IllegalArgumentException("The upper bound does not contain the lower bound! Missing answers: " + difference | ||
| 699 | .size()); | ||
| 700 | } | ||
| 701 | /*** END: debugging ***/ | ||
| 702 | |||
| 703 | boolean update; | ||
| 704 | if(gapAnswerTuples == null) { | ||
| 705 | gapAnswerTuples = candidateGapAnswerTuples; | ||
| 706 | update = true; | ||
| 707 | } | ||
| 708 | else { | ||
| 709 | update = gapAnswerTuples.retainAll(candidateGapAnswerTuples); | ||
| 710 | } | ||
| 711 | |||
| 712 | if(update) | ||
| 713 | Utility.logInfo("Upper bound answers updated: " + getNumberOfAnswers()); | ||
| 714 | else | ||
| 715 | Utility.logInfo("Upper bound answers unchanged"); | ||
| 716 | |||
| 717 | return update; | ||
| 718 | |||
| 719 | // boolean update = false; | ||
| 720 | // for(Iterator<AnswerTuple> iter = gapAnswerTuples.iterator(); iter.hasNext(); ) { | ||
| 721 | // tuple = iter.next(); | ||
| 722 | // if(!candidateGapAnswerTuples.contains(tuple)) { | ||
| 723 | // iter.remove(); | ||
| 724 | // update = true; | ||
| 725 | // } | ||
| 726 | // } | ||
| 727 | } | ||
| 728 | |||
| 716 | public enum Step { | 729 | public enum Step { |
| 717 | LOWER_BOUND, | 730 | LOWER_BOUND, |
| 718 | UPPER_BOUND, | 731 | UPPER_BOUND, |
