| package de.ids_mannheim.korap.query.spans; |
| |
| import java.io.IOException; |
| import java.util.Map; |
| |
| import org.apache.lucene.index.AtomicReaderContext; |
| import org.apache.lucene.index.Term; |
| import org.apache.lucene.index.TermContext; |
| import org.apache.lucene.search.spans.Spans; |
| import org.apache.lucene.util.Bits; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import de.ids_mannheim.korap.query.SpanMultipleDistanceQuery; |
| |
| /** Span enumeration of matches whose two sub-spans have exactly the same |
| * first and second sub-sub-spans. This class basically filters the span |
| * matches of its child spans. |
| * |
| * This accommodates distance constraint with exclusion. |
| * Case 1: return the match from another non-exclusion constraint. |
| * Case 2: return only the first-span when all constraints are exclusions. |
| * Case 3: spans are not in the same doc |
| * |
| * @author margaretha |
| * */ |
| public class MultipleDistanceSpans extends DistanceSpans{ |
| |
| private final static Logger log = LoggerFactory.getLogger(MultipleDistanceSpans.class); |
| // This advices the java compiler to ignore all loggings |
| public static final boolean DEBUG = false; |
| |
| private DistanceSpans x,y; |
| private boolean isOrdered; |
| |
| public MultipleDistanceSpans(SpanMultipleDistanceQuery query, |
| AtomicReaderContext context, Bits acceptDocs, |
| Map<Term, TermContext> termContexts, Spans firstSpans, |
| Spans secondSpans, boolean isOrdered, boolean exclusion) |
| throws IOException { |
| super(query, context, acceptDocs, termContexts); |
| this.isOrdered = isOrdered; |
| this.exclusion = exclusion; |
| x = (DistanceSpans) firstSpans; |
| y = (DistanceSpans) secondSpans; |
| hasMoreSpans = x.next() && y.next(); |
| } |
| |
| @Override |
| public boolean next() throws IOException { |
| isStartEnumeration=false; |
| matchPayload.clear(); |
| return advance(); |
| } |
| |
| /** Find the next match. |
| * */ |
| protected boolean advance() throws IOException { |
| while (hasMoreSpans && ensureSameDoc(x, y)){ |
| if (findMatch()){ |
| moveForward(); |
| return true; |
| } |
| moveForward(); |
| } |
| return false; |
| } |
| |
| /** Find the next match of one of the sub/child-span. |
| * */ |
| private void moveForward() throws IOException{ |
| if (isOrdered){ |
| if (x.end() < y.end() || |
| (x.end() == y.end() && x.start() < y.start()) ) |
| hasMoreSpans = x.next(); |
| else hasMoreSpans = y.next(); |
| } |
| // The matches of unordered distance spans are ordered by the |
| // start position |
| else { |
| if (x.start() < y.start() || |
| (x.start() == y.start() && x.end() < y.end()) ) |
| hasMoreSpans = x.next(); |
| else hasMoreSpans = y.next(); |
| } |
| } |
| |
| /** Check if the sub-spans of x and y having exactly the same position. |
| * This is basically an AND operation. |
| * @return true iff the sub-spans are identical. |
| * */ |
| protected boolean findMatch() throws IOException { |
| |
| CandidateSpan xf = x.getMatchFirstSpan(); |
| CandidateSpan xs = x.getMatchSecondSpan(); |
| |
| CandidateSpan yf = y.getMatchFirstSpan(); |
| CandidateSpan ys = y.getMatchSecondSpan(); |
| |
| if (x.isExclusion() || y.isExclusion()){ |
| if (xf.getStart() == yf.getStart() && xf.getEnd() == yf.getEnd()){ |
| // case 2 |
| if (x.isExclusion() && y.isExclusion()){ |
| // set x or y doesnt matter |
| setMatchProperties(x,true); |
| } |
| // case 1 |
| else if (x.isExclusion()){ |
| // set y, the usual match |
| setMatchProperties(y,true); |
| } |
| // case 1 |
| else { setMatchProperties(x,true); } |
| return true; |
| } |
| } |
| else if (xf.getStart() == yf.getStart() && |
| xf.getEnd() == yf.getEnd() && |
| xs.getStart() == ys.getStart() && |
| xs.getEnd() == ys.getEnd()){ |
| setMatchProperties(x,false); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| private void setMatchProperties(DistanceSpans span, boolean exclusion) { |
| matchStartPosition = span.start(); |
| matchEndPosition = span.end(); |
| matchDocNumber = span.doc(); |
| matchPayload = span.matchPayload; |
| |
| setMatchFirstSpan(span.getMatchFirstSpan()); |
| if (!exclusion) setMatchSecondSpan(span.getMatchSecondSpan()); |
| if (DEBUG) |
| log.trace("doc# {}, start {}, end {}",matchDocNumber, |
| matchStartPosition,matchEndPosition); |
| } |
| |
| @Override |
| public boolean skipTo(int target) throws IOException { |
| if (hasMoreSpans && (y.doc() < target)){ |
| if (!y.skipTo(target)){ |
| return false; |
| } |
| } |
| matchPayload.clear(); |
| isStartEnumeration=false; |
| return advance(); |
| } |
| |
| @Override |
| public long cost() { |
| return x.cost() + y.cost(); |
| } |
| |
| } |