/* * Copyright (C) 2014 Indeed Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package com.indeed.flamdex.search; import com.indeed.flamdex.api.FlamdexOutOfMemoryException; import com.indeed.flamdex.api.FlamdexReader; import com.indeed.flamdex.api.IntValueLookup; import com.indeed.flamdex.datastruct.FastBitSet; import com.indeed.flamdex.datastruct.FastBitSetPooler; import com.indeed.flamdex.query.Term; /** * @author jsgroth */ class IntRangeQueryEvaluator implements QueryEvaluator { private static final int BUFFER_SIZE = 64; private final Term startTerm; private final Term endTerm; private final boolean isMaxInclusive; IntRangeQueryEvaluator(Term startTerm, Term endTerm, boolean maxInclusive) { this.startTerm = startTerm; this.endTerm = endTerm; isMaxInclusive = maxInclusive; } @Override public void and(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException { final IntValueLookup metric = r.getMetric(startTerm.getFieldName()); try { internalAnd(metric, r.getNumDocs(), bitSet); } finally { metric.close(); } } private void internalAnd(IntValueLookup metric, int numDocs, FastBitSet bitSet) { final long startVal = startTerm.getTermIntVal(); final long endVal = endTerm.getTermIntVal(); if (isMaxInclusive) { if (endVal < metric.getMin() || startVal > metric.getMax()) { bitSet.clearAll(); return; } if (startVal <= metric.getMin() && endVal >= metric.getMax()) { return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; int lastDoc = 0; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val <= endVal) { if (lastDoc != doc) { bitSet.clearRange(lastDoc, doc); } lastDoc = doc + 1; } } } bitSet.clearRange(lastDoc, numDocs); } else { if (endVal <= metric.getMin() || startVal > metric.getMax()) { bitSet.clearAll(); return; } if (startVal <= metric.getMin() && endVal > metric.getMax()) { return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; int lastDoc = 0; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val < endVal) { if (lastDoc != doc) { bitSet.clearRange(lastDoc, doc); } lastDoc = doc + 1; } } } bitSet.clearRange(lastDoc, numDocs); } } @Override public void or(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException { final IntValueLookup metric = r.getMetric(startTerm.getFieldName()); try { internalOr(metric, r.getNumDocs(), bitSet); } finally { metric.close(); } } private void internalOr(IntValueLookup metric, int numDocs, FastBitSet bitSet) { final long startVal = startTerm.getTermIntVal(); final long endVal = endTerm.getTermIntVal(); if (isMaxInclusive) { if (endVal < metric.getMin() || startVal > metric.getMax()) { return; } if (startVal <= metric.getMin() && endVal >= metric.getMax()) { bitSet.setAll(); return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val <= endVal) { bitSet.set(doc); } } } } else { if (endVal <= metric.getMin() || startVal > metric.getMax()) { return; } if (startVal <= metric.getMin() && endVal > metric.getMax()) { bitSet.setAll(); return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val < endVal) { bitSet.set(doc); } } } } } @Override public void not(FlamdexReader r, FastBitSet bitSet, FastBitSetPooler bitSetPooler) throws FlamdexOutOfMemoryException { final IntValueLookup metric = r.getMetric(startTerm.getFieldName()); try { internalNot(metric, r.getNumDocs(), bitSet); } finally { metric.close(); } } private void internalNot(IntValueLookup metric, int numDocs, FastBitSet bitSet) { final long startVal = startTerm.getTermIntVal(); final long endVal = endTerm.getTermIntVal(); if (isMaxInclusive) { if (endVal < metric.getMin() || startVal > metric.getMax()) { bitSet.setAll(); return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; int lastDoc = 0; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val <= endVal) { if (lastDoc != doc) { bitSet.setRange(lastDoc, doc); } bitSet.clear(doc); lastDoc = doc + 1; } } } bitSet.setRange(lastDoc, numDocs); } else { if (endVal <= metric.getMin() || startVal > metric.getMax()) { bitSet.setAll(); return; } final int[] docBuf = new int[BUFFER_SIZE]; final long[] valueBuf = new long[BUFFER_SIZE]; int lastDoc = 0; for (int docStart = 0; docStart < numDocs; docStart += BUFFER_SIZE) { final int n = Math.min(numDocs, docStart + BUFFER_SIZE) - docStart; for (int i = 0; i < n; ++i) { docBuf[i] = docStart + i; } metric.lookup(docBuf, valueBuf, n); for (int i = 0; i < n; ++i) { final int doc = docBuf[i]; final long val = valueBuf[i]; if (val >= startVal && val < endVal) { if (lastDoc != doc) { bitSet.setRange(lastDoc, doc); } bitSet.clear(doc); lastDoc = doc + 1; } } } bitSet.setRange(lastDoc, numDocs); } } }