Modified AttributeSpans to have the same start and end positions as their elements,
Modified SpansWithAttribute to be able to return *arbitrary* elements with attributes.
Modified deserialization for SpanWithAttributeQuery.
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index 9af942d..a3e1f86 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -959,6 +959,7 @@
"JSON-LD group has no @type attribute");
}
+ SpanQueryWrapper elementWithIdWrapper = null;
if (value.toString().isEmpty()) {
// attribute with arbitraty elements
@@ -966,10 +967,9 @@
"Arbitraty elements with attributes are currently not supported.");
return null;
}
-
- SpanQueryWrapper elementWithIdWrapper = tag(value.toString());
- if (elementWithIdWrapper == null) {
- return null;
+ else{
+ elementWithIdWrapper = tag(value.toString());
+ if (elementWithIdWrapper == null) return null;
}
if (attrNode.get("@type").asText().equals("korap:term")) {
diff --git a/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java b/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
index 9c7f616..c304bb9 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
@@ -8,6 +8,10 @@
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.SpanTermQuery;
+
+import de.ids_mannheim.korap.query.spans.AttributeSpans;
+import de.ids_mannheim.korap.query.spans.ElementSpans;
/**
* A base class for Spanqueries. It added some properties and methods to the
@@ -110,28 +114,16 @@
* */
public SimpleSpanQuery(SpanQuery firstClause,
List<SpanQuery> secondClauses, boolean collectPayloads) {
- this(firstClause, collectPayloads);
-
- if (secondClauses == null) {
- throw new IllegalArgumentException(
- "The list of second clauses cannot be null.");
- }
- if (secondClauses.size() < 1) {
- throw new IllegalArgumentException(
- "The list of second clauses cannot be empty.");
- }
-
- for (SpanQuery secondClause : secondClauses) {
- if (secondClause == null) {
- throw new IllegalArgumentException(
- "A second clause cannot be null.");
- }
- checkField(secondClause);
- }
- this.setClauseList(secondClauses);
+ this(firstClause, collectPayloads);
+ setClauseList(secondClauses);
}
- private void checkField(SpanQuery clause) {
+ public SimpleSpanQuery(List<SpanQuery> clauses, boolean collectPayloads) {
+ this.collectPayloads = collectPayloads;
+ setClauseList(clauses);
+ }
+
+ private void checkField(SpanQuery clause) {
if (!clause.getField().equals(field)) {
throw new IllegalArgumentException(
"Clauses must have the same field.");
@@ -152,8 +144,27 @@
*
* @param clauseList a list of spanqueries
*/
- public void setClauseList(List<SpanQuery> clauseList) {
- this.clauseList = clauseList;
+ public void setClauseList(List<SpanQuery> clauses) {
+ if (clauses == null) {
+ throw new IllegalArgumentException(
+ "The list of clauses cannot be null.");
+ }
+ if (clauses.size() < 1) {
+ throw new IllegalArgumentException(
+ "The list of clauses cannot be empty.");
+ }
+
+ if (this.field == null) {
+ this.field = clauses.get(0).getField();
+ }
+
+ for (SpanQuery clause : clauses) {
+ if (clause == null) {
+ throw new IllegalArgumentException("A clause cannot be null.");
+ }
+ checkField(clause);
+ }
+ this.clauseList = clauses;
}
/**
@@ -247,10 +258,13 @@
@Override
public Query rewrite(IndexReader reader) throws IOException {
SimpleSpanQuery clone = null;
- clone = updateClone(reader, clone, firstClause, 1);
+ if (firstClause != null) {
+ clone = updateClone(reader, clone, firstClause, 1);
+ }
if (secondClause != null) {
clone = updateClone(reader, clone, secondClause, 2);
- } else if (clauseList != null) {
+ }
+ else if (clauseList != null) {
clone = updateClone(reader, clone, clauseList);
}
return (clone != null ? clone : this);
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanAttributeQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanAttributeQuery.java
index 5f4c262..6a5038c 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SpanAttributeQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanAttributeQuery.java
@@ -38,7 +38,7 @@
*
* @author margaretha
* */
-public class SpanAttributeQuery extends SimpleSpanQuery {
+public class SpanAttributeQuery extends SpanWithIdQuery {
boolean negation;
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java
index 65335f2..d4d66eb 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java
@@ -39,13 +39,39 @@
*/
public class SpanWithAttributeQuery extends SpanWithIdQuery {
- private boolean isMultipleAttributes;
+ public boolean isMultipleAttributes;
private String type;
+ /**
+ * Constructs a SpanWithAttributeQuery for any arbitrary SpansWithId (e.g.
+ * elements, relations) having the specified {@link SpanAttributeQuery}.
+ *
+ * @param attributeQuery a SpanAttributeQuery
+ * @param collectPayloads a boolean flag representing the value
+ * <code>true</code> if payloads are to be collected, otherwise
+ * <code>false</code>.
+ */
+ public SpanWithAttributeQuery(SpanAttributeQuery attributeQuery,
+ boolean collectPayloads) {
+ super(attributeQuery, collectPayloads);
+ type = "spanWithAttribute";
+ }
+
+ public SpanWithAttributeQuery(List<SpanQuery> attributeQueries,
+ boolean collectPayloads) {
+ super(attributeQueries, collectPayloads);
+ isMultipleAttributes = true;
+ type = "spanWithAttribute";
+ }
+
/**
* Constructs a SpanWithAttributeQuery for the specified SpanWithIdQuery and
* SpanAttributeQuery retrieving spans having a specific attribute.
*
+ * If the SpanWithIdQuery is a SpanAttributeQuery, this will return arbitrary
+ * elements with two specified attributes (i.e. and relation between the two
+ * attributes).
+ *
* @param firstClause a SpanWithIdQuery
* @param secondClause a SpanAttributeQuery
* @param collectPayloads a boolean flag representing the value
@@ -98,53 +124,88 @@
@Override
public SimpleSpanQuery clone() {
- SpanWithAttributeQuery sq;
- if (!isMultipleAttributes) {
- sq = new SpanWithAttributeQuery(
- (SpanWithIdQuery) firstClause.clone(),
- (SpanAttributeQuery) secondClause.clone(), collectPayloads);
- } else {
- List<SpanQuery> clauseList = new ArrayList<SpanQuery>();
- SpanAttributeQuery saq;
- for (SpanQuery q : this.clauseList) {
- saq = (SpanAttributeQuery) q;
- clauseList.add(saq.clone());
+ if (secondClause != null) {
+ if (isMultipleAttributes) {
+ return new SpanWithAttributeQuery(
+ (SpanWithIdQuery) firstClause.clone(), cloneClauseList(),
+ collectPayloads);
+ }
+ else {
+ return new SpanWithAttributeQuery(
+ (SpanWithIdQuery) firstClause.clone(),
+ (SpanAttributeQuery) secondClause.clone(),
+ collectPayloads);
}
- sq = new SpanWithAttributeQuery(
- (SpanWithIdQuery) firstClause.clone(), clauseList,
- collectPayloads);
}
- return sq;
+ else {
+ if (isMultipleAttributes) {
+ return new SpanWithAttributeQuery(cloneClauseList(),
+ collectPayloads);
+ }
+ else {
+ return new SpanWithAttributeQuery(
+ (SpanAttributeQuery) firstClause.clone(),
+ collectPayloads);
+ }
+ }
}
+ private List<SpanQuery> cloneClauseList() {
+ List<SpanQuery> clauseList = new ArrayList<SpanQuery>();
+ SpanAttributeQuery saq;
+ for (SpanQuery q : this.clauseList) {
+ saq = (SpanAttributeQuery) q;
+ clauseList.add(saq.clone());
+ }
+ return clauseList;
+ }
+
@Override
public Spans getSpans(AtomicReaderContext context, Bits acceptDocs,
Map<Term, TermContext> termContexts) throws IOException {
+ if (type.equals("spanWithAttribute")) {
+ return new SpansWithAttribute(this, context, acceptDocs,
+ termContexts);
+ }
+
Spans spans = this.getFirstClause().getSpans(context, acceptDocs,
termContexts);
- if (type.equals("spanElementWithAttribute")) {
+ if (type.equals("spanElementWithAttribute")) {
return new SpansWithAttribute(this, (ElementSpans) spans, context,
acceptDocs, termContexts);
- } else if (type.equals("spanRelationWithAttribute")) {
+ }
+ else if (type.equals("spanRelationWithAttribute")) {
return new SpansWithAttribute(this, (RelationSpans) spans, context,
acceptDocs, termContexts);
}
-
- return new SpansWithAttribute(this, (TermSpansWithId) spans, context,
+ else if (type.equals("spanTermWithAttribute")){
+ return new SpansWithAttribute(this, (TermSpansWithId) spans, context,
acceptDocs, termContexts);
+ }
+ else {
+ throw new IllegalArgumentException("Span query type: " + type
+ + "is unknown.");
+ }
}
@Override
public String toString(String field) {
-
+ boolean isFirstClassNull = true;
StringBuilder sb = new StringBuilder();
sb.append(type);
sb.append("(");
- sb.append(firstClause.toString(field));
- sb.append(", ");
- if (isMultipleAttributes) {
+ if (firstClause != null) {
+ sb.append(firstClause.toString(field));
+ isFirstClassNull = false;
+ }
+ if (secondClause !=null){
+ sb.append(", ");
+ sb.append(secondClause.toString(field));
+ }
+ else if (isMultipleAttributes) {
+ if (!isFirstClassNull) sb.append(", ");
sb.append("[");
SpanQuery sq;
@@ -157,10 +218,8 @@
}
sb.append("]");
- } else {
- sb.append(secondClause.toString(field));
- }
- sb.append(")");
+ }
+ sb.append(")");
return sb.toString();
}
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanWithIdQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanWithIdQuery.java
index 55e2744..4845a01 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SpanWithIdQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanWithIdQuery.java
@@ -56,4 +56,9 @@
List<SpanQuery> secondClauses, boolean collectPayloads) {
super(firstClause, secondClauses, collectPayloads);
}
+
+ public SpanWithIdQuery(List<SpanQuery> clauses,
+ boolean collectPayloads) {
+ super(clauses, collectPayloads);
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
index 201e9df..6382222 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
@@ -18,7 +18,7 @@
import de.ids_mannheim.korap.query.SpanAttributeQuery;
-/**
+/** UPDATE THIS!
* Span enumeration of attributes which are term spans with special payload
* assignments referring to another span (e.g. element/relation span) to which
* an attribute span belongs. The class is basically a wrapper of Lucene
@@ -36,13 +36,13 @@
*
* @author margaretha
* */
-public class AttributeSpans extends SimpleSpans {
+public class AttributeSpans extends SpansWithId {
private List<CandidateAttributeSpan> candidateList;
private int currentDoc, currentPosition;
- private short referentId;
+ // private short referentId;
private boolean isFinish;
- private int elementEnd;
+ // private int elementEnd;
protected Logger logger = LoggerFactory.getLogger(AttributeSpans.class);
@@ -90,8 +90,8 @@
this.matchDocNumber = cs.getDoc();
this.matchStartPosition = cs.getStart();
this.matchEndPosition = cs.getEnd();
- this.setReferentId(cs.getSpanId());
- this.setElementEnd(cs.getElementEnd());
+ this.setSpanId(cs.getSpanId()); // referentId
+ // this.setElementEnd(cs.getElementEnd());
candidateList.remove(0);
return true;
} else {
@@ -149,9 +149,9 @@
*
* @return a span id, for instance a relation id or an element id
*/
- public short getReferentId() {
- return this.referentId;
- }
+ // public short getReferentId() {
+ // return this.referentId;
+ // }
/**
* Sets the span id to which an attribute span belongs, for instance a
@@ -160,9 +160,9 @@
* @param refId the span id to which an attribute span belongs, for
* instance a relation id or an element id.
*/
- public void setReferentId(short refId) {
- this.referentId = refId;
- }
+ // public void setReferentId(short refId) {
+ // this.referentId = refId;
+ // }
/**
* Returns the end position of the element to which an attribute span
@@ -170,9 +170,9 @@
*
* @return an element end position
*/
- public int getElementEnd() {
- return elementEnd;
- }
+ // public int getElementEnd() {
+ // return elementEnd;
+ // }
/**
* Sets the end position of the element to which an attribute span belongs.
@@ -180,9 +180,9 @@
* @param elementEnd the end position of the element to which an attribute
* span belongs.
*/
- public void setElementEnd(int elementEnd) {
- this.elementEnd = elementEnd;
- }
+ // public void setElementEnd(int elementEnd) {
+ // this.elementEnd = elementEnd;
+ // }
/**
* Tells if the enumeration of the AttributeSpans has come to an end.
@@ -234,7 +234,7 @@
Comparable<CandidateSpan> {
private short spanId;
- private int elementEnd;
+ // private int elementEnd;
/**
* Construct a CandidateAttributeSpan based on the given span, spanId,
@@ -251,8 +251,9 @@
public CandidateAttributeSpan(Spans span, short spanId, int elementEnd)
throws IOException {
super(span);
- setSpanId(spanId);
- setElementEnd(elementEnd);
+ setSpanId(spanId);
+ this.end = elementEnd;
+ // setElementEnd(elementEnd);
}
public void setSpanId(short spanId) {
@@ -263,13 +264,13 @@
return spanId;
}
- public int getElementEnd() {
- return elementEnd;
- }
-
- public void setElementEnd(int elementEnd) {
- this.elementEnd = elementEnd;
- }
+ // public int getElementEnd() {
+ // return elementEnd;
+ // }
+ //
+ // public void setElementEnd(int elementEnd) {
+ // this.elementEnd = elementEnd;
+ // }
@Override
public int compareTo(CandidateSpan o) {
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java b/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
index 914556b..ca1132d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
@@ -14,7 +14,7 @@
* @author margaretha
* */
public class CandidateSpan implements Comparable<CandidateSpan>, Cloneable {
- private int doc, start, end;
+ protected int doc, start, end;
private long cost;
private Collection<byte[]> payloads = new ArrayList<>();
private int position;
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/SimpleSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/SimpleSpans.java
index 869ece0..c9ca2e6 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/SimpleSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/SimpleSpans.java
@@ -8,6 +8,7 @@
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
+import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.Spans;
import org.apache.lucene.util.Bits;
@@ -44,12 +45,12 @@
matchPayload = new ArrayList<byte[]>();
// Get the enumeration of the two spans to match
- firstSpans = simpleSpanQuery.getFirstClause().
- getSpans(context, acceptDocs, termContexts);
+ SpanQuery sq;
+ if ((sq = simpleSpanQuery.getFirstClause()) != null)
+ firstSpans = sq.getSpans(context, acceptDocs, termContexts);
- if (simpleSpanQuery.getSecondClause() != null)
- secondSpans = simpleSpanQuery.getSecondClause().
- getSpans(context, acceptDocs, termContexts);
+ if ((sq = simpleSpanQuery.getSecondClause()) != null)
+ secondSpans = sq.getSpans(context, acceptDocs, termContexts);
isStartEnumeration=true;
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/SpansWithAttribute.java b/src/main/java/de/ids_mannheim/korap/query/spans/SpansWithAttribute.java
index 0362bfa..6adeaf5 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/SpansWithAttribute.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/SpansWithAttribute.java
@@ -9,6 +9,7 @@
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.Spans;
import org.apache.lucene.util.Bits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,24 +56,62 @@
referentSpans = spansWithId;
referentSpans.hasSpanId = true; // dummy setting enabling reading elementRef
hasMoreSpans = referentSpans.next();
-
- attributeList = new ArrayList<AttributeSpans>();
- notAttributeList = new ArrayList<AttributeSpans>();
-
- List<SpanQuery> sqs = spanWithAttributeQuery.getClauseList();
- if (sqs != null) {
- for (SpanQuery sq : sqs) {
- addAttributes((SpanAttributeQuery) sq, context, acceptDocs,
- termContexts);
- }
- } else {
- addAttributes(
- (SpanAttributeQuery) spanWithAttributeQuery
- .getSecondClause(),
- context, acceptDocs, termContexts);
- }
+ setAttributeList(spanWithAttributeQuery, context, acceptDocs,
+ termContexts);
}
+ // if there is no (positive) attributes, but there are *not attributes*
+ // hasmorespan = true
+ public SpansWithAttribute(SpanWithAttributeQuery spanWithAttributeQuery,
+ AtomicReaderContext context,
+ Bits acceptDocs, Map<Term, TermContext> termContexts)
+ throws IOException {
+ super(spanWithAttributeQuery, context, acceptDocs, termContexts);
+ hasMoreSpans = true;
+ setAttributeList(spanWithAttributeQuery, context, acceptDocs,
+ termContexts);
+ if (attributeList.size() == 0){
+ throw new IllegalArgumentException("No (positive) attribute is defined.");
+ }
+ else if (attributeList.size() > 1) {
+ referentSpans = attributeList.get(0);
+ attributeList.remove(0);
+ }
+ }
+
+ public void setAttributeList(SpanWithAttributeQuery swaq,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+
+ attributeList = new ArrayList<AttributeSpans>();
+ notAttributeList = new ArrayList<AttributeSpans>();
+
+ List<SpanQuery> attributeList = swaq.getClauseList();
+ if (swaq.isMultipleAttributes) {
+ if (attributeList != null) {
+ for (SpanQuery sq : attributeList) {
+ addAttributes((SpanAttributeQuery) sq, context, acceptDocs,
+ termContexts);
+ }
+ }
+ else {
+ throw new NullPointerException("Attribute list is null.");
+ }
+ }
+ else if (swaq.getSecondClause() != null) {
+ addAttributes((SpanAttributeQuery) swaq.getSecondClause(),
+ context, acceptDocs, termContexts);
+ }
+ else if (swaq.getType().equals("spanWithAttribute") &&
+ swaq.getFirstClause() != null) {
+ addAttributes((SpanAttributeQuery) swaq.getFirstClause(),
+ context, acceptDocs, termContexts);
+ }
+ else {
+ throw new NullPointerException("No attribute is defined.");
+ }
+ }
+
/**
* Adds the given {@link SpanAttributeQuery} to the attributeList or
* notAttributeList depending on the query, whether it is a negation or not.
@@ -86,12 +125,14 @@
private void addAttributes(SpanAttributeQuery sq,
AtomicReaderContext context, Bits acceptDocs,
Map<Term, TermContext> termContexts) throws IOException {
+
AttributeSpans as = (AttributeSpans) sq.getSpans(context, acceptDocs,
termContexts);
if (sq.isNegation()) {
notAttributeList.add(as);
as.next();
- } else {
+ }
+ else {
attributeList.add(as);
hasMoreSpans &= as.next();
}
@@ -100,25 +141,45 @@
@Override
public boolean next() throws IOException {
isStartEnumeration = false;
- return advance();
+ if (referentSpans == null) { // only one (positive) attribute
+ return advanceAttribute();
+ }
+ else { return advance(); }
}
- /**
- * Searches for the next match by first identify a possible element
- * position, and then ensuring that the element contains all the attributes
- * and <em>do not</em> contain any of the not attributes.
- *
- * @return <code>true</code> if the a match is found, <code>false</code>
- * otherwise.
- * @throws IOException
- */
+ private boolean advanceAttribute() throws IOException {
+ while(hasMoreSpans){
+ SpansWithId referentSpans = attributeList.get(0);
+ advanceNotAttributes(referentSpans);
+ if (checkNotReferentId(referentSpans)) {
+ this.matchDocNumber = referentSpans.doc();
+ this.matchStartPosition = referentSpans.start();
+ this.matchEndPosition = referentSpans.end();
+ this.matchPayload = referentSpans.getPayload();
+ this.spanId = referentSpans.getSpanId();
+ hasMoreSpans = referentSpans.next();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Searches for the next match by first identify a possible element
+ * position, and then ensuring that the element contains all the attributes
+ * and <em>do not</em> contain any of the not attributes.
+ *
+ * @return <code>true</code> if the a match is found, <code>false</code>
+ * otherwise.
+ * @throws IOException
+ */
private boolean advance() throws IOException {
while (hasMoreSpans && searchSpanPosition()) {
//logger.info("element: " + withAttributeSpans.start() + ","+ withAttributeSpans.end() +
// " ref:"+withAttributeSpans.getSpanId());
- if (checkReferentId() && checkNotReferentId()) {
+ if (checkReferentId() && checkNotReferentId(referentSpans)) {
this.matchDocNumber = referentSpans.doc();
this.matchStartPosition = referentSpans.start();
this.matchEndPosition = referentSpans.end();
@@ -151,8 +212,8 @@
continue;
}
if (checkAttributeListPosition()) {
- advanceNotAttributes();
- // logger.info("element is found: "+ withAttributeSpans.start());
+ advanceNotAttributes(referentSpans);
+ // logger.info("element is found: "+ withAttributeSpans.start());
return true;
}
}
@@ -216,7 +277,7 @@
*
* @throws IOException
*/
- private void advanceNotAttributes() throws IOException {
+ private void advanceNotAttributes(Spans referentSpans) throws IOException {
for (AttributeSpans a : notAttributeList) {
// advance the doc# of not AttributeSpans
@@ -231,7 +292,6 @@
a.setFinish(true);
}
}
- //return true;
}
/**
@@ -245,8 +305,8 @@
*/
private boolean checkReferentId() throws IOException {
for (AttributeSpans attribute : attributeList) {
- if (referentSpans.getSpanId() != attribute.getReferentId()) {
- if (referentSpans.getSpanId() < attribute.getReferentId())
+ if (referentSpans.getSpanId() != attribute.getSpanId()) {
+ if (referentSpans.getSpanId() < attribute.getSpanId())
hasMoreSpans = attribute.next();
else {
hasMoreSpans = referentSpans.next();
@@ -268,12 +328,12 @@
* <code>false</code> otherwise.
* @throws IOException
*/
- private boolean checkNotReferentId() throws IOException {
+ private boolean checkNotReferentId(SpansWithId referentSpans) throws IOException {
for (AttributeSpans notAttribute : notAttributeList) {
if (!notAttribute.isFinish()
&& referentSpans.start() == notAttribute.start()
&& referentSpans.getSpanId() == notAttribute
- .getReferentId()) {
+ .getSpanId()) {
hasMoreSpans = referentSpans.next();
return false;
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithAttributeQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithAttributeQueryWrapper.java
index 517e4c6..7b7418f 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithAttributeQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWithAttributeQueryWrapper.java
@@ -11,11 +11,48 @@
import de.ids_mannheim.korap.query.SpanWithIdQuery;
import de.ids_mannheim.korap.util.QueryException;
+/**
+ * No optimization using expansion
+ *
+ * @author margaretha
+ * */
public class SpanWithAttributeQueryWrapper extends SpanQueryWrapper {
private SpanQueryWrapper withIdQueryWrapper = null;
private SpanQueryWrapper attrQueryWrapper = null;
private List<SpanQueryWrapper> queryWrapperList = null;
+ private boolean isSingleAttribute = false;
+
+ public SpanWithAttributeQueryWrapper(SpanQueryWrapper attrQuery) {
+ if (attrQuery != null) isNull = false;
+ if (attrQuery.isEmpty()) {
+ isEmpty = true;
+ return;
+ }
+ this.attrQueryWrapper = attrQuery;
+ this.isSingleAttribute = true;
+ }
+
+ public SpanWithAttributeQueryWrapper(List<SpanQueryWrapper> attrList)
+ throws QueryException {
+
+ if (attrList != null) isNull = false;
+ if (attrList.isEmpty()) {
+ throw new QueryException("No attribute is defined.");
+ }
+
+ for (SpanQueryWrapper sqw : attrList) {
+ if (sqw == null) {
+ isNull = true;
+ return;
+ }
+ if (sqw.isEmpty) {
+ isEmpty = true;
+ return;
+ }
+ }
+ this.queryWrapperList = attrList;
+ }
public SpanWithAttributeQueryWrapper(SpanQueryWrapper withIdQuery,
SpanQueryWrapper attrQuery) {
@@ -30,6 +67,7 @@
this.attrQueryWrapper = attrQuery;
this.withIdQueryWrapper = withIdQuery;
+ this.isSingleAttribute = true;
}
public SpanWithAttributeQueryWrapper(SpanQueryWrapper withIdQuery,
@@ -42,6 +80,9 @@
isEmpty = true;
return;
}
+ // if (attrList.isEmpty()) {
+ // not withattribute query, just a normal query
+ // }
for (SpanQueryWrapper sqw : attrList) {
if (sqw == null) {
@@ -53,68 +94,108 @@
return;
}
}
- if (attrList.isEmpty()) {
- // not withattribute query, just a normal query
- }
+
this.queryWrapperList = attrList;
this.withIdQueryWrapper = withIdQuery;
}
- public SpanAttributeQuery createSpanAttributeQuery(
- SpanQueryWrapper attrQueryWrapper) throws QueryException {
- SpanQuery sq = attrQueryWrapper.toQuery();
- if (sq == null) {
- isNull = true;
- return null;
- }
- if (sq instanceof SpanTermQuery) {
- return new SpanAttributeQuery(
- (SpanTermQuery) sq,
- attrQueryWrapper.isNegative, true);
- }
- else {
- throw new IllegalArgumentException(
- "The subquery is not a SpanTermQuery.");
- }
- }
-
@Override
public SpanQuery toQuery() throws QueryException {
- if (isNull || isEmpty) return null;
-
+ if (isNull || isEmpty) return null;
+ if (withIdQueryWrapper != null){
+ return createSpecificSpanWithAttributeQuery();
+ }
+ else{
+ return createArbitrarySpanWithAttributeQuery();
+ }
+ }
+
+ private SpanQuery createSpecificSpanWithAttributeQuery()
+ throws QueryException {
SpanWithIdQuery withIdQuery = (SpanWithIdQuery) withIdQueryWrapper
.toQuery();
if (withIdQuery == null) {
isNull = true;
return null;
}
-
- if (attrQueryWrapper != null){
- SpanAttributeQuery attrQuery = createSpanAttributeQuery(attrQueryWrapper);
+ if (isSingleAttribute) {
+ return createSpanWithSingleAttributeQuery(withIdQuery);
+ }
+ else if (queryWrapperList.isEmpty()) {
+ return withIdQuery;
+ }
+ else{
+ return createSpanWithAttributeListQuery(withIdQuery);
+ }
+ }
+
+ private SpanWithAttributeQuery createSpanWithSingleAttributeQuery(
+ SpanWithIdQuery withIdQuery)
+ throws QueryException {
+ SpanAttributeQuery attrQuery = createSpanAttributeQuery(this.attrQueryWrapper);
+ if (attrQuery != null) {
+ if (withIdQuery != null) {
+ return new SpanWithAttributeQuery(withIdQuery, attrQuery, true);
+ }
+ else {
+ return new SpanWithAttributeQuery(attrQuery, true);
+ }
+ }
+ isNull = true;
+ return null;
+ }
+
+ private SpanAttributeQuery createSpanAttributeQuery(
+ SpanQueryWrapper attrQueryWrapper) throws QueryException {
+ SpanQuery sq = attrQueryWrapper.toQuery();
+ if (sq != null) {
+ if (sq instanceof SpanTermQuery) {
+ return new SpanAttributeQuery((SpanTermQuery) sq,
+ attrQueryWrapper.isNegative, true);
+ }
+ else {
+ throw new IllegalArgumentException(
+ "The subquery is not a SpanTermQuery.");
+ }
+ }
+ return null;
+ }
+
+ private SpanWithAttributeQuery createSpanWithAttributeListQuery(
+ SpanWithIdQuery withIdQuery)
+ throws QueryException {
+ List<SpanQuery> attrQueries = new ArrayList<SpanQuery>();
+ SpanQuery attrQuery = null;
+ for (SpanQueryWrapper sqw : queryWrapperList) {
+ attrQuery = createSpanAttributeQuery(sqw);
if (attrQuery == null) {
isNull = true;
return null;
}
- return new SpanWithAttributeQuery(withIdQuery, attrQuery, true);
+ attrQueries.add(attrQuery);
}
- else if (queryWrapperList != null) {
- if (queryWrapperList.isEmpty()) {
- return withIdQuery;
- }
-
- List<SpanQuery> attrQueries = new ArrayList<SpanQuery>();
- SpanQuery attrQuery;
- for (SpanQueryWrapper sqw : queryWrapperList) {
- attrQuery = createSpanAttributeQuery(sqw);
- if (attrQuery == null) {
- isNull = true;
- return null;
- }
- attrQueries.add(attrQuery);
- }
+
+ if (withIdQuery != null) {
return new SpanWithAttributeQuery(withIdQuery, attrQueries, true);
+ }
+ else {
+ return new SpanWithAttributeQuery(attrQueries, true);
}
- return null;
}
+
+ private SpanQuery createArbitrarySpanWithAttributeQuery()
+ throws QueryException {
+ if (isSingleAttribute) {
+ return createSpanWithSingleAttributeQuery(null);
+ }
+ else if (queryWrapperList.isEmpty()) {
+ throw new QueryException("No attribute is defined.");
+ }
+ else{
+ return createSpanWithAttributeListQuery(null);
+ }
+ }
+
+
}
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
index d4a9ae2..aa14142 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
@@ -72,7 +72,7 @@
+ "[(1-2)s:e|_2#1-2|<>:div#1-2$<i>2<s>1|<>:a#1-2$<i>2<s>2|@:class=book$<s>2<i>2|@:class=header$<s>1<i>2]"
+ "[(2-3)s:b|_3#2-3|<>:div#2-3$<i>5<s>1|<>:a#1-2$<i>2<s>2|@:class=header$<s>2<i>2|@:class=book$<s>1<i>5]"
+ "[(3-4)s:a|_4#3-4|<>:div#3-5$<i>5<s>1|@:class=title$<s>1<i>5]"
- + "[(4-5)s:b|_5#4-5|<>:div#4-5$<i>5<s>1|@:class=header$<s>1<i>5|@:class=book$<s>1<i>5|@:class=book$<s>1<i>5]"
+ + "[(4-5)s:b|_5#4-5|<>:div#4-5$<i>5<s>1|@:class=header$<s>1<i>5|@:class=book$<s>1<i>5]"
+ "[(5-6)s:d|_6#5-6|<>:s#5-6$<i>6<s>-1|<>:div#5-6$<i>6<s>1|@:class=header$<s>1<i>6]"
+ "[(6-7)s:d|_7#6-7|<>:s#6-7$<i>7<s>2|<>:div#6-7$<i>7<s>1|@:class=header$<s>1<i>7|@:class=book$<s>2<i>7]");
@@ -171,6 +171,51 @@
assertEquals(6, kr.getMatch(0).getEndPos());
}
+ /**
+ * Element with only not attributes
+ *
+ * @throws IOException
+ * */
+ @Test
+ public void testcase9() throws IOException {
+
+ ki.addDoc(createFieldDoc2());
+ ki.commit();
+
+ SpanAttributeQuery saq = new SpanAttributeQuery(new SpanTermQuery(
+ new Term("base", "@:class=book")), true, true);
+ SpanQuery sq = new SpanWithAttributeQuery(new SpanElementQuery("base",
+ "div"), saq, true);
+
+ kr = ki.search(sq, (short) 10);
+ assertEquals(4, kr.getTotalResults());
+ assertEquals(1, kr.getMatch(0).getStartPos());
+ assertEquals(2, kr.getMatch(0).getEndPos());
+ assertEquals(3, kr.getMatch(1).getStartPos());
+ assertEquals(5, kr.getMatch(1).getEndPos());
+ assertEquals(5, kr.getMatch(2).getStartPos());
+ assertEquals(6, kr.getMatch(2).getEndPos());
+ assertEquals(6, kr.getMatch(3).getStartPos());
+ assertEquals(7, kr.getMatch(3).getEndPos());
+
+ List<SpanQuery> sql = new ArrayList<>();
+ sql.add(saq);
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=header")), true, true));
+ sq = new SpanWithAttributeQuery(new SpanElementQuery("base", "div"),
+ sql, true);
+
+ kr = ki.search(sq, (short) 10);
+ assertEquals(1, kr.getTotalResults());
+ assertEquals(3, kr.getMatch(0).getStartPos());
+ assertEquals(5, kr.getMatch(0).getEndPos());
+
+// for (int i = 0; i < kr.getTotalResults(); i++) {
+// System.out.println(kr.getMatch(i).getLocalDocID() + " "
+// + kr.getMatch(i).startPos + " " + kr.getMatch(i).endPos);
+// }
+ }
+
/**
* same attribute types referring to different element types
* */
@@ -230,23 +275,111 @@
}
/**
- * Arbitrary elements with a specific attribute This is just spanAttribute
- * query, to get the elementEnd, you have to use getElementEnd().
- * Alternatives (unimplemented): 1) store in payload? 2) wrap as a span
- * */
+ * Arbitrary elements with a specific attribute.
+ * */
@Test
public void testCase5() throws IOException {
- ki.addDoc(createFieldDoc1());
+ ki.addDoc(createFieldDoc2());
ki.commit();
- SpanAttributeQuery saq = new SpanAttributeQuery(new SpanTermQuery(
- new Term("base", "@:class=book")), true);
- kr = ki.search(saq, (short) 10);
- assertEquals((long) 3, kr.getTotalResults());
+ SpanAttributeQuery saq = new SpanAttributeQuery(new SpanTermQuery(
+ new Term("base", "@:class=book")), true);
- /*
- * for (int i=0; i< kr.getTotalResults(); i++){ System.out.println(
- * kr.match(i).getLocalDocID()+" "+ kr.match(i).startPos + " " +
- * kr.match(i).endPos ); }
- */
+ SpanWithAttributeQuery swaq = new SpanWithAttributeQuery(saq, true);
+ kr = ki.search(swaq, (short) 10);
+ assertEquals(6, kr.getTotalResults());
+
+ assertEquals(0, kr.getMatch(0).getStartPos());
+ assertEquals(3, kr.getMatch(0).getEndPos());
+ assertEquals(0, kr.getMatch(1).getStartPos());
+ assertEquals(5, kr.getMatch(1).getEndPos());
+ assertEquals(1, kr.getMatch(2).getStartPos());
+ assertEquals(2, kr.getMatch(2).getEndPos());
+ assertEquals(2, kr.getMatch(3).getStartPos());
+ assertEquals(5, kr.getMatch(3).getEndPos());
+ assertEquals(4, kr.getMatch(4).getStartPos());
+ assertEquals(5, kr.getMatch(4).getEndPos());
+ assertEquals(6, kr.getMatch(5).getStartPos());
+ assertEquals(7, kr.getMatch(5).getEndPos());
}
+
+ /**
+ * Arbitrary elements with multiple attributes.
+ * */
+ @Test
+ public void testCase6() throws IOException {
+ ki.addDoc(createFieldDoc2());
+ ki.commit();
+
+ List<SpanQuery> sql = new ArrayList<>();
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=header")), true));
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=book")), true));
+
+ SpanWithAttributeQuery swaq = new SpanWithAttributeQuery(sql, true);
+ kr = ki.search(swaq, (short) 10);
+ assertEquals(2, kr.getTotalResults());
+
+ assertEquals(0, kr.getMatch(0).getStartPos());
+ assertEquals(3, kr.getMatch(0).getEndPos());
+ assertEquals(4, kr.getMatch(1).getStartPos());
+ assertEquals(5, kr.getMatch(1).getEndPos());
+
+// for (int i = 0; i < kr.getTotalResults(); i++) {
+// System.out.println(kr.getMatch(i).getLocalDocID() + " "
+// + kr.getMatch(i).startPos + " " + kr.getMatch(i).endPos);
+// }
+ }
+
+ /**
+ * Arbitrary elements with an attribute and a not attribute.
+ * */
+ @Test
+ public void testCase7() throws IOException {
+ ki.addDoc(createFieldDoc2());
+ ki.commit();
+
+ List<SpanQuery> sql = new ArrayList<>();
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=header")), true, true));
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=book")), true));
+
+ SpanWithAttributeQuery swaq = new SpanWithAttributeQuery(sql, true);
+ kr = ki.search(swaq, (short) 10);
+ assertEquals(4, kr.getTotalResults());
+
+ assertEquals(0, kr.getMatch(0).getStartPos());
+ assertEquals(5, kr.getMatch(0).getEndPos());
+ assertEquals(1, kr.getMatch(1).getStartPos());
+ assertEquals(2, kr.getMatch(1).getEndPos());
+ assertEquals(2, kr.getMatch(2).getStartPos());
+ assertEquals(5, kr.getMatch(2).getEndPos());
+ assertEquals(6, kr.getMatch(3).getStartPos());
+ assertEquals(7, kr.getMatch(3).getEndPos());
+
+// for (int i = 0; i < kr.getTotalResults(); i++) {
+// System.out.println(kr.getMatch(i).getLocalDocID() + " "
+// + kr.getMatch(i).startPos + " " + kr.getMatch(i).endPos);
+// }
+ }
+
+ /**
+ * Arbitrary elements with only not attributes.
+ * */
+ @Test(expected = IllegalArgumentException.class)
+ public void testCase8() throws IOException {
+ ki.addDoc(createFieldDoc2());
+ ki.commit();
+
+ List<SpanQuery> sql = new ArrayList<>();
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=header")), true, true));
+ sql.add(new SpanAttributeQuery(new SpanTermQuery(new Term("base",
+ "@:class=book")), true, true));
+
+ SpanWithAttributeQuery swaq = new SpanWithAttributeQuery(sql, true);
+ kr = ki.search(swaq, (short) 10);
+ }
+
}