blob: 0dbd06e802608eaf394350cbaf823974389e29fe [file] [log] [blame]
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();
}
}