Added optionality for quantified queries
diff --git a/CHANGES b/CHANGES
index 8e14cd9..0bc6f4c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+0.31.8 2014-07-23
+ - [feature] Added optionality to querys for quantifiers (diewald)
+
0.31.7 2014-07-18
- [feature] Added warnings to responses (diewald)
diff --git a/pom.xml b/pom.xml
index cc4ae02..45aa13f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
-->
<groupId>KorAP-modules</groupId>
<artifactId>KorAP-lucene-index</artifactId>
- <version>0.31.7</version>
+ <version>0.31.8</version>
<packaging>jar</packaging>
<name>KorAP-lucene-index</name>
diff --git a/src/main/java/de/ids_mannheim/korap/KorapFilter.java b/src/main/java/de/ids_mannheim/korap/KorapFilter.java
index c4541d6..d97dd6e 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapFilter.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapFilter.java
@@ -38,6 +38,41 @@
pubDate
pubPlace
+Query: (corpusID=BRZ13 | corpusID=WPD) & textClass=wissenschaft
+
+{
+ "@type": "korap:filter",
+ "filter": {
+ "@type": "korap:docGroup",
+ "relation": "relation:and",
+ "operands": [
+ {
+ "@type": "korap:docGroup",
+ "relation": "relation:or",
+ "operands": [
+ {
+ "@type": "korap:doc",
+ "key": "corpusID",
+ "value": "BRZ13",
+ "match": "match:eq"
+ },
+ {
+ "@type": "korap:doc",
+ "key": "corpusID",
+ "value": "WPD",
+ "match": "match:eq"
+ }
+ ]
+ },
+ {
+ "@type": "korap:doc",
+ "key": "textClass",
+ "value": "wissenschaft",
+ "match": "match:eq"
+ }
+ ]
+ }
+}
*/
public class KorapFilter {
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index d05d4d2..e258f57 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -24,6 +24,13 @@
negation terms (and negation subqueries), like
[base=Der]([base=alte]|[base=junge])[base=Mann & p!=ADJA]![base=war | base=lag]
Search for all documents containing "s:Der" and ("s:alte" or "s:junge") and "s:Mann"
+
+ TODO: korap:reference doesn't work as expected:
+ - Check with
+ - focus(2:{1:[orth=der]{3:{2:[orth=Baum]}}})
+ - focus(3:startswith(<s>,{3:[tt/p=ART]{1:{2:[tt/p=ADJA]{3,4}}[tt/p=NN]}}))
+ - focus(3:endswith(<s>,{3:[tt/p=ART]{1:{2:[tt/p=ADJA]{3,4}}[tt/p=NN]}}))
+
*/
/**
@@ -279,8 +286,10 @@
throw new QueryException("The maximum repetition value has to " +
"be greater or equal to the minimum repetition value");
- if (min == 0)
- throw new QueryException("Minimum value of zero is not supported yet");
+ if (min == 0) {
+ throw new QueryException(
+ "Zero minimum of repetition is not supported yet");
+ };
return new SpanRepetitionQueryWrapper(
this.fromJSON(operands.get(0)), min, max
@@ -320,13 +329,13 @@
case "korap:token":
if (!json.has("wrap"))
- throw new QueryException("Tokens need a wrap attribute");
+ throw new QueryException("Empty Tokens are not supported yet");
return this._segFromJSON(json.get("wrap"));
case "korap:span":
if (!json.has("key"))
- throw new QueryException("A span need at least a key definition");
+ throw new QueryException("A span needs at least a key definition");
return this._termFromJSON(json);
};
@@ -722,5 +731,4 @@
// split
-
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index f1b637f..f0a1012 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -65,7 +65,7 @@
};
if (this.request.has("warning"))
- this.warning = this.request.get("warning").asText();
+ this.addWarning(this.request.get("warning").asText());
// "meta" virtual collections
if (this.request.has("collections"))
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
index fd7c65d..5d5c4dc 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanAlterQueryWrapper.java
@@ -17,12 +17,19 @@
private SpanQuery query;
private List<SpanQuery> alternatives;
private boolean isNull = true;
+ private boolean isOptional = false;
public SpanAlterQueryWrapper (String field) {
this.field = field;
this.alternatives = new ArrayList<>();
};
+ public SpanAlterQueryWrapper (String field, SpanQuery query) {
+ this.field = field;
+ this.alternatives = new ArrayList<>();
+ this.alternatives.add(query);
+ };
+
public SpanAlterQueryWrapper (String field, String ... terms) {
this.field = field;
this.alternatives = new ArrayList<>();
@@ -33,7 +40,11 @@
};
public SpanAlterQueryWrapper or (String term) {
- this.alternatives.add(new SpanTermQuery(new Term(this.field, term)));
+ return this.or(new SpanTermQuery(new Term(this.field, term)));
+ };
+
+ public SpanAlterQueryWrapper or (SpanQuery query) {
+ this.alternatives.add(query);
this.isNull = false;
return this;
};
@@ -41,6 +52,12 @@
public SpanAlterQueryWrapper or (SpanQueryWrapperInterface term) {
if (term.isNull())
return this;
+
+ // If one operand is optional, the whole group can be optional
+ // a | b* | c
+ if (term.isOptional())
+ this.isOptional = true;
+
this.alternatives.add( term.toQuery() );
this.isNull = false;
return this;
@@ -75,7 +92,7 @@
};
public boolean isOptional () {
- return false;
+ return this.isOptional;
};
public boolean isNull () {
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
index 5a6c1a4..50671f6 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanClassQueryWrapper.java
@@ -43,7 +43,7 @@
};
public boolean isOptional () {
- return false;
+ return this.subquery.isOptional();
};
public boolean isNull () {
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
index 85926e2..4476f76 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanMatchModifyQueryWrapper.java
@@ -39,7 +39,7 @@
};
public boolean isOptional () {
- return false;
+ return this.subquery.isOptional();
};
public boolean isNull () {
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
index 68ffb5b..d4b8c54 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanRepetitionQueryWrapper.java
@@ -10,7 +10,7 @@
private SpanQueryWrapperInterface subquery;
private int min = 1;
private int max = 1;
- private boolean optional = false;
+ private boolean isOptional = false;
private boolean isNull = false;
public SpanRepetitionQueryWrapper (SpanQueryWrapperInterface subquery, int exact) {
@@ -18,6 +18,7 @@
if (exact < 1 || this.subquery.isNull()) {
this.isNull = true;
+ this.isOptional = true;
return;
};
@@ -34,7 +35,8 @@
};
if (min == 0) {
- this.optional = true;
+ this.isOptional = true;
+ min = 1;
if (max == 0)
this.isNull = true;
};
@@ -45,11 +47,13 @@
public SpanQuery toQuery () {
if (this.isNull)
return (SpanQuery) null;
+ if (this.min == 1 && this.max == 1)
+ return this.subquery.toQuery();
return new SpanRepetitionQuery(this.subquery.toQuery(), this.min, this.max, true);
};
public boolean isOptional () {
- return this.optional;
+ return this.isOptional;
};
public boolean isNull () {
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
index e3b755d..f758a8b 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanSequenceQueryWrapper.java
@@ -8,6 +8,7 @@
import de.ids_mannheim.korap.query.SpanMultipleDistanceQuery;
import de.ids_mannheim.korap.query.wrap.SpanSegmentQueryWrapper;
+import de.ids_mannheim.korap.query.wrap.SpanAlterQueryWrapper;
import de.ids_mannheim.korap.query.wrap.SpanRegexQueryWrapper;
import de.ids_mannheim.korap.query.wrap.SpanWildcardQueryWrapper;
@@ -23,8 +24,12 @@
private String field;
private ArrayList<SpanQuery> segments;
private ArrayList<DistanceConstraint> constraints;
- private boolean isInOrder = true;
- private boolean isNull = true;
+ private boolean
+ isInOrder = true,
+ isNull = true,
+ isOptional = true,
+ lastIsOptional = false,
+ firstIsOptional = false;
public SpanSequenceQueryWrapper (String field) {
this.field = field;
@@ -35,6 +40,7 @@
this(field);
for (int i = 0; i < terms.length; i++) {
this.segments.add((SpanQuery) new SpanTermQuery(new Term(field, terms[i])));
+ this.isOptional = false;
};
this.isNull = false;
};
@@ -42,6 +48,7 @@
public SpanSequenceQueryWrapper (String field, SpanQuery sq) {
this(field);
this.segments.add((SpanQuery) sq);
+ this.isOptional = false;
this.isNull = false;
};
@@ -50,6 +57,14 @@
if (!sswq.isNull()) {
this.segments.add((SpanQuery) sswq.toQuery());
this.isNull = false;
+ if (sswq.isOptional()) {
+ this.isOptional = true;
+ this.lastIsOptional = true;
+ this.firstIsOptional = true;
+ }
+ else {
+ this.isOptional = false;
+ };
};
};
@@ -58,6 +73,7 @@
if (!re.isNull()) {
this.segments.add((SpanQuery) re.toQuery());
this.isNull = false;
+ this.isOptional = false;
};
};
@@ -65,6 +81,7 @@
this(field);
if (!wc.isNull()) {
this.segments.add((SpanQuery) wc.toQuery());
+ this.isOptional = false;
this.isNull = false;
};
};
@@ -78,14 +95,74 @@
};
public SpanSequenceQueryWrapper append (String term) {
- this.segments.add((SpanQuery) new SpanTermQuery(new Term(field, term)));
+ return this.append((SpanQuery) new SpanTermQuery(new Term(field, term)));
+ };
+
+ public SpanSequenceQueryWrapper append (SpanQuery query) {
this.isNull = false;
+ this.isOptional = false;
+
+ // Check if there has to be alternation magic in action
+ if (this.lastIsOptional) {
+ SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, query);
+ SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, query);
+ // Remove last element of the list and prepend it
+ ssqw.prepend(this.segments.remove(this.segments.size() - 1));
+ saqw.or(ssqw);
+
+ // Update boundary optionality
+ if (this.firstIsOptional && this.segments.size() == 0)
+ this.firstIsOptional = false;
+ this.lastIsOptional = false;
+
+ this.segments.add((SpanQuery) saqw.toQuery());
+ }
+ else {
+ this.segments.add(query);
+ };
+
return this;
};
public SpanSequenceQueryWrapper append (SpanQueryWrapperInterface ssq) {
if (!ssq.isNull()) {
- this.segments.add((SpanQuery) ssq.toQuery());
+ SpanQuery appendQuery = ssq.toQuery();
+ if (!ssq.isOptional()) {
+ return this.append((SpanQuery) ssq.toQuery());
+ };
+
+ // Situation is a?b?
+ if (this.lastIsOptional) {
+ // Remove last element of the list and prepend it
+ SpanQuery lastQuery = this.segments.remove(this.segments.size() - 1);
+ SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, lastQuery);
+ SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, appendQuery);
+ ssqw.prepend(lastQuery);
+ saqw.or(appendQuery);
+ saqw.or(ssqw);
+ this.segments.add((SpanQuery) saqw.toQuery());
+ }
+
+ // Situation is ab?
+ else if (this.segments.size() != 0) {
+ // Remove last element of the list and prepend it
+ SpanQuery lastQuery = this.segments.remove(this.segments.size() - 1);
+ SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, lastQuery);
+ SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, appendQuery);
+ ssqw.prepend(lastQuery);
+ saqw.or(ssqw);
+ this.segments.add((SpanQuery) saqw.toQuery());
+ }
+
+ // Situation is b?
+ else {
+ this.segments.add(appendQuery);
+
+ // Update boundary optionality
+ this.firstIsOptional = true;
+ this.isOptional = true;
+ this.lastIsOptional = true;
+ };
this.isNull = false;
};
return this;
@@ -93,46 +170,64 @@
public SpanSequenceQueryWrapper append (SpanRegexQueryWrapper srqw) {
if (!srqw.isNull()) {
- this.segments.add((SpanQuery) srqw.toQuery());
- this.isNull = false;
+ return this.append((SpanQuery) srqw.toQuery());
};
return this;
};
public SpanSequenceQueryWrapper append (SpanWildcardQueryWrapper swqw) {
if (!swqw.isNull()) {
- this.segments.add((SpanQuery) swqw.toQuery());
- this.isNull = false;
+ return this.append((SpanQuery) swqw.toQuery());
};
return this;
};
public SpanSequenceQueryWrapper prepend (String term) {
- this.segments.add(0, (SpanQuery) new SpanTermQuery(new Term(field, term)));
+ return this.prepend(new SpanTermQuery(new Term(field, term)));
+ };
+
+ public SpanSequenceQueryWrapper prepend (SpanQuery query) {
this.isNull = false;
+ this.isOptional = false;
+
+ // Check if there has to be alternation magic in action
+ if (this.firstIsOptional) {
+ SpanAlterQueryWrapper saqw = new SpanAlterQueryWrapper(field, query);
+ SpanSequenceQueryWrapper ssqw = new SpanSequenceQueryWrapper(field, query);
+ // Remove last element of the list and prepend it
+ ssqw.append(this.segments.remove(0));
+ saqw.or(ssqw);
+
+ // Update boundary optionality
+ if (this.lastIsOptional && this.segments.size() == 0)
+ this.lastIsOptional = false;
+ this.firstIsOptional = false;
+
+ this.segments.add(0, (SpanQuery) saqw.toQuery());
+ }
+ else {
+ this.segments.add(0,query);
+ };
return this;
};
public SpanSequenceQueryWrapper prepend (SpanSegmentQueryWrapper ssq) {
if (!ssq.isNull()) {
- this.segments.add(0, (SpanQuery) ssq.toQuery());
- this.isNull = false;
+ return this.prepend(ssq.toQuery());
};
return this;
};
public SpanSequenceQueryWrapper prepend (SpanRegexQueryWrapper re) {
if (!re.isNull()) {
- this.segments.add(0, (SpanQuery) re.toQuery());
- this.isNull = false;
+ return this.prepend(re.toQuery());
};
return this;
};
public SpanSequenceQueryWrapper prepend (SpanWildcardQueryWrapper swqw) {
if (!swqw.isNull()) {
- this.segments.add(0, (SpanQuery) swqw.toQuery());
- this.isNull = false;
+ return this.prepend(swqw.toQuery());
};
return this;
};
@@ -254,7 +349,7 @@
};
public boolean isOptional () {
- return false;
+ return this.isOptional;
};
public boolean isNull () {
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
index fe6f9c2..68b07fd 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithinQueryWrapper.java
@@ -10,13 +10,19 @@
import org.apache.lucene.search.spans.SpanQuery;
+/*
+ Document: Optionality of operands will be ignored - while the optionality of the wrap is herited!
+
+ Idea:
+ - Maybe inherit the optionality when it is in an element and rewrite the query to an alternation if the wrap is
+*/
public class SpanWithinQueryWrapper implements SpanQueryWrapperInterface {
private SpanQueryWrapperInterface element;
private SpanQueryWrapperInterface wrap;
private byte flag;
- private boolean isNull = true;;
+ private boolean isNull = true;
public SpanWithinQueryWrapper (SpanQueryWrapperInterface element, SpanQueryWrapperInterface wrap) {
this.element = element;
@@ -30,6 +36,7 @@
this.element = element;
this.wrap = wrap;
this.flag = flag;
+
if (!element.isNull() && !wrap.isNull())
this.isNull = false;
};