/** * Evaluates the full-text match. * * @param qc query context * @return number of tokens, used for scoring * @throws QueryException query exception */ private int contains(final QueryContext qc) throws QueryException { first = true; final FTLexer lexer = ftt.lexer(qc.ftToken); // use faster evaluation for default options int num = 0; if (fast) { for (final byte[] t : tokens) { final FTTokens qtok = ftt.cache(t); num = Math.max(num, ftt.contains(qtok, lexer) * qtok.length()); } return num; } // find and count all occurrences final boolean all = mode == FTMode.ALL || mode == FTMode.ALL_WORDS; int oc = 0; for (final byte[] w : unique(tokens(qc))) { final FTTokens qtok = ftt.cache(w); final int o = ftt.contains(qtok, lexer); if (all && o == 0) return 0; num = Math.max(num, o * qtok.length()); oc += o; } // check if occurrences are in valid range. if yes, return number of tokens final long mn = occ != null ? toLong(occ[0], qc) : 1; final long mx = occ != null ? toLong(occ[1], qc) : Long.MAX_VALUE; if (mn == 0 && oc == 0) matches = FTNot.not(matches); return oc >= mn && oc <= mx ? Math.max(1, num) : 0; }
/** * Returns a scan-based index iterator. * * @param lex lexer, including the queried value * @return node iterator * @throws QueryException query exception */ private FTIndexIterator scan(final FTLexer lex) throws QueryException { final FTLexer input = new FTLexer(ftt.opt); final FTTokens fttokens = ftt.cache(lex.get()); return new FTIndexIterator() { final int sz = data.meta.size; int pre = -1, ps; @Override public int pre() { return pre; } @Override public boolean more() { while (++pre < sz) { if (data.kind(pre) != Data.TEXT) continue; input.init(data.text(pre, true)); matches.reset(ps); try { if (ftt.contains(fttokens, input) != 0) return true; } catch (final QueryException ignore) { // ignore exceptions } } return false; } @Override public FTMatches matches() { return matches; } @Override public void pos(final int p) { ps = p; } @Override public int size() { // worst case return Math.max(1, sz >>> 1); } }; }