package org.basex.index.ft; import org.basex.data.FTMatch; import org.basex.data.FTMatches; import org.basex.index.IndexIterator; import org.basex.util.ft.Scoring; /** * This interface provides methods for returning index results. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public abstract class FTIndexIterator extends IndexIterator { /** Each token in the query has a number. */ int toknum; /** Empty iterator. */ static final FTIndexIterator FTEMPTY = new FTIndexIterator() { @Override public boolean more() { return false; } @Override public int next() { return 0; } @Override public FTMatches matches() { return null; } @Override public double score() { return -1; } @Override public int size() { return 0; } }; /** * Returns the next match. * @return next match */ public abstract FTMatches matches(); /** * Sets the unique token number. Used for visualization. * @param tn number of tokens */ public void tokenNum(final byte tn) { toknum = tn; } /** * Merges two index array iterators. * @param i1 first index array iterator to merge * @param i2 second index array iterator to merge * @return IndexArrayIterator */ public static FTIndexIterator union(final FTIndexIterator i1, final FTIndexIterator i2) { return new FTIndexIterator() { FTIndexIterator n, r, s; int c; @Override public boolean more() { if(c <= 0) r = i1.more() ? i1 : null; if(c >= 0) s = i2.more() ? i2 : null; c = r != null && s != null ? r.next() - s.next() : r != null ? -1 : 1; n = c <= 0 ? r : s; return n != null; } @Override public FTMatches matches() { final FTMatches m = n.matches(); if(c == 0) for(final FTMatch sm : s.matches()) m.add(sm); return m; } @Override public int next() { return n.next(); } @Override public void tokenNum(final byte tn) { i1.toknum = tn; i2.toknum = tn; } @Override public synchronized int size() { return i1.size() + i2.size(); } @Override public double score() { return Scoring.union(i1.score(), i2.score()); } @Override public String toString() { return "(" + i1 + " | " + i2 + ')'; } }; } /** * Merges two index array iterators. * @param i1 first index array iterator to merge * @param i2 second index array iterator to merge * @param dis word distance. Ignored if {@code 0} * @return IndexArrayIterator */ public static FTIndexIterator intersect(final FTIndexIterator i1, final FTIndexIterator i2, final int dis) { return new FTIndexIterator() { FTIndexIterator r, s; @Override public boolean more() { int c = 0; while(true) { if(c <= 0) r = i1.more() ? i1 : null; if(c >= 0) s = i2.more() ? i2 : null; if(r == null || s == null) return false; c = r.next() - s.next(); if(c == 0 && (dis == 0 || r.matches().phrase(s.matches(), dis))) return true; } } @Override public FTMatches matches() { return r.matches(); } @Override public int next() { return r.next(); } @Override public void tokenNum(final byte tn) { i1.toknum = tn; i2.toknum = tn; } @Override public synchronized int size() { return Math.min(i1.size(), i2.size()); } @Override public double score() { return Scoring.intersect(i1.score(), i2.score()); } @Override public String toString() { return "(" + i1 + " & " + i2 + ')'; } }; } }