Added javadoc comments.
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 968fa39..7beedc0 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
@@ -6,133 +6,251 @@
import org.apache.lucene.search.spans.Spans;
-/** A span kept as a candidate for matching with another Span
- * @author margaretha
+/**
+ * A CandidateSpan works as an object storing the current state of the
+ * corresponding Lucene {@link Spans}, which is an enumeration. CandidateSpan is
+ * used for various purposes, such as for collecting spans which will be used in
+ * a latter process or next matching.
+ *
+ * @author margaretha
* */
-public class CandidateSpan implements Comparable<CandidateSpan>, Cloneable{
- private int doc,start,end;
- private long cost;
- private Collection<byte[]> payloads = new ArrayList<>();
- private int position;
- private CandidateSpan childSpan; // used for example for multiple distance with unordered constraint
- protected short spanId;
-
-
- public CandidateSpan(Spans span) throws IOException {
- this.doc = span.doc();
- this.start = span.start();
- this.end = span.end();
- this.cost = span.cost();
- if (span.isPayloadAvailable())
- setPayloads(span.getPayload());
- }
-
- @Override
- protected CandidateSpan clone() throws CloneNotSupportedException {
- return new CandidateSpan(
- this.start,
- this.end,
- this.doc,
- this.cost,
- this.payloads
- );
- }
-
- public CandidateSpan(Spans span, int position) throws IOException {
- this(span);
- this.position = position;
- }
-
- public CandidateSpan(int start, int end, int doc, long cost,
- Collection<byte[]> payloads) {
- this.start = start;
- this.end = end;
- this.doc = doc;
- this.cost = cost;
- if (payloads != null) setPayloads(payloads);
- }
+public class CandidateSpan implements Comparable<CandidateSpan>, Cloneable {
+ private int doc, start, end;
+ private long cost;
+ private Collection<byte[]> payloads = new ArrayList<>();
+ private int position;
+ private CandidateSpan childSpan; // used for example for multiple distance
+ // with unordered constraint
+ protected short spanId;
- public int getDoc() {
- return doc;
- }
- public void setDoc(int doc) {
- this.doc = doc;
- }
- public int getStart() {
- return start;
- }
- public void setStart(int start) {
- this.start = start;
- }
- public int getEnd() {
- return end;
- }
- public void setEnd(int end) {
- this.end = end;
- }
+ /**
+ * Constructs a CandidateSpan for the given Span.
+ *
+ * @param span a Span
+ * @throws IOException
+ */
+ public CandidateSpan(Spans span) throws IOException {
+ this.doc = span.doc();
+ this.start = span.start();
+ this.end = span.end();
+ this.cost = span.cost();
+ if (span.isPayloadAvailable())
+ setPayloads(span.getPayload());
+ }
- public Collection<byte[]> getPayloads() {
- return payloads;
- }
+ /**
+ * Constructs a CandidateSpan for the given Span and element position (where
+ * the span is included in a document). The element position is important
+ * for the matching process in {@link ElementDistanceSpans}.
+ *
+ * @param span a Span
+ * @param position an element position
+ * @throws IOException
+ */
+ public CandidateSpan(Spans span, int position) throws IOException {
+ this(span);
+ this.position = position;
+ }
- public void setPayloads(Collection<byte[]> payloads) {
-
- for (byte[] b : payloads){
- if (b == null)
- this.payloads.add(null);
- else
- this.payloads.add(b.clone());
- }
- }
+ /**
+ * Constructs a CandidateSpan from all the given variables which are
+ * properties of a Span.
+ *
+ * @param start the start position of a span
+ * @param end the end position of a span
+ * @param doc the document including the span
+ * @param cost the cost of finding a span
+ * @param payloads the payloads of a span
+ */
+ public CandidateSpan(int start, int end, int doc, long cost,
+ Collection<byte[]> payloads) {
+ this.start = start;
+ this.end = end;
+ this.doc = doc;
+ this.cost = cost;
+ if (payloads != null)
+ setPayloads(payloads);
+ }
- public long getCost() {
- return cost;
- }
+ @Override
+ protected CandidateSpan clone() throws CloneNotSupportedException {
+ return new CandidateSpan(this.start, this.end, this.doc, this.cost,
+ this.payloads);
+ }
- public void setCost(long cost) {
- this.cost = cost;
- }
+ /**
+ * Returns the document number containing the CandidateSpan.
+ *
+ * @return the document number
+ */
+ public int getDoc() {
+ return doc;
+ }
- public int getPosition() {
- return position;
- }
+ /**
+ * Sets the document number containing the CandidateSpan.
+ *
+ * @param doc the document number
+ */
+ public void setDoc(int doc) {
+ this.doc = doc;
+ }
- public void setPosition(int position) {
- this.position = position;
- }
+ /**
+ * Returns the start position of the CandidateSpan.
+ *
+ * @return the start position
+ */
+ public int getStart() {
+ return start;
+ }
- public CandidateSpan getChildSpan() {
- return childSpan;
- }
+ /**
+ * Sets the start position of the CandidateSpan.
+ *
+ * @param start the start position
+ */
+ public void setStart(int start) {
+ this.start = start;
+ }
- public void setChildSpan(CandidateSpan childSpan) {
- this.childSpan = childSpan;
- }
+ /**
+ * Returns the end position of the CandidateSpan.
+ *
+ * @return the end position
+ */
+ public int getEnd() {
+ return end;
+ }
- public short getSpanId() {
- return spanId;
- }
+ /**
+ * Sets the end position of the CandidateSpan.
+ *
+ * @param end the end position
+ */
+ public void setEnd(int end) {
+ this.end = end;
+ }
- public void setSpanId(short elementRef) {
- this.spanId = elementRef;
- }
+ /**
+ * Returns the payloads of the CandidateSpan.
+ *
+ * @return the payloads
+ */
+ public Collection<byte[]> getPayloads() {
+ return payloads;
+ }
- @Override
- public int compareTo(CandidateSpan o) {
- if (this.doc == o.doc){
- if (this.getStart() == o.getStart()){
- if (this.getEnd() == o.getEnd())
- return 0;
- if (this.getEnd() > o.getEnd() )
- return 1;
- else return -1;
- }
- else if (this.getStart() < o.getStart())
- return -1;
- else return 1;
- }
- else if (this.doc < o.doc)
- return -1;
- else return 1;
- }
+ /**
+ * Sets the payloads of the CandidateSpan.
+ *
+ * @param payloads the payloads
+ */
+ public void setPayloads(Collection<byte[]> payloads) {
+
+ for (byte[] b : payloads) {
+ if (b == null)
+ this.payloads.add(null);
+ else
+ this.payloads.add(b.clone());
+ }
+ }
+
+ /**
+ * Returns the cost of finding the CandidateSpan.
+ *
+ * @return the cost
+ */
+ public long getCost() {
+ return cost;
+ }
+
+ /**
+ * Sets the cost of finding the CandidateSpan.
+ *
+ * @param cost the cost
+ */
+ public void setCost(long cost) {
+ this.cost = cost;
+ }
+
+ /**
+ * Returns the element position number containing the CandidateSpan.
+ *
+ * @return the element position number
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Sets the element position number containing the CandidateSpan.
+ *
+ * @param position the element position number
+ */
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ /**
+ * Returns a child/sub Span of the CandidateSpan.
+ *
+ * @return a child/sub span of the CandidateSpan
+ */
+ public CandidateSpan getChildSpan() {
+ return childSpan;
+ }
+
+ /**
+ * Sets the child/sub span of the CandidateSpan.
+ *
+ * @param childSpan a child/sub span of the CandidateSpan
+ */
+ public void setChildSpan(CandidateSpan childSpan) {
+ this.childSpan = childSpan;
+ }
+
+ /**
+ * Returns the span id of another Span related to the CandidateSpan. Only
+ * CandidateSpan of particular Spans such as {@link AttributeSpans} having
+ * this property. For instance, an AttributeSpan has a spanId of the element
+ * it belongs to.
+ *
+ * @return the span id of another Span related to the CandidateSpan
+ */
+ public short getSpanId() {
+ return spanId;
+ }
+
+ /**
+ * Sets the span id of another Span related to the CandidateSpan. Only
+ * CandidateSpan of particular Spans such as {@link AttributeSpans} having
+ * this property. For instance, an AttributeSpan has a spanId of the element
+ * it belongs to.
+ *
+ * @param spanId the span id of another Span related to the CandidateSpan
+ */
+ public void setSpanId(short spanId) {
+ this.spanId = spanId;
+ }
+
+ @Override
+ public int compareTo(CandidateSpan o) {
+ if (this.doc == o.doc) {
+ if (this.getStart() == o.getStart()) {
+ if (this.getEnd() == o.getEnd())
+ return 0;
+ if (this.getEnd() > o.getEnd())
+ return 1;
+ else
+ return -1;
+ } else if (this.getStart() < o.getStart())
+ return -1;
+ else
+ return 1;
+ } else if (this.doc < o.doc)
+ return -1;
+ else
+ return 1;
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/ElementDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/ElementDistanceSpans.java
index 229004e..cad169a 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/ElementDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/ElementDistanceSpans.java
@@ -12,145 +12,158 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Span enumeration of element-based distance span matches.
- * Each match consists of two child spans. The element-distance between
- * the child spans is the difference between the element position numbers
- * where the child spans are. The element-distance unit can be a sentence
- * or a paragraph. All other child spans occurrence which are not in
- * a sentence or a paragraph (with respect to the element distance type
- * current used), are ignored.
- *
- * Note: elements cannot overlap to each other.
+/**
+ * Span enumeration of element-based distance span matches. Each match consists
+ * of two child spans. The element-distance between the child spans is the
+ * difference between the element position numbers where the child spans are.
+ * The element-distance unit can be a sentence or a paragraph. All other child
+ * spans' occurrences which are not in a sentence or a paragraph (with respect
+ * to the element distance type currently used), are ignored.
+ *
+ * Note: elements cannot overlap to each other.
*
* @author margaretha
* */
public class ElementDistanceSpans extends OrderedDistanceSpans {
- private Spans elements;
- private boolean hasMoreElements;
- private int elementPosition;
- private int secondSpanPostion;
-
- public ElementDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts)
- throws IOException {
- super(query, context, acceptDocs, termContexts);
-
- elements = query.getElementQuery().
- getSpans(context, acceptDocs, termContexts);
-
- hasMoreElements = elements.next();
- hasMoreSpans = hasMoreFirstSpans && hasMoreElements;
- elementPosition=0;
- }
+ private Spans elements;
+ private boolean hasMoreElements;
+ private int elementPosition;
+ private int secondSpanPostion;
- @Override
- protected boolean findMatch() throws IOException {
- CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
- int actualDistance = secondSpanPostion - candidateSpan.getPosition();
-
- // In the same element
- if (minDistance == 0 && actualDistance == 0){
- setMatchProperties(candidateSpan, true);
- return true;
- }
-
- if (minDistance <= actualDistance && actualDistance <= maxDistance){
- setMatchProperties(candidateSpan, false);
- return true;
- }
-
- return false;
- }
-
- @Override
- protected void setCandidateList() throws IOException{
- if (candidateListDocNum == elements.doc() &&
- candidateListDocNum == secondSpans.doc()){
- candidateListIndex = -1;
- addNewCandidates();
- }
- else {
- candidateList.clear();
- if (hasMoreFirstSpans && findSameDoc(firstSpans, secondSpans, elements)){
- candidateListDocNum = firstSpans.doc();
- elementPosition=0;
- candidateListIndex = -1;
- addNewCandidates();
- }
- }
- }
-
- /** Add new possible candidates. Candidates must be in an element
- * and not too far from the secondspan.
- * */
- private void addNewCandidates() throws IOException{
- while ( hasMoreFirstSpans &&
- firstSpans.doc() == candidateListDocNum &&
- firstSpans.start() < secondSpans.end()){
-
- if (advanceElementTo(firstSpans)){
- candidateList.add(new CandidateSpan(firstSpans,elementPosition));
- filterCandidateList(elementPosition);
- }
- hasMoreFirstSpans = firstSpans.next();
- }
- }
-
-
- /** Advance elements until encountering a span within the given document.
- * @return true iff an element containing the span, is found.
- */
- private boolean advanceElementTo(Spans span) throws IOException{
- while (hasMoreElements &&
- elements.doc() == candidateListDocNum &&
- elements.start() < span.end()){
-
- if (span.start() >= elements.start() &&
- span.end() <= elements.end()){
- return true;
- }
-
- hasMoreElements = elements.next();
- elementPosition++;
- }
- return false;
- }
-
+ /**
+ * Constructs ElementDistanceSpans based on the given SpanDistanceQuery.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public ElementDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
- /** Reduce the number of candidates by removing all candidates that are
- * not within the max distance from the given element position.
- * */
- private void filterCandidateList(int position){
-
- Iterator<CandidateSpan> i = candidateList.iterator();
- CandidateSpan cs;
- while(i.hasNext()){
- cs = i.next();
- if (cs.getPosition() == position ||
- cs.getPosition()+maxDistance >= position){
- break;
- }
- i.remove();
- }
- //System.out.println("pos "+position+" " +candidateList.size());
- }
-
- @Override
- protected boolean isSecondSpanValid() throws IOException{
- if (advanceElementTo(secondSpans)){
- secondSpanPostion = elementPosition;
- filterCandidateList(secondSpanPostion);
- return true;
- }
- // second span is not in an element
- return false;
- }
-
- @Override
- public long cost() {
- CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
- return elements.cost() + candidateSpan.getCost() + secondSpans.cost();
- }
+ elements = query.getElementQuery().getSpans(context, acceptDocs,
+ termContexts);
+
+ hasMoreElements = elements.next();
+ hasMoreSpans = hasMoreFirstSpans && hasMoreElements;
+ elementPosition = 0;
+ }
+
+ @Override
+ protected boolean findMatch() throws IOException {
+ CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
+ int actualDistance = secondSpanPostion - candidateSpan.getPosition();
+
+ // In the same element
+ if (minDistance == 0 && actualDistance == 0) {
+ setMatchProperties(candidateSpan, true);
+ return true;
+ }
+
+ if (minDistance <= actualDistance && actualDistance <= maxDistance) {
+ setMatchProperties(candidateSpan, false);
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void setCandidateList() throws IOException {
+ if (candidateListDocNum == elements.doc()
+ && candidateListDocNum == secondSpans.doc()) {
+ candidateListIndex = -1;
+ addNewCandidates();
+ } else {
+ candidateList.clear();
+ if (hasMoreFirstSpans
+ && findSameDoc(firstSpans, secondSpans, elements)) {
+ candidateListDocNum = firstSpans.doc();
+ elementPosition = 0;
+ candidateListIndex = -1;
+ addNewCandidates();
+ }
+ }
+ }
+
+ /**
+ * Add new possible (candidate) firstspans. Candidate firstspans must be in
+ * an element and not too far from the secondspan.
+ *
+ * @throws IOException
+ */
+ private void addNewCandidates() throws IOException {
+ while (hasMoreFirstSpans && firstSpans.doc() == candidateListDocNum
+ && firstSpans.start() < secondSpans.end()) {
+
+ if (advanceElementTo(firstSpans)) {
+ candidateList
+ .add(new CandidateSpan(firstSpans, elementPosition));
+ filterCandidateList(elementPosition);
+ }
+ hasMoreFirstSpans = firstSpans.next();
+ }
+ }
+
+ /**
+ * Advance elements until encountering a span within the given document.
+ *
+ * @return true iff an element containing the span, is found.
+ */
+ private boolean advanceElementTo(Spans span) throws IOException {
+ while (hasMoreElements && elements.doc() == candidateListDocNum
+ && elements.start() < span.end()) {
+
+ if (span.start() >= elements.start()
+ && span.end() <= elements.end()) {
+ return true;
+ }
+
+ hasMoreElements = elements.next();
+ elementPosition++;
+ }
+ return false;
+ }
+
+ /**
+ * Reduce the number of candidates by removing all candidates that are not
+ * within the max distance from the given element position.
+ *
+ * @param position an element position
+ */
+ private void filterCandidateList(int position) {
+
+ Iterator<CandidateSpan> i = candidateList.iterator();
+ CandidateSpan cs;
+ while (i.hasNext()) {
+ cs = i.next();
+ if (cs.getPosition() == position
+ || cs.getPosition() + maxDistance >= position) {
+ break;
+ }
+ i.remove();
+ }
+ // System.out.println("pos "+position+" " +candidateList.size());
+ }
+
+ @Override
+ protected boolean isSecondSpanValid() throws IOException {
+ if (advanceElementTo(secondSpans)) {
+ secondSpanPostion = elementPosition;
+ filterCandidateList(secondSpanPostion);
+ return true;
+ }
+ // second span is not in an element
+ return false;
+ }
+
+ @Override
+ public long cost() {
+ CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
+ return elements.cost() + candidateSpan.getCost() + secondSpans.cost();
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/OrderedDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/OrderedDistanceSpans.java
index 1dd1a04..52185e8 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/OrderedDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/OrderedDistanceSpans.java
@@ -12,120 +12,145 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Base class for calculating a distance between two ordered spans.
- * @author margaretha
+/**
+ * Base class for calculating a distance between two ordered spans.
+ *
+ * @author margaretha
* */
public abstract class OrderedDistanceSpans extends DistanceSpans {
- public static final boolean DEBUG = false;
+ protected boolean hasMoreFirstSpans;
+ protected int minDistance, maxDistance;
- protected boolean hasMoreFirstSpans;
- protected int minDistance,maxDistance;
-
- protected List<CandidateSpan> candidateList;
- protected int candidateListIndex;
- protected int candidateListDocNum;
-
-
- public OrderedDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts)
- throws IOException {
- super(query, context, acceptDocs, termContexts);
-
- minDistance = query.getMinDistance();
- maxDistance = query.getMaxDistance();
-
- hasMoreFirstSpans = firstSpans.next();
-
- candidateList = new ArrayList<>();
- candidateListIndex = -1;
- candidateListDocNum = firstSpans.doc();
- }
-
- /** Find a span match in the candidate list.
- * */
- @Override
- protected boolean advance() throws IOException {
- while( hasMoreSpans && candidateListIndex < candidateList.size() ){
- // Check candidates
- for (candidateListIndex++;candidateListIndex < candidateList.size();
- candidateListIndex++){
- if (findMatch())
- return true;
- }
-
- do { // Forward secondspan
- hasMoreSpans = secondSpans.next();
- setCandidateList();
- }
- while (hasMoreSpans && !isSecondSpanValid());
- }
- return false;
- }
-
- /** Determine if the current second span is valid. It is always valid in
- * TokenDistanceSpan, but it can be invalid in the ElementDistanceSpan,
- * namely when it is not within a particular element (a sentence or a
- * paragraph depends on the element distance unit).
- *
- * */
- protected abstract boolean isSecondSpanValid() throws IOException;
-
- /** Collect all possible firstspan instances as candidate spans for
- * the current secondspan. The candidate spans are within the max
- * distance from the current secondspan.
- * */
- protected abstract void setCandidateList() throws IOException;
-
- /** Define the conditions for a match.
- * */
- protected abstract boolean findMatch() throws IOException;
-
- /** Define the properties of a span match.
- * */
- protected void setMatchProperties(CandidateSpan candidateSpan,
- boolean isDistanceZero) throws IOException{
-
- setMatchFirstSpan(candidateSpan);
- setMatchSecondSpan(new CandidateSpan(secondSpans));
-
- if (isDistanceZero){
- matchStartPosition = Math.min(candidateSpan.getStart(), secondSpans.start());
- matchEndPosition = Math.max(candidateSpan.getEnd(), secondSpans.end());
- }
- else {
- matchStartPosition = candidateSpan.getStart();
- matchEndPosition = secondSpans.end();
- }
-
- this.matchDocNumber = secondSpans.doc();
- if (collectPayloads){
- if (candidateSpan.getPayloads() != null) {
- matchPayload.addAll(candidateSpan.getPayloads());
- }
- if (secondSpans.isPayloadAvailable()) {
- matchPayload.addAll(secondSpans.getPayload());
- }
- }
+ protected List<CandidateSpan> candidateList;
+ protected int candidateListIndex;
+ protected int candidateListDocNum;
- if (DEBUG)
- log.trace("doc# {}, start {}, end {}",matchDocNumber,matchStartPosition,
- matchEndPosition);
- }
+ /**
+ * Constructs an OrderedDistanceSpans based on the given SpanDistanceQuery.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public OrderedDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
- @Override
- public boolean skipTo(int target) throws IOException {
- if (hasMoreSpans && (secondSpans.doc() < target)){
- if (!secondSpans.skipTo(target)){
- candidateList.clear();
- return false;
- }
- }
-
- setCandidateList();
- matchPayload.clear();
- isStartEnumeration=false;
- return advance();
- }
+ minDistance = query.getMinDistance();
+ maxDistance = query.getMaxDistance();
+
+ hasMoreFirstSpans = firstSpans.next();
+
+ candidateList = new ArrayList<>();
+ candidateListIndex = -1;
+ candidateListDocNum = firstSpans.doc();
+ }
+
+ /**
+ * Finds a span match in the candidate list.
+ * */
+ @Override
+ protected boolean advance() throws IOException {
+ while (hasMoreSpans && candidateListIndex < candidateList.size()) {
+ // Check candidates
+ for (candidateListIndex++; candidateListIndex < candidateList
+ .size(); candidateListIndex++) {
+ if (findMatch())
+ return true;
+ }
+
+ do { // Forward secondspan
+ hasMoreSpans = secondSpans.next();
+ setCandidateList();
+ } while (hasMoreSpans && !isSecondSpanValid());
+ }
+ return false;
+ }
+
+ /**
+ * Determines if the current second span is valid (i.e. within an element).
+ * It is always valid in TokenDistanceSpan, but it can be invalid in the
+ * ElementDistanceSpan, namely when it is not within a particular element (a
+ * sentence or a paragraph depends on the element distance unit).
+ *
+ * @return <code>true</code> of the current second span is valid,
+ * <code>false</code> otherwise.
+ * @throws IOException
+ */
+ protected abstract boolean isSecondSpanValid() throws IOException;
+
+ /**
+ * Stores/collects the states of all possible firstspans as candidate spans
+ * for the current secondspan. The candidate spans must be within the
+ * maximum distance from the current secondspan.
+ *
+ * @throws IOException
+ */
+ protected abstract void setCandidateList() throws IOException;
+
+ /**
+ * Defines the conditions for a match and tells if a match is found.
+ *
+ * @return <code>true</code> if a match is found, <code>false</code>
+ * otherwise.
+ * @throws IOException
+ */
+ protected abstract boolean findMatch() throws IOException;
+
+ /**
+ * Defines the properties of a span match. The distance between the first
+ * and the second spans is zero, when there is an intersection between them
+ * in {@link TokenDistanceSpans}, or they occur in the same element in
+ * {@link ElementDistanceSpans}.
+ *
+ * @param candidateSpan a match span
+ * @param isDistanceZero <code>true</code> if the distance between the first
+ * and the second spans is zero, <code>false</code> otherwise.
+ * @throws IOException
+ */
+ protected void setMatchProperties(CandidateSpan candidateSpan,
+ boolean isDistanceZero) throws IOException {
+
+ setMatchFirstSpan(candidateSpan);
+ setMatchSecondSpan(new CandidateSpan(secondSpans));
+
+ if (isDistanceZero) {
+ matchStartPosition = Math.min(candidateSpan.getStart(),
+ secondSpans.start());
+ matchEndPosition = Math.max(candidateSpan.getEnd(),
+ secondSpans.end());
+ } else {
+ matchStartPosition = candidateSpan.getStart();
+ matchEndPosition = secondSpans.end();
+ }
+
+ this.matchDocNumber = secondSpans.doc();
+ if (collectPayloads) {
+ if (candidateSpan.getPayloads() != null) {
+ matchPayload.addAll(candidateSpan.getPayloads());
+ }
+ if (secondSpans.isPayloadAvailable()) {
+ matchPayload.addAll(secondSpans.getPayload());
+ }
+ }
+ }
+
+ @Override
+ public boolean skipTo(int target) throws IOException {
+ if (hasMoreSpans && (secondSpans.doc() < target)) {
+ if (!secondSpans.skipTo(target)) {
+ candidateList.clear();
+ return false;
+ }
+ }
+
+ setCandidateList();
+ matchPayload.clear();
+ isStartEnumeration = false;
+ return advance();
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/TokenDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/TokenDistanceSpans.java
index f3c4907..150c61e 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/TokenDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/TokenDistanceSpans.java
@@ -12,95 +12,108 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Enumeration of token-based distance span matches.
- * Each match consists of two specified spans having an actual distance
- * in the range of the min and max distance parameters given in the query.
+/**
+ * Enumeration of token-based distance span matches consisting of two child
+ * spans having an actual distance in the range of the minimum and maximum
+ * distance parameters specified in the corresponding query.
*
- * @author margaretha
+ * @author margaretha
* */
-public class TokenDistanceSpans extends OrderedDistanceSpans{
+public class TokenDistanceSpans extends OrderedDistanceSpans {
- public TokenDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts) throws IOException {
- super(query, context, acceptDocs, termContexts);
- hasMoreSpans = hasMoreFirstSpans;
- }
-
- @Override
- protected void setCandidateList() throws IOException{
- if (candidateListDocNum == secondSpans.doc()){
- copyPossibleCandidates();
- addNewCandidates();
- candidateListIndex = -1;
- }
- else {
- candidateList.clear();
- if (hasMoreFirstSpans && ensureSameDoc(firstSpans,secondSpans)){
- candidateListDocNum = firstSpans.doc();
- addNewCandidates();
- candidateListIndex = -1;
- }
- }
- }
-
- /** Copy candidate spans which are still possible to create a match,
- * from the candidate list prepared for the previous second spans.
- * */
- private void copyPossibleCandidates(){
- List<CandidateSpan> temp = new ArrayList<>();
- for (CandidateSpan cs : candidateList){
- if (cs.getEnd()+maxDistance > secondSpans.start())
- temp.add(cs);
- }
- candidateList = temp;
- }
-
- /** Add new possible candidates for the current secondspan.
- * */
- private void addNewCandidates() throws IOException{
- while ( hasMoreFirstSpans &&
- firstSpans.doc() == candidateListDocNum &&
- firstSpans.start() < secondSpans.end()){
-
- if (firstSpans.end()+maxDistance > secondSpans.start())
- candidateList.add(new CandidateSpan(firstSpans));
-
- hasMoreFirstSpans = firstSpans.next();
- }
- }
-
- @Override
- protected boolean findMatch() throws IOException {
- CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
- if (minDistance == 0 &&
- // intersection
- candidateSpan.getStart() < secondSpans.end() &&
- secondSpans.start() < candidateSpan.getEnd()){
-
- setMatchProperties(candidateSpan, true);
- return true;
- }
-
- int actualDistance = secondSpans.start() - candidateSpan.getEnd() +1;
- if (candidateSpan.getStart() < secondSpans.start() &&
- minDistance <= actualDistance &&
- actualDistance <= maxDistance){
-
- setMatchProperties(candidateSpan, false);
- return true;
- }
- return false;
- }
-
- @Override
- public long cost() {
- CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
- return candidateSpan.getCost() + secondSpans.cost();
- }
+ /**
+ * Constructs a TokenDistanceSpans from the given query.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public TokenDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
+ hasMoreSpans = hasMoreFirstSpans;
+ }
- @Override
- protected boolean isSecondSpanValid() throws IOException {
- return true;
- }
+ @Override
+ protected void setCandidateList() throws IOException {
+ if (candidateListDocNum == secondSpans.doc()) {
+ copyPossibleCandidates();
+ addNewCandidates();
+ candidateListIndex = -1;
+ } else {
+ candidateList.clear();
+ if (hasMoreFirstSpans && ensureSameDoc(firstSpans, secondSpans)) {
+ candidateListDocNum = firstSpans.doc();
+ addNewCandidates();
+ candidateListIndex = -1;
+ }
+ }
+ }
+
+ /**
+ * Restructures the candidateList to contain only candidate (first) spans
+ * which are still possible to create a match, from the candidate list
+ * prepared for the previous second spans.
+ *
+ * */
+ private void copyPossibleCandidates() {
+ List<CandidateSpan> temp = new ArrayList<>();
+ for (CandidateSpan cs : candidateList) {
+ if (cs.getEnd() + maxDistance > secondSpans.start())
+ temp.add(cs);
+ }
+ candidateList = temp;
+ }
+
+ /**
+ * Add new possible firstspan candidates for the current secondspan.
+ * */
+ private void addNewCandidates() throws IOException {
+ while (hasMoreFirstSpans && firstSpans.doc() == candidateListDocNum
+ && firstSpans.start() < secondSpans.end()) {
+
+ if (firstSpans.end() + maxDistance > secondSpans.start())
+ candidateList.add(new CandidateSpan(firstSpans));
+
+ hasMoreFirstSpans = firstSpans.next();
+ }
+ }
+
+ @Override
+ protected boolean findMatch() throws IOException {
+ CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
+ if (minDistance == 0
+ &&
+ // intersection
+ candidateSpan.getStart() < secondSpans.end()
+ && secondSpans.start() < candidateSpan.getEnd()) {
+
+ setMatchProperties(candidateSpan, true);
+ return true;
+ }
+
+ int actualDistance = secondSpans.start() - candidateSpan.getEnd() + 1;
+ if (candidateSpan.getStart() < secondSpans.start()
+ && minDistance <= actualDistance
+ && actualDistance <= maxDistance) {
+
+ setMatchProperties(candidateSpan, false);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public long cost() {
+ CandidateSpan candidateSpan = candidateList.get(candidateListIndex);
+ return candidateSpan.getCost() + secondSpans.cost();
+ }
+
+ @Override
+ protected boolean isSecondSpanValid() throws IOException {
+ return true;
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedDistanceSpans.java
index 7934f34..8f68c8d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedDistanceSpans.java
@@ -15,227 +15,283 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Enumeration of span matches, whose two child spans have a specific range
- * of distance (within a min and a max distance) and can be in any order.
- *
- * @author margaretha
+/**
+ * Enumeration of span matches, whose two child spans have a specific range of
+ * distance (within a minimum and a maximum distance) and can occur in any
+ * order.
+ *
+ * @author margaretha
* */
-public abstract class UnorderedDistanceSpans extends DistanceSpans{
+public abstract class UnorderedDistanceSpans extends DistanceSpans {
- protected int minDistance, maxDistance;
- protected boolean hasMoreFirstSpans, hasMoreSecondSpans;
- protected List<CandidateSpan> firstSpanList, secondSpanList;
- protected List<CandidateSpan> matchList;
- private long matchCost;
- private int matchListSpanNum;
- protected int currentDocNum;
+ protected int minDistance, maxDistance;
+ protected boolean hasMoreFirstSpans, hasMoreSecondSpans;
+ protected List<CandidateSpan> firstSpanList, secondSpanList;
+ protected List<CandidateSpan> matchList;
+ private long matchCost;
+ private int matchListSpanNum;
+ protected int currentDocNum;
- // This advices the java compiler to ignore all loggings
- public static final boolean DEBUG = false;
+ /**
+ * Constructs an UnorderedDistanceSpans for the given
+ * {@link SpanDistanceQuery}.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public UnorderedDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
+ minDistance = query.getMinDistance();
+ maxDistance = query.getMaxDistance();
- public UnorderedDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts) throws IOException {
- super(query, context, acceptDocs, termContexts);
- minDistance = query.getMinDistance();
- maxDistance = query.getMaxDistance();
-
- firstSpanList = new ArrayList<CandidateSpan>();
- secondSpanList = new ArrayList<CandidateSpan>();
- matchList = new ArrayList<CandidateSpan>();
-
- hasMoreFirstSpans = firstSpans.next();
- hasMoreSecondSpans = secondSpans.next();
- hasMoreSpans = hasMoreFirstSpans && hasMoreSecondSpans;
- }
+ firstSpanList = new ArrayList<CandidateSpan>();
+ secondSpanList = new ArrayList<CandidateSpan>();
+ matchList = new ArrayList<CandidateSpan>();
- @Override
- protected boolean advance() throws IOException {
- while (hasMoreSpans || !matchList.isEmpty()){
- if (!matchList.isEmpty()){
- setMatchProperties();
- return true;
- }
- if (prepareLists()) setMatchList();
- }
- return false;
- }
-
- /** Add the next possible first and second spans. Both the spans must be in the
- * same document. In UnorderedElementDistanceSpans, a span that is not in
- * an element, is not added to its candidate list. The element must also be in
- * the same document.
- *
- * @return true iff at least one of the candidate lists can be filled.
- * */
- protected abstract boolean prepareLists() throws IOException;
-
- /** Set the list of matches between the span having the smallest position, and
- * its candidates. Simply remove the span if it does not have any candidates.
- * */
- protected void setMatchList() throws IOException {
-
- hasMoreFirstSpans = setCandidateList(firstSpanList,firstSpans,
- hasMoreFirstSpans,secondSpanList);
- hasMoreSecondSpans = setCandidateList(secondSpanList,secondSpans,
- hasMoreSecondSpans,firstSpanList);
-// System.out.println("--------------------");
-// System.out.println("firstSpanList:");
-// for (CandidateSpan cs: firstSpanList) {
-// System.out.println(cs.getStart() +" "+ cs.getEnd());
-// }
-//
-// System.out.println("secondSpanList:");
-// for (CandidateSpan cs: secondSpanList) {
-// System.out.println(cs.getStart() +" "+ cs.getEnd());
-// }
-
- CandidateSpan currentFirstSpan, currentSecondSpan;
- if (!firstSpanList.isEmpty() && !secondSpanList.isEmpty()){
-
- currentFirstSpan = firstSpanList.get(0) ;
- currentSecondSpan = secondSpanList.get(0);
-
- if (currentFirstSpan.getEnd() < currentSecondSpan.getEnd() ||
- isLastCandidateSmaller(currentFirstSpan, currentSecondSpan)){
- if (DEBUG)
- log.trace("current target: "+firstSpanList.get(0).getStart() +" "+firstSpanList.get(0).getEnd());
-// System.out.println("candidates:");
-// for (CandidateSpan cs: secondSpanList) {
-// System.out.println(cs.getStart() +" "+ cs.getEnd());
-// }
-
- matchList = findMatches(currentFirstSpan, secondSpanList);
- setMatchFirstSpan(currentFirstSpan);
- matchListSpanNum = 2;
- updateList(firstSpanList);
- }
- else {
- if (DEBUG)
- log.trace("current target: "+secondSpanList.get(0).getStart() +" "+secondSpanList.get(0).getEnd());
-// System.out.println("candidates:");
-// for (CandidateSpan cs: firstSpanList) {
-// System.out.println(cs.getStart() +" "+ cs.getEnd());
-// }
-
- matchList = findMatches(currentSecondSpan, firstSpanList);
- setMatchSecondSpan(currentSecondSpan);
- matchListSpanNum = 1;
- updateList(secondSpanList);
- }
- }
- else if (firstSpanList.isEmpty()){
- if (DEBUG) {
- log.trace("current target: "+secondSpanList.get(0).getStart() +" "+secondSpanList.get(0).getEnd());
- log.trace("candidates: empty");
- };
- updateList(secondSpanList);
- }
- else{
- if (DEBUG) {
- log.trace("current target: "+firstSpanList.get(0).getStart() +" "+firstSpanList.get(0).getEnd());
- log.trace("candidates: empty");
- };
- updateList(firstSpanList);
- }
- }
-
- private boolean isLastCandidateSmaller(CandidateSpan currentFirstSpan, CandidateSpan
- currentSecondSpan){
- if (currentFirstSpan.getEnd() == currentSecondSpan.getEnd() ){
- int secondEnd = secondSpanList.get(secondSpanList.size()-1).getEnd();
- int firstEnd = firstSpanList.get(firstSpanList.size()-1).getEnd();
- return (secondEnd < firstEnd ? true : false);
- }
-
- return false;
- }
-
- protected abstract void updateList(List<CandidateSpan> candidateList);
-
- /** Set the candidate list for the first element in the target list.
- * @return true iff the spans enumeration still has a next element
- * to be a candidate
- */
- protected abstract boolean setCandidateList(List<CandidateSpan>
- candidateList, Spans candidate, boolean hasMoreCandidates,
- List<CandidateSpan> targetList) throws IOException;
-
- /** Search all matches between the target span and its candidates in the candidate
- * list.
- * @return the matches in a list
- * */
- protected abstract List<CandidateSpan> findMatches(CandidateSpan target,
- List<CandidateSpan> candidateList);
-
- /** Compute match properties and create a candidate span match
- * to be added to the match list.
- * @return a candidate span match
- * */
- protected CandidateSpan createMatchCandidate(CandidateSpan target,
- CandidateSpan cs, boolean isDistanceZero) {
-
- int start = Math.min(target.getStart(), cs.getStart());
- int end = Math.max(target.getEnd(),cs.getEnd());
- int doc = target.getDoc();
- long cost = target.getCost() + cs.getCost();
-
- Collection<byte[]> payloads = new LinkedList<byte[]>();
- if (collectPayloads) {
- if (target.getPayloads() != null){
- payloads.addAll(target.getPayloads());
- }
- if (cs.getPayloads() != null){
- payloads.addAll(cs.getPayloads());
- }
- }
-
- CandidateSpan match = new CandidateSpan(start,end,doc,cost,payloads);
- match.setChildSpan(cs);
- return match;
- }
+ hasMoreFirstSpans = firstSpans.next();
+ hasMoreSecondSpans = secondSpans.next();
+ hasMoreSpans = hasMoreFirstSpans && hasMoreSecondSpans;
+ }
- /** Assign the first candidate span in the match list as the current span match.
- * */
- private void setMatchProperties() {
- CandidateSpan cs = matchList.get(0);
- matchDocNumber = cs.getDoc();
- matchStartPosition = cs.getStart();
- matchEndPosition = cs.getEnd();
- matchCost = cs.getCost();
- matchPayload.addAll(cs.getPayloads());
- matchList.remove(0);
-
- if (matchListSpanNum == 1)
- setMatchFirstSpan(cs.getChildSpan());
- else setMatchSecondSpan(cs.getChildSpan());
+ @Override
+ protected boolean advance() throws IOException {
+ while (hasMoreSpans || !matchList.isEmpty()) {
+ if (!matchList.isEmpty()) {
+ setMatchProperties();
+ return true;
+ }
+ if (prepareLists())
+ setMatchList();
+ }
+ return false;
+ }
- if (DEBUG) {
- log.trace("Match doc#={} start={} end={}",matchDocNumber,matchStartPosition,matchEndPosition);
- log.trace("firstspan "+getMatchFirstSpan().getStart()+" "+ getMatchFirstSpan().getEnd());
- log.trace("secondspan "+getMatchSecondSpan().getStart()+" "+ getMatchSecondSpan().getEnd());
- };
- }
+ /**
+ * Updates the firstSpanList and secondSpanList by adding the next possible
+ * first and second spans. Both the spans must be in the same document. In
+ * UnorderedElementDistanceSpans, a span that is not in an element (distance
+ * unit), is not added to its candidate list. The element must also be in
+ * the same document.
+ *
+ * @return <code>true</code> if at least one of the candidate lists can be
+ * filled, <code>false</code> otherwise.
+ * @throws IOException
+ */
+ protected abstract boolean prepareLists() throws IOException;
- @Override
- public boolean skipTo(int target) throws IOException {
- if (hasMoreSpans && (secondSpans.doc() < target)){
- if (!secondSpans.skipTo(target)){
- hasMoreSpans = false;
- return false;
- }
- }
-
- firstSpanList.clear();
- secondSpanList.clear();
- matchPayload.clear();
- isStartEnumeration=false;
- return advance();
- }
+ /**
+ * Sets the list of matches for the span having the smallest position (i.e.
+ * between the first and the second spans), and its candidates (i.e. its
+ * counterparts). The candidates also must have smaller positions. Simply
+ * remove the span if it does not have any candidates.
+ *
+ * @throws IOException
+ */
+ protected void setMatchList() throws IOException {
- @Override
- public long cost() {
- return matchCost;
- }
+ hasMoreFirstSpans = setCandidateList(firstSpanList, firstSpans,
+ hasMoreFirstSpans, secondSpanList);
+ hasMoreSecondSpans = setCandidateList(secondSpanList, secondSpans,
+ hasMoreSecondSpans, firstSpanList);
+ // System.out.println("--------------------");
+ // System.out.println("firstSpanList:");
+ // for (CandidateSpan cs: firstSpanList) {
+ // System.out.println(cs.getStart() +" "+ cs.getEnd());
+ // }
+ //
+ // System.out.println("secondSpanList:");
+ // for (CandidateSpan cs: secondSpanList) {
+ // System.out.println(cs.getStart() +" "+ cs.getEnd());
+ // }
+
+ CandidateSpan currentFirstSpan, currentSecondSpan;
+ if (!firstSpanList.isEmpty() && !secondSpanList.isEmpty()) {
+
+ currentFirstSpan = firstSpanList.get(0);
+ currentSecondSpan = secondSpanList.get(0);
+
+ if (currentFirstSpan.getEnd() < currentSecondSpan.getEnd()
+ || isLastCandidateSmaller(currentFirstSpan,
+ currentSecondSpan)) {
+ // log.trace("current target: "
+ // + firstSpanList.get(0).getStart() + " "
+ // + firstSpanList.get(0).getEnd());
+ // System.out.println("candidates:");
+ // for (CandidateSpan cs: secondSpanList) {
+ // System.out.println(cs.getStart() +" "+ cs.getEnd());
+ // }
+
+ matchList = findMatches(currentFirstSpan, secondSpanList);
+ setMatchFirstSpan(currentFirstSpan);
+ matchListSpanNum = 2;
+ updateList(firstSpanList);
+ } else {
+ // log.trace("current target: "
+ // + secondSpanList.get(0).getStart() + " "
+ // + secondSpanList.get(0).getEnd());
+ // System.out.println("candidates:");
+ // for (CandidateSpan cs: firstSpanList) {
+ // System.out.println(cs.getStart() +" "+ cs.getEnd());
+ // }
+
+ matchList = findMatches(currentSecondSpan, firstSpanList);
+ setMatchSecondSpan(currentSecondSpan);
+ matchListSpanNum = 1;
+ updateList(secondSpanList);
+ }
+ } else if (firstSpanList.isEmpty()) {
+ // log.trace("current target: " + secondSpanList.get(0).getStart()
+ // + " " + secondSpanList.get(0).getEnd());
+ // log.trace("candidates: empty");
+ updateList(secondSpanList);
+ } else {
+ // log.trace("current target: " + firstSpanList.get(0).getStart()
+ // + " " + firstSpanList.get(0).getEnd());
+ // log.trace("candidates: empty");
+ updateList(firstSpanList);
+ }
+ }
+
+ /**
+ * Tells if the last candidate from the secondSpanList has a smaller end
+ * position than the end position of the the last candidate from the
+ * firstSpanList.
+ *
+ * @param currentFirstSpan the current firstspan
+ * @param currentSecondSpan the current secondspan
+ * @return <code>true</code> if the end position of the last candidate from
+ * the secondSpanList is smaller than that from the firstSpanList,
+ * <code>false</code> otherwise.
+ */
+ private boolean isLastCandidateSmaller(CandidateSpan currentFirstSpan,
+ CandidateSpan currentSecondSpan) {
+ if (currentFirstSpan.getEnd() == currentSecondSpan.getEnd()) {
+ int secondEnd = secondSpanList.get(secondSpanList.size() - 1)
+ .getEnd();
+ int firstEnd = firstSpanList.get(firstSpanList.size() - 1).getEnd();
+ return (secondEnd < firstEnd ? true : false);
+ }
+
+ return false;
+ }
+
+ /**
+ * Performs an update based on the given candidateList. In
+ * {@link UnorderedTokenDistanceSpans}, the first candidate in the
+ * candidateList is simply removed. In {@link UnorderedElementDistanceSpans}
+ * , the elementList is also updated.
+ *
+ * @param candidateList a candidateList
+ */
+ protected abstract void updateList(List<CandidateSpan> candidateList);
+
+ /**
+ * Sets the candidate list for the first element in the target list and
+ * tells if the the specified spans has finished or not.
+ *
+ * @param candidateList a list of candidate spans
+ * @param candidate a Spans
+ * @param hasMoreCandidates a boolean
+ * @param targetList a list of target spans
+ * @return <code>true</code> if the span enumeration still has a next
+ * element to be a candidate, <code>false</code> otherwise.
+ * @throws IOException
+ */
+ protected abstract boolean setCandidateList(
+ List<CandidateSpan> candidateList, Spans candidate,
+ boolean hasMoreCandidates, List<CandidateSpan> targetList)
+ throws IOException;
+
+ /**
+ * Finds all matches between the target span and its candidates in the
+ * candidate list.
+ *
+ * @param target a target span
+ * @param candidateList a candidate list
+ * @return the matches in a list
+ */
+ protected abstract List<CandidateSpan> findMatches(CandidateSpan target,
+ List<CandidateSpan> candidateList);
+
+ /**
+ * Computes match properties and creates a candidate span match to be added
+ * to the match list.
+ *
+ * @return a candidate span match
+ * */
+ protected CandidateSpan createMatchCandidate(CandidateSpan target,
+ CandidateSpan cs, boolean isDistanceZero) {
+
+ int start = Math.min(target.getStart(), cs.getStart());
+ int end = Math.max(target.getEnd(), cs.getEnd());
+ int doc = target.getDoc();
+ long cost = target.getCost() + cs.getCost();
+
+ Collection<byte[]> payloads = new LinkedList<byte[]>();
+ if (collectPayloads) {
+ if (target.getPayloads() != null) {
+ payloads.addAll(target.getPayloads());
+ }
+ if (cs.getPayloads() != null) {
+ payloads.addAll(cs.getPayloads());
+ }
+ }
+
+ CandidateSpan match = new CandidateSpan(start, end, doc, cost, payloads);
+ match.setChildSpan(cs);
+ return match;
+ }
+
+ /**
+ * Assigns the first candidate span in the match list as the current span
+ * match, and removes it from the matchList.
+ * */
+ private void setMatchProperties() {
+ CandidateSpan cs = matchList.get(0);
+ matchDocNumber = cs.getDoc();
+ matchStartPosition = cs.getStart();
+ matchEndPosition = cs.getEnd();
+ matchCost = cs.getCost();
+ matchPayload.addAll(cs.getPayloads());
+ matchList.remove(0);
+
+ if (matchListSpanNum == 1)
+ setMatchFirstSpan(cs.getChildSpan());
+ else
+ setMatchSecondSpan(cs.getChildSpan());
+
+ // log.trace("Match doc#={} start={} end={}", matchDocNumber,
+ // matchStartPosition, matchEndPosition);
+ // log.trace("firstspan " + getMatchFirstSpan().getStart() + " "
+ // + getMatchFirstSpan().getEnd());
+ // log.trace("secondspan " + getMatchSecondSpan().getStart() + " "
+ // + getMatchSecondSpan().getEnd());
+ }
+
+ @Override
+ public boolean skipTo(int target) throws IOException {
+ if (hasMoreSpans && (secondSpans.doc() < target)) {
+ if (!secondSpans.skipTo(target)) {
+ hasMoreSpans = false;
+ return false;
+ }
+ }
+
+ firstSpanList.clear();
+ secondSpanList.clear();
+ matchPayload.clear();
+ isStartEnumeration = false;
+ return advance();
+ }
+
+ @Override
+ public long cost() {
+ return matchCost;
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedElementDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedElementDistanceSpans.java
index a0c4474..102b5c9 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedElementDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedElementDistanceSpans.java
@@ -14,213 +14,248 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Enumeration of span matches, whose two child spans have a specific range
- * of distance (within a min and a max distance) and can be in any order.
- * The unit distance is an element position, where element can be a sentence
- * or a paragraph.
+/**
+ * Enumeration of span matches, whose two child spans have a specific range of
+ * distance (within a min and a max distance) and can be in any order. The unit
+ * distance is an element, which can be a sentence or a paragraph for instance.
+ * The distance is the difference between the positions of elements containing
+ * the spans.
*
* @author margaretha
* */
-public class UnorderedElementDistanceSpans extends UnorderedDistanceSpans{
-
- private Spans elements;
- private boolean hasMoreElements;
- private int elementPosition;
-
- // contains all previous elements whose position is greater than the last
- // target span
- private List<CandidateSpan> elementList;
-
- public UnorderedElementDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts) throws IOException {
- super(query, context, acceptDocs, termContexts);
- elements = query.getElementQuery().
- getSpans(context, acceptDocs, termContexts);
- hasMoreElements = elements.next();
- elementPosition=0;
- elementList = new ArrayList<CandidateSpan>();
- }
-
- @Override
- protected boolean prepareLists() throws IOException {
-
- if (firstSpanList.isEmpty() && secondSpanList.isEmpty()){
- if (hasMoreFirstSpans && hasMoreSecondSpans && hasMoreElements &&
- findSameDoc(firstSpans, secondSpans, elements)){
-
- if (currentDocNum != firstSpans.doc()){
- currentDocNum = firstSpans.doc();
- elementList.clear();
- }
-
- hasMoreFirstSpans = addSpan(firstSpans,firstSpanList,hasMoreFirstSpans);
- hasMoreSecondSpans = addSpan(secondSpans, secondSpanList, hasMoreSecondSpans);
- }
- else {
- hasMoreSpans = false;
- return false;
- }
- }
- else if (firstSpanList.isEmpty() && hasMoreFirstSpans &&
- firstSpans.doc() == currentDocNum){
- hasMoreFirstSpans = addSpan(firstSpans,firstSpanList,hasMoreFirstSpans);
- }
- else if (secondSpanList.isEmpty() && hasMoreSecondSpans &&
- secondSpans.doc() == currentDocNum){
- hasMoreSecondSpans = addSpan(secondSpans, secondSpanList, hasMoreSecondSpans);
- }
-
- return true;
- }
-
- private boolean addSpan(Spans span, List<CandidateSpan> list, boolean hasMoreSpan)
- throws IOException {
- int position;
- while (hasMoreSpan && span.doc() == currentDocNum){
- position = findElementPosition(span);
- if (position != -1){
- list.add(new CandidateSpan(span,position));
- hasMoreSpan = span.next();
- return hasMoreSpan;
- }
- hasMoreSpan = span.next();
- }
- return hasMoreSpan;
- }
-
-
- /** Find the element position of the span in the element list or by advancing
- * the element spans until encountering the span.
- *
- * @return the element position
- * */
- private int findElementPosition(Spans span) throws IOException {
- // Check in the element list
- if (!elementList.isEmpty() &&
- span.end() <= elementList.get(elementList.size()-1).getEnd()){
-
- for (CandidateSpan e : elementList)
- if (e.getEnd() >= span.end() && e.getStart() <= span.start()){
- return e.getPosition();
- }
- return -1; // The span is not in an element.
- }
-
- return ( advanceElementTo(span) ? elementPosition : -1 );
- }
-
- /** Advance the element spans until encountering the given span.
- *
- * @return true iff such an element is found, false if the span is not in
- * an element.
- * */
- private boolean advanceElementTo(Spans span) throws IOException {
- while (hasMoreElements &&
- elements.doc() == currentDocNum &&
- elements.start() < span.end()){
-
- if (span.start() >= elements.start() &&
- span.end() <= elements.end()){
- return true;
- }
- elementList.add(new CandidateSpan(elements,elementPosition));
- hasMoreElements = elements.next();
- elementPosition++;
- }
-
- return false; // invalid
- }
+public class UnorderedElementDistanceSpans extends UnorderedDistanceSpans {
- @Override
- protected boolean setCandidateList(List<CandidateSpan>
- candidateList, Spans candidate, boolean hasMoreCandidates,
- List<CandidateSpan> targetList) throws IOException {
-
- if (!targetList.isEmpty()){
- CandidateSpan cs;
- CandidateSpan target = targetList.get(0);
- int position;
- while (hasMoreCandidates && candidate.doc() == target.getDoc()){
- position = findElementPosition(candidate);
- if (position != -1){
- cs = new CandidateSpan(candidate,position);
-
- if (isWithinMaxDistance(target, cs)){
- candidateList.add(cs);
- }
- else break;
- }
- hasMoreCandidates = candidate.next();
- }
- }
- return hasMoreCandidates;
- }
-
- /** Check if the target and candidate spans are not too far from each other.
- *
- * @return true iff the target and candidate spans are within the maximum
- * distance
- * */
- protected boolean isWithinMaxDistance(CandidateSpan target, CandidateSpan candidate) {
- int candidatePos = candidate.getPosition();
- int targetPos = target.getPosition();
-
- // left candidate
- if (candidatePos < targetPos &&
- candidatePos + maxDistance < targetPos){
- return false;
- }
- // right candidate
- if (candidatePos > targetPos &&
- targetPos + maxDistance < candidatePos){
- return false;
- }
- return true;
- }
-
- @Override
- protected List<CandidateSpan> findMatches(CandidateSpan target, List<CandidateSpan>
- candidateList) {
-
- List<CandidateSpan> matches = new ArrayList<>();
-
- int actualDistance;
- int targetPos = target.getPosition();
-
- for (CandidateSpan cs : candidateList){
- actualDistance = Math.abs( targetPos - cs.getPosition() );
-
- if (minDistance == 0 && actualDistance == 0){
- matches.add(createMatchCandidate(target,cs,true));
- continue;
- }
-
- if (minDistance <= actualDistance && actualDistance <= maxDistance)
- matches.add(createMatchCandidate(target, cs, false));
- }
- return matches;
- }
+ private Spans elements;
+ private boolean hasMoreElements;
+ private int elementPosition;
- @Override
- protected void updateList(List<CandidateSpan> candidateList) {
- updateElementList(candidateList.get(0).getPosition());
- candidateList.remove(0);
- }
-
- /** Reduce the number of elements kept in the element list by removing the element
- * whose position is smaller than or identical to the position of the last target
- * span.
- * */
- private void updateElementList(int position){
- Iterator<CandidateSpan> i = elementList.iterator();
- CandidateSpan e;
- while(i.hasNext()){
- e = i.next();
- if (e.getPosition() <= position) {
- i.remove();
- }
- break;
- }
- }
+ // contains all previous elements whose position is greater than the last
+ // target span
+ private List<CandidateSpan> elementList;
+
+ /**
+ * Constructs an UnorderedElementDistanceSpans for the given
+ * {@link SpanDistanceQuery}.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public UnorderedElementDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
+ elements = query.getElementQuery().getSpans(context, acceptDocs,
+ termContexts);
+ hasMoreElements = elements.next();
+ elementPosition = 0;
+ elementList = new ArrayList<CandidateSpan>();
+ }
+
+ @Override
+ protected boolean prepareLists() throws IOException {
+
+ if (firstSpanList.isEmpty() && secondSpanList.isEmpty()) {
+ if (hasMoreFirstSpans && hasMoreSecondSpans && hasMoreElements
+ && findSameDoc(firstSpans, secondSpans, elements)) {
+
+ if (currentDocNum != firstSpans.doc()) {
+ currentDocNum = firstSpans.doc();
+ elementList.clear();
+ }
+
+ hasMoreFirstSpans = addSpan(firstSpans, firstSpanList,
+ hasMoreFirstSpans);
+ hasMoreSecondSpans = addSpan(secondSpans, secondSpanList,
+ hasMoreSecondSpans);
+ } else {
+ hasMoreSpans = false;
+ return false;
+ }
+ } else if (firstSpanList.isEmpty() && hasMoreFirstSpans
+ && firstSpans.doc() == currentDocNum) {
+ hasMoreFirstSpans = addSpan(firstSpans, firstSpanList,
+ hasMoreFirstSpans);
+ } else if (secondSpanList.isEmpty() && hasMoreSecondSpans
+ && secondSpans.doc() == currentDocNum) {
+ hasMoreSecondSpans = addSpan(secondSpans, secondSpanList,
+ hasMoreSecondSpans);
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds all the spans occurring in the current document, as CandidateSpans
+ * to the specified candidate list, and tells if the enumeration of the
+ * spans has finished, or not.
+ *
+ * @param span a Span
+ * @param list a candidateList
+ * @param hasMoreSpan a boolean describing if the span enumeration has
+ * finished or not.
+ * @return <code>true</code> if the the span enumeration has finished,
+ * <code>false</code> otherwise.
+ * @throws IOException
+ */
+ private boolean addSpan(Spans span, List<CandidateSpan> list,
+ boolean hasMoreSpan) throws IOException {
+ int position;
+ while (hasMoreSpan && span.doc() == currentDocNum) {
+ position = findElementPosition(span);
+ if (position != -1) {
+ list.add(new CandidateSpan(span, position));
+ hasMoreSpan = span.next();
+ return hasMoreSpan;
+ }
+ hasMoreSpan = span.next();
+ }
+ return hasMoreSpan;
+ }
+
+ /**
+ * Finds the element position of the specified span in the element list or
+ * by advancing the element spans until encountering the span.
+ *
+ * @param span a Span
+ * @return the element position
+ * @throws IOException
+ */
+ private int findElementPosition(Spans span) throws IOException {
+ // Check in the element list
+ if (!elementList.isEmpty()
+ && span.end() <= elementList.get(elementList.size() - 1)
+ .getEnd()) {
+
+ for (CandidateSpan e : elementList)
+ if (e.getEnd() >= span.end() && e.getStart() <= span.start()) {
+ return e.getPosition();
+ }
+ return -1; // The span is not in an element.
+ }
+
+ return (advanceElementTo(span) ? elementPosition : -1);
+ }
+
+ /**
+ * Advances the element spans until encountering the given span.
+ *
+ * @param span
+ * @return <code>true</code> if such an element is found, <code>false</code>
+ * if the span is not in an element.
+ * @throws IOException
+ */
+ private boolean advanceElementTo(Spans span) throws IOException {
+ while (hasMoreElements && elements.doc() == currentDocNum
+ && elements.start() < span.end()) {
+
+ if (span.start() >= elements.start()
+ && span.end() <= elements.end()) {
+ return true;
+ }
+ elementList.add(new CandidateSpan(elements, elementPosition));
+ hasMoreElements = elements.next();
+ elementPosition++;
+ }
+
+ return false; // invalid
+ }
+
+ @Override
+ protected boolean setCandidateList(List<CandidateSpan> candidateList,
+ Spans candidate, boolean hasMoreCandidates,
+ List<CandidateSpan> targetList) throws IOException {
+
+ if (!targetList.isEmpty()) {
+ CandidateSpan cs;
+ CandidateSpan target = targetList.get(0);
+ int position;
+ while (hasMoreCandidates && candidate.doc() == target.getDoc()) {
+ position = findElementPosition(candidate);
+ if (position != -1) {
+ cs = new CandidateSpan(candidate, position);
+
+ if (isWithinMaxDistance(target, cs)) {
+ candidateList.add(cs);
+ } else
+ break;
+ }
+ hasMoreCandidates = candidate.next();
+ }
+ }
+ return hasMoreCandidates;
+ }
+
+ /**
+ * Tells if the target and candidate spans are not too far from each other
+ * (within the maximum distance).
+ *
+ * @return <code>true</code> if the target and candidate spans are within
+ * the maximum distance, <code>false</code> otherwise.
+ * */
+ protected boolean isWithinMaxDistance(CandidateSpan target,
+ CandidateSpan candidate) {
+ int candidatePos = candidate.getPosition();
+ int targetPos = target.getPosition();
+
+ // left candidate
+ if (candidatePos < targetPos && candidatePos + maxDistance < targetPos) {
+ return false;
+ }
+ // right candidate
+ if (candidatePos > targetPos && targetPos + maxDistance < candidatePos) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected List<CandidateSpan> findMatches(CandidateSpan target,
+ List<CandidateSpan> candidateList) {
+
+ List<CandidateSpan> matches = new ArrayList<>();
+
+ int actualDistance;
+ int targetPos = target.getPosition();
+
+ for (CandidateSpan cs : candidateList) {
+ actualDistance = Math.abs(targetPos - cs.getPosition());
+
+ if (minDistance == 0 && actualDistance == 0) {
+ matches.add(createMatchCandidate(target, cs, true));
+ continue;
+ }
+
+ if (minDistance <= actualDistance && actualDistance <= maxDistance)
+ matches.add(createMatchCandidate(target, cs, false));
+ }
+ return matches;
+ }
+
+ @Override
+ protected void updateList(List<CandidateSpan> candidateList) {
+ updateElementList(candidateList.get(0).getPosition());
+ candidateList.remove(0);
+ }
+
+ /**
+ * Reduces the number of elements kept in the element list by removing the
+ * elements whose position is smaller than or identical to the position of
+ * the last target span.
+ *
+ * @param position the last target span position
+ */
+ private void updateElementList(int position) {
+ Iterator<CandidateSpan> i = elementList.iterator();
+ CandidateSpan e;
+ while (i.hasNext()) {
+ e = i.next();
+ if (e.getPosition() <= position) {
+ i.remove();
+ }
+ break;
+ }
+ }
}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedTokenDistanceSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedTokenDistanceSpans.java
index 5f1abd9..bc9f0e5 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedTokenDistanceSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/UnorderedTokenDistanceSpans.java
@@ -13,114 +13,129 @@
import de.ids_mannheim.korap.query.SpanDistanceQuery;
-/** Enumeration of span matches, whose two child spans have a specific range
- * of distance (within a min and a max distance) and can be in any order.
- * The unit distance is a token position.
+/**
+ * Enumeration of span matches, whose two child spans have a specific range of
+ * distance (within a min and a max distance) and can be in any order. The unit
+ * distance is a token position.
*
* @author margaretha
* */
-public class UnorderedTokenDistanceSpans extends UnorderedDistanceSpans{
+public class UnorderedTokenDistanceSpans extends UnorderedDistanceSpans {
- public UnorderedTokenDistanceSpans(SpanDistanceQuery query,
- AtomicReaderContext context, Bits acceptDocs,
- Map<Term, TermContext> termContexts) throws IOException {
- super(query, context, acceptDocs, termContexts);
- }
-
- @Override
- protected boolean prepareLists() throws IOException {
-
- if (firstSpanList.isEmpty() && secondSpanList.isEmpty()){
- if (hasMoreFirstSpans && hasMoreSecondSpans &&
- ensureSameDoc(firstSpans, secondSpans)){
- firstSpanList.add(new CandidateSpan(firstSpans));
- secondSpanList.add(new CandidateSpan(secondSpans));
- currentDocNum = firstSpans.doc();
- hasMoreFirstSpans = firstSpans.next();
- hasMoreSecondSpans = secondSpans.next();
- }
- else {
- hasMoreSpans = false;
- return false;
- }
- }
- else if (firstSpanList.isEmpty() && hasMoreFirstSpans &&
- firstSpans.doc() == currentDocNum){
- firstSpanList.add(new CandidateSpan(firstSpans));
- hasMoreFirstSpans = firstSpans.next();
- }
- else if (secondSpanList.isEmpty() && hasMoreSecondSpans &&
- secondSpans.doc() == currentDocNum){
- secondSpanList.add(new CandidateSpan(secondSpans));
- hasMoreSecondSpans = secondSpans.next();
- }
- return true;
- }
-
- @Override
- protected boolean setCandidateList(List<CandidateSpan>
- candidateList, Spans candidate, boolean hasMoreCandidates,
- List<CandidateSpan> targetList) throws IOException {
-
- if (!targetList.isEmpty()){
- CandidateSpan target = targetList.get(0);
- while (hasMoreCandidates && candidate.doc() == target.getDoc()
- && isWithinMaxDistance(target,candidate)){
- candidateList.add(new CandidateSpan(candidate));
- hasMoreCandidates = candidate.next();
- }
- }
- return hasMoreCandidates;
- }
-
- /** Check if the target and candidate spans are not too far from each other.
- * @return true iff the target and candidate spans are within the maximum
- * distance
- * */
- protected boolean isWithinMaxDistance(CandidateSpan target, Spans candidate) {
- // left candidate
- if (candidate.end() < target.getStart() &&
- candidate.end() + maxDistance <= target.getStart()){
- return false;
- }
- // right candidate
- if (candidate.start() > target.getEnd() &&
- target.getEnd() + maxDistance <= candidate.start()){
- return false;
- }
- return true;
- }
-
- @Override
- protected List<CandidateSpan> findMatches(CandidateSpan target, List<CandidateSpan>
- candidateList) {
-
- List<CandidateSpan> matches = new ArrayList<>();
- int actualDistance;
- for (CandidateSpan cs : candidateList){
- if (minDistance == 0 &&
- //intersection
- target.getStart() < cs.getEnd() &&
- cs.getStart() < target.getEnd()){
- matches.add(createMatchCandidate(target,cs,true));
- continue;
- }
-
- // left candidate
- if (cs.getEnd() < target.getStart())
- actualDistance = target.getStart() - cs.getEnd() +1;
- else // right candidate
- actualDistance = cs.getStart() - target.getEnd() +1;
-
- if (minDistance <= actualDistance && actualDistance <= maxDistance)
- matches.add(createMatchCandidate(target, cs, false));
- }
- return matches;
- }
+ /**
+ * Constructs an UnorderedTokenDistanceSpans for the given
+ * SpanDistanceQuery.
+ *
+ * @param query a SpanDistanceQuery
+ * @param context
+ * @param acceptDocs
+ * @param termContexts
+ * @throws IOException
+ */
+ public UnorderedTokenDistanceSpans(SpanDistanceQuery query,
+ AtomicReaderContext context, Bits acceptDocs,
+ Map<Term, TermContext> termContexts) throws IOException {
+ super(query, context, acceptDocs, termContexts);
+ }
- @Override
- protected void updateList(List<CandidateSpan> candidateList) {
- candidateList.remove(0);
- }
+ @Override
+ protected boolean prepareLists() throws IOException {
+
+ if (firstSpanList.isEmpty() && secondSpanList.isEmpty()) {
+ if (hasMoreFirstSpans && hasMoreSecondSpans
+ && ensureSameDoc(firstSpans, secondSpans)) {
+ firstSpanList.add(new CandidateSpan(firstSpans));
+ secondSpanList.add(new CandidateSpan(secondSpans));
+ currentDocNum = firstSpans.doc();
+ hasMoreFirstSpans = firstSpans.next();
+ hasMoreSecondSpans = secondSpans.next();
+ } else {
+ hasMoreSpans = false;
+ return false;
+ }
+ } else if (firstSpanList.isEmpty() && hasMoreFirstSpans
+ && firstSpans.doc() == currentDocNum) {
+ firstSpanList.add(new CandidateSpan(firstSpans));
+ hasMoreFirstSpans = firstSpans.next();
+ } else if (secondSpanList.isEmpty() && hasMoreSecondSpans
+ && secondSpans.doc() == currentDocNum) {
+ secondSpanList.add(new CandidateSpan(secondSpans));
+ hasMoreSecondSpans = secondSpans.next();
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean setCandidateList(List<CandidateSpan> candidateList,
+ Spans candidate, boolean hasMoreCandidates,
+ List<CandidateSpan> targetList) throws IOException {
+
+ if (!targetList.isEmpty()) {
+ CandidateSpan target = targetList.get(0);
+ while (hasMoreCandidates && candidate.doc() == target.getDoc()
+ && isWithinMaxDistance(target, candidate)) {
+ candidateList.add(new CandidateSpan(candidate));
+ hasMoreCandidates = candidate.next();
+ }
+ }
+ return hasMoreCandidates;
+ }
+
+ /**
+ * Tells if the target and candidate spans are not too far from each other
+ * (within the maximum distance).
+ *
+ * @param target a target span
+ * @param candidate a candidate span
+ * @return <code>true</code> if the target and candidate spans are within
+ * the maximum distance, <code>false</code> otherwise.
+ */
+ protected boolean isWithinMaxDistance(CandidateSpan target, Spans candidate) {
+ // left candidate
+ if (candidate.end() < target.getStart()
+ && candidate.end() + maxDistance <= target.getStart()) {
+ return false;
+ }
+ // right candidate
+ if (candidate.start() > target.getEnd()
+ && target.getEnd() + maxDistance <= candidate.start()) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected List<CandidateSpan> findMatches(CandidateSpan target,
+ List<CandidateSpan> candidateList) {
+
+ List<CandidateSpan> matches = new ArrayList<>();
+ int actualDistance;
+ for (CandidateSpan cs : candidateList) {
+ if (minDistance == 0
+ &&
+ // intersection
+ target.getStart() < cs.getEnd()
+ && cs.getStart() < target.getEnd()) {
+ matches.add(createMatchCandidate(target, cs, true));
+ continue;
+ }
+
+ // left candidate
+ if (cs.getEnd() < target.getStart())
+ actualDistance = target.getStart() - cs.getEnd() + 1;
+ else
+ // right candidate
+ actualDistance = cs.getStart() - target.getEnd() + 1;
+
+ if (minDistance <= actualDistance && actualDistance <= maxDistance)
+ matches.add(createMatchCandidate(target, cs, false));
+ }
+ return matches;
+ }
+
+ @Override
+ protected void updateList(List<CandidateSpan> candidateList) {
+ candidateList.remove(0);
+ }
}