/** * Checks if the dividing record passed as arguments is in the multi-dimensional search range * defined by this class. */ public boolean isInSearchRange(final byte[] dividingRecord) { final boolean dimShownToBeLargerThanMin[] = new boolean[numDimensions]; final boolean dimShownToBeSmallerThanMax[] = new boolean[numDimensions]; // get first byte in which the values differ int firstDifferingByte = 0; for (; firstDifferingByte < dividingRecord.length; firstDifferingByte++) { if (dividingRecord[firstDifferingByte] != searchMinZOrder[firstDifferingByte] || dividingRecord[firstDifferingByte] != searchMaxZOrder[firstDifferingByte]) { break; } } /** * We now scan sequentially over the bit array, starting with firstDifferingByte. Thereby, we * notice whenever we detect a smaller or greater situation (and make sure that, for the * dimension under investigation, we do not check again in future). Note that this operation * operates on top of the zOrder string, in which bits are interleaved. * * <p>The unsatisfiedConstraintsCtr is for performance optimizations. It is initialized with * numDimensions*2, and when its count reaches zero we know that all dimensions have to be shown * larger than min and smaller than max, i.e. that all constraints have been satisfied. */ int unsatisfiedConstraintsCtr = numDimensions * 2; for (int i = firstDifferingByte * Byte.SIZE; i < dividingRecord.length * Byte.SIZE && unsatisfiedConstraintsCtr > 0; i++) { final int dimension = i % numDimensions; final boolean divRecordBitSet = BytesUtil.getBit(dividingRecord, i); if (!dimShownToBeLargerThanMin[dimension]) { final boolean searchMinBitSet = BytesUtil.getBit(searchMinZOrder, i); if (divRecordBitSet && !searchMinBitSet) { dimShownToBeLargerThanMin[dimension] = true; unsatisfiedConstraintsCtr--; } else if (!divRecordBitSet && searchMinBitSet) { return false; // conflict } // else: skip } if (!dimShownToBeSmallerThanMax[dimension]) { final boolean searchMaxBitSet = BytesUtil.getBit(searchMaxZOrder, i); if (!divRecordBitSet && searchMaxBitSet) { dimShownToBeSmallerThanMax[dimension] = true; unsatisfiedConstraintsCtr--; } else if (divRecordBitSet && !searchMaxBitSet) { return false; } // else: skip } } return true; // all is good }
/** * Returns the BIGMIN, i.e. the next relevant value in the search range. The value is returned as * unsigned, which needs to be converted into two's complement prior to appending as a key (see * {@link GeoSpatialLiteralExtension} for details). * * <p>This method implements the BIGMIN decision table as provided in * http://www.vision-tools.com/h-tropf/multidimensionalrangequery.pdf, see page 76. * * @param iv the IV of the dividing record * @return */ public byte[] calculateBigMin(final byte[] dividingRecord) { if (dividingRecord.length != searchMinZOrder.length || dividingRecord.length != searchMaxZOrder.length) { // this should never happen, assuming correct configuration throw new RuntimeException("Key dimenisions differs"); } final int numBytes = dividingRecord.length; System.arraycopy(searchMinZOrder, 0, min, 0, zOrderArrayLength); System.arraycopy(searchMaxZOrder, 0, max, 0, zOrderArrayLength); java.util.Arrays.fill(bigmin, (byte) 0); // reset bigmin boolean finished = false; for (int i = 0; i < numBytes * Byte.SIZE && !finished; i++) { final boolean divRecordBitSet = BytesUtil.getBit(dividingRecord, i); final boolean minBitSet = BytesUtil.getBit(min, i); final boolean maxBitSet = BytesUtil.getBit(max, i); if (!divRecordBitSet) { if (!minBitSet) { if (!maxBitSet) { // case 0 - 0 - 0: continue (nothing to do) } else { // case 0 - 0 - 1 System.arraycopy(min, 0, bigmin, 0, zOrderArrayLength); load(true /* setFirst */, i, bigmin, numDimensions); load(false, i, max, numDimensions); } } else { if (!maxBitSet) { // case 0 - 1 - 0 throw new RuntimeException("MIN must be <= MAX."); } else { // case 0 - 1 - 1 System.arraycopy(min, 0, bigmin, 0, zOrderArrayLength); finished = true; } } } else { if (!minBitSet) { if (!maxBitSet) { // case 1 - 0 - 0 finished = true; } else { // case 1 - 0 - 1 load(true, i, min, numDimensions); } } else { if (!maxBitSet) { // case 1 - 1 - 0 throw new RuntimeException("MIN must be <= MAX."); } else { // case 1 - 1 - 1: continue (nothing to do) } } } } return bigmin; }