blob: e4daee3ab8dc32db4d34126764003bed3d301ddf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.carbondata.core.scan.filter.executer;
import java.io.IOException;
import java.util.BitSet;
import org.apache.carbondata.core.constants.CarbonCommonConstants;
import org.apache.carbondata.core.datastore.block.SegmentProperties;
import org.apache.carbondata.core.datastore.chunk.DimensionColumnPage;
import org.apache.carbondata.core.datastore.chunk.impl.DimensionRawColumnChunk;
import org.apache.carbondata.core.metadata.datatype.DataTypes;
import org.apache.carbondata.core.metadata.schema.table.column.CarbonDimension;
import org.apache.carbondata.core.scan.expression.Expression;
import org.apache.carbondata.core.scan.expression.conditional.GreaterThanEqualToExpression;
import org.apache.carbondata.core.scan.expression.conditional.GreaterThanExpression;
import org.apache.carbondata.core.scan.expression.conditional.LessThanEqualToExpression;
import org.apache.carbondata.core.scan.expression.conditional.LessThanExpression;
import org.apache.carbondata.core.scan.filter.FilterUtil;
import org.apache.carbondata.core.scan.filter.intf.RowIntf;
import org.apache.carbondata.core.scan.filter.resolver.resolverinfo.DimColumnResolvedFilterInfo;
import org.apache.carbondata.core.scan.processor.RawBlockletColumnChunks;
import org.apache.carbondata.core.util.BitSetGroup;
import org.apache.carbondata.core.util.ByteUtil;
import org.apache.carbondata.core.util.CarbonUtil;
/**
* This Class get a Min And Max value of a RANGE expression. Finds out if scan is required
* for this Range. Also search the data block and set the required bitsets which falls within
* the Range of the RANGE Expression.
*/
public class RangeValueFilterExecutorImpl implements FilterExecutor {
private DimColumnResolvedFilterInfo dimColEvaluatorInfo;
private Expression exp;
private byte[][] filterRangesValues;
private SegmentProperties segmentProperties;
private boolean isDefaultValuePresentInFilter;
/**
* flag to check whether the filter dimension is present in current block list of dimensions.
* Applicable for restructure scenarios
*/
private boolean isDimensionPresentInCurrentBlock;
private boolean lessThanExp;
private boolean lessThanEqualExp;
private boolean greaterThanExp;
private boolean greaterThanEqualExp;
private boolean startBlockMinIsDefaultStart;
private boolean endBlockMaxisDefaultEnd;
private boolean isRangeFullyCoverBlock;
private boolean isNaturalSorted;
public RangeValueFilterExecutorImpl(DimColumnResolvedFilterInfo dimColEvaluatorInfo,
Expression exp, byte[][] filterRangeValues, SegmentProperties segmentProperties) {
this.dimColEvaluatorInfo = dimColEvaluatorInfo;
this.exp = exp;
this.segmentProperties = segmentProperties;
this.filterRangesValues = filterRangeValues;
this.lessThanExp = isLessThan();
this.lessThanEqualExp = isLessThanEqualTo();
this.greaterThanExp = isGreaterThan();
this.greaterThanEqualExp = isGreaterThanEqualTo();
startBlockMinIsDefaultStart = false;
endBlockMaxisDefaultEnd = false;
isRangeFullyCoverBlock = false;
initDimensionChunkIndexes();
ifDefaultValueMatchesFilter();
if (isDimensionPresentInCurrentBlock) {
isNaturalSorted = dimColEvaluatorInfo.getDimension().isUseInvertedIndex()
&& dimColEvaluatorInfo.getDimension().isSortColumn();
}
}
/**
* This method will initialize the dimension info for the current block to be
* used for filtering the data
*/
private void initDimensionChunkIndexes() {
// find the dimension in the current block dimensions list
CarbonDimension dimensionFromCurrentBlock =
segmentProperties.getDimensionFromCurrentBlock(dimColEvaluatorInfo.getDimension());
if (null != dimensionFromCurrentBlock) {
dimColEvaluatorInfo.setColumnIndex(dimensionFromCurrentBlock.getOrdinal());
isDimensionPresentInCurrentBlock = true;
}
}
/**
* This method will check whether default value is present in the given filter values
*/
private void ifDefaultValueMatchesFilter() {
isDefaultValuePresentInFilter = false;
if (!this.isDimensionPresentInCurrentBlock && null != filterRangesValues) {
CarbonDimension dimension = this.dimColEvaluatorInfo.getDimension();
byte[] defaultValue = dimension.getDefaultValue();
if (null != defaultValue) {
int minCompare =
FilterUtil.compareValues(filterRangesValues[0], defaultValue, dimension, true);
int maxCompare =
FilterUtil.compareValues(filterRangesValues[1], defaultValue, dimension, false);
if (((greaterThanExp && maxCompare > 0) || (greaterThanEqualExp && maxCompare >= 0)) && (
(lessThanExp && minCompare > 0) || (lessThanEqualExp && minCompare >= 0))) {
isDefaultValuePresentInFilter = true;
}
}
}
}
/**
* Method to apply the filter.
* @param rawBlockletColumnChunks
* @return
* @throws IOException
*/
public BitSetGroup applyFilter(RawBlockletColumnChunks rawBlockletColumnChunks,
boolean useBitsetPipeLine) throws IOException {
return applyNoAndDirectFilter(rawBlockletColumnChunks, useBitsetPipeLine);
}
@Override
public BitSet prunePages(RawBlockletColumnChunks blockChunkHolder)
throws IOException {
// In case of Alter Table Add and Delete Columns the isDimensionPresentInCurrentBlock can be
// false, in that scenario the default values of the column should be shown.
// select all rows if dimension does not exists in the current block
if (!isDimensionPresentInCurrentBlock) {
int numberOfPages = blockChunkHolder.getDataBlock().numberOfPages();
BitSet bitSet = new BitSet();
bitSet.set(0, numberOfPages);
return bitSet;
}
int chunkIndex = segmentProperties.getDimensionOrdinalToChunkMapping()
.get(dimColEvaluatorInfo.getColumnIndex());
if (null == blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex]) {
blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex] = blockChunkHolder.getDataBlock()
.readDimensionChunk(blockChunkHolder.getFileReader(), chunkIndex);
}
DimensionRawColumnChunk rawColumnChunk =
blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex];
BitSet bitSet = new BitSet(rawColumnChunk.getPagesCount());
for (int i = 0; i < rawColumnChunk.getPagesCount(); i++) {
if (rawColumnChunk.getMaxValues() != null) {
if (isScanRequired(rawColumnChunk.getMinValues()[i], rawColumnChunk.getMaxValues()[i],
this.filterRangesValues, rawColumnChunk.getMinMaxFlagArray()[i])) {
bitSet.set(i);
}
} else {
bitSet.set(i);
}
}
return bitSet;
}
/**
* apply range filter on a row
*/
public boolean applyFilter(RowIntf value, int dimOrdinalMax) {
byte[] col = (byte[]) value.getVal(dimColEvaluatorInfo.getDimension().getOrdinal());
byte[][] filterValues = this.filterRangesValues;
if (isDimensionPresentInCurrentBlock) {
boolean result;
if (greaterThanExp) {
result = ByteUtil.compare(filterValues[0], col) < 0;
} else {
result = ByteUtil.compare(filterValues[0], col) <= 0;
}
if (result) {
if (lessThanExp) {
return ByteUtil.compare(filterValues[1], col) > 0;
} else {
return ByteUtil.compare(filterValues[1], col) >= 0;
}
}
}
return false;
}
/**
* Method to find presence of LessThan Expression.
* @return
*/
private boolean isLessThan() {
for (Expression result : this.exp.getChildren()) {
if (result instanceof LessThanExpression) {
return true;
}
}
return false;
}
/**
* Method to find presence of LessThanEqualTo Expression.
* @return
*/
private boolean isLessThanEqualTo() {
for (Expression result : this.exp.getChildren()) {
if (result instanceof LessThanEqualToExpression) {
return true;
}
}
return false;
}
/**
* Method to find presence of GreaterThan Expression.
* @return
*/
private boolean isGreaterThan() {
for (Expression result : this.exp.getChildren()) {
if (result instanceof GreaterThanExpression) {
return true;
}
}
return false;
}
/**
* Method to find presence of GreaterThanEqual Expression.
* @return
*/
private boolean isGreaterThanEqualTo() {
for (Expression result : this.exp.getChildren()) {
if (result instanceof GreaterThanEqualToExpression) {
return true;
}
}
return false;
}
/**
* Method to identify if scanning of Data Block required or not by comparing the Block Min and Max
* values and comparing them with filter min and max value.
* @param blockMinValue
* @param blockMaxValue
* @param filterValues
* @return
*/
public boolean isScanRequired(byte[] blockMinValue, byte[] blockMaxValue, byte[][] filterValues,
boolean isMinMaxSet) {
if (!isMinMaxSet) {
// scan complete data if min max is not written for a given column
return true;
}
boolean isScanRequired = true;
isRangeFullyCoverBlock = false;
startBlockMinIsDefaultStart = false;
endBlockMaxisDefaultEnd = false;
/*
For understanding the below logic kept the value evaluation code intact.
int filterMinLessThanBlockMin =
ByteUtil.UnsafeComparer.INSTANCE.compareTo(blockMinValue, filterValues[0]);
int filterMaxLessThanBlockMin =
ByteUtil.UnsafeComparer.INSTANCE.compareTo(blockMinValue, filterValues[1]);
int filterMinGreaterThanBlockMax =
ByteUtil.UnsafeComparer.INSTANCE.compareTo(filterValues[0], blockMaxValue);
int filterMaxGreaterThanBlockMax =
ByteUtil.UnsafeComparer.INSTANCE.compareTo(filterValues[1], blockMaxValue);
*/
// if any filter value is in range than this block needs to be
// scanned less than equal to max range.
// There are 4 cases which has been explicitly handled.
// case A: Outside Boundary > No Scan required
// Block Min <----------> Block Max
// Filter Min <----------> Filter Max
// case B: Filter Overlaps Upper Part Block then Block Start Scan Becomes StartIndex of Block.
// Block Min <-----------------> Block Max
// Filter Min <-------------------------> Filter Min
// Case C: Filter Overlaps Lower Part of Block then Block End Scan becomes Number Of Rows - 1
// Block Min <-------------------------> Block Max
// Filter Min <--------------------------> Filter Max
// Case D: Filter Values Completely overlaps Block Min and Max then all bits are set.
// Block Min <-----------------------> Block Max
// Filter Min <-----------------------------------------------> Filter Max
// for no dictionary measure column comparison can be done
// on the original data as like measure column
if (isDimensionPresentInCurrentBlock) {
CarbonDimension carbonDimension = dimColEvaluatorInfo.getDimension();
if (((lessThanExp) && (
FilterUtil.compareValues(filterValues[1], blockMinValue, carbonDimension, true) >= 0))
|| ((lessThanEqualExp) && (
FilterUtil.compareValues(filterValues[1], blockMinValue, carbonDimension, true) > 0)) || (
(greaterThanExp) && (
FilterUtil.compareValues(filterValues[0], blockMaxValue, carbonDimension, false)
>= 0)) || ((greaterThanEqualExp) && (
FilterUtil.compareValues(filterValues[0], blockMaxValue, carbonDimension, false) > 0))) {
// completely out of block boundary
isScanRequired = false;
} else {
if (((greaterThanExp) && (
FilterUtil.compareValues(filterValues[0], blockMinValue, carbonDimension, true) > 0))
|| ((greaterThanEqualExp) && (
FilterUtil.compareValues(filterValues[0], blockMinValue, carbonDimension, true)
>= 0))) {
startBlockMinIsDefaultStart = true;
}
if (((lessThanExp) && (
FilterUtil.compareValues(filterValues[1], blockMaxValue, carbonDimension, false) > 0))
|| ((lessThanEqualExp) && (
FilterUtil.compareValues(filterValues[1], blockMaxValue, carbonDimension, false)
>= 0))) {
endBlockMaxisDefaultEnd = true;
}
if (startBlockMinIsDefaultStart && endBlockMaxisDefaultEnd) {
isRangeFullyCoverBlock = true;
}
}
return isScanRequired;
} else {
return isDefaultValuePresentInFilter;
}
}
/**
* Method checks is the scan lies within the range values or not.
* @param blockMaxValue
* @param blockMinValue
* @return
*/
@Override
public BitSet isScanRequired(byte[][] blockMaxValue, byte[][] blockMinValue,
boolean[] isMinMaxSet) {
BitSet bitSet = new BitSet(1);
byte[][] filterValues = this.filterRangesValues;
int columnIndex = this.dimColEvaluatorInfo.getColumnIndexInMinMaxByteArray();
boolean isScanRequired =
columnIndex >= blockMinValue.length || isScanRequired(blockMinValue[columnIndex],
blockMaxValue[columnIndex], filterValues, isMinMaxSet[columnIndex]);
if (isScanRequired) {
bitSet.set(0);
}
return bitSet;
}
/**
* Method to apply the Range Filter.
* @param blockChunkHolder
* @return
* @throws IOException
*/
private BitSetGroup applyNoAndDirectFilter(RawBlockletColumnChunks blockChunkHolder,
boolean useBitsetPipeLine) throws IOException {
// In case of Alter Table Add and Delete Columns the isDimensionPresentInCurrentBlock can be
// false, in that scenario the default values of the column should be shown.
// select all rows if dimension does not exists in the current block
if (!isDimensionPresentInCurrentBlock) {
int numberOfRows = blockChunkHolder.getDataBlock().numRows();
return FilterUtil.createBitSetGroupWithDefaultValue(
blockChunkHolder.getDataBlock().numberOfPages(), numberOfRows, true);
}
int chunkIndex = segmentProperties.getDimensionOrdinalToChunkMapping()
.get(dimColEvaluatorInfo.getColumnIndex());
if (null == blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex]) {
blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex] =
blockChunkHolder.getDataBlock().readDimensionChunk(
blockChunkHolder.getFileReader(), chunkIndex);
}
DimensionRawColumnChunk rawColumnChunk =
blockChunkHolder.getDimensionRawColumnChunks()[chunkIndex];
BitSetGroup bitSetGroup = new BitSetGroup(rawColumnChunk.getPagesCount());
FilterExecutor filterExecutor = null;
boolean isExclude = false;
for (int i = 0; i < rawColumnChunk.getPagesCount(); i++) {
if (rawColumnChunk.getMaxValues() != null) {
if (isScanRequired(rawColumnChunk.getMinValues()[i], rawColumnChunk.getMaxValues()[i],
this.filterRangesValues, rawColumnChunk.getMinMaxFlagArray()[i])) {
if (isRangeFullyCoverBlock) {
// Set all the bits in this case as filter Min Max values cover the whole block.
BitSet bitSet = new BitSet(rawColumnChunk.getRowCount()[i]);
bitSet.flip(0, rawColumnChunk.getRowCount()[i]);
bitSetGroup.setBitSet(bitSet, i);
} else {
BitSet bitSet;
DimensionColumnPage dimensionColumnPage = rawColumnChunk.decodeColumnPage(i);
if (null != rawColumnChunk.getLocalDictionary()) {
if (null == filterExecutor) {
filterExecutor = FilterUtil
.getFilterExecutorForRangeFilters(rawColumnChunk, exp, isNaturalSorted);
if (filterExecutor instanceof ExcludeFilterExecutorImpl) {
isExclude = true;
}
}
if (!isExclude) {
bitSet = ((IncludeFilterExecutorImpl) filterExecutor)
.getFilteredIndexes(dimensionColumnPage,
rawColumnChunk.getRowCount()[i], useBitsetPipeLine,
blockChunkHolder.getBitSetGroup(), i);
} else {
bitSet = ((ExcludeFilterExecutorImpl) filterExecutor)
.getFilteredIndexes(dimensionColumnPage,
rawColumnChunk.getRowCount()[i], useBitsetPipeLine,
blockChunkHolder.getBitSetGroup(), i);
}
} else {
bitSet = getFilteredIndexes(dimensionColumnPage,
rawColumnChunk.getRowCount()[i]);
}
bitSetGroup.setBitSet(bitSet, i);
}
}
} else {
BitSet bitSet = getFilteredIndexes(rawColumnChunk.decodeColumnPage(i),
rawColumnChunk.getRowCount()[i]);
bitSetGroup.setBitSet(bitSet, i);
}
}
return bitSetGroup;
}
private BitSet getFilteredIndexes(DimensionColumnPage dimensionColumnPage,
int numberOfRows) {
if (dimensionColumnPage.isExplicitSorted()) {
return setFilteredIndexToBitSetWithColumnIndex(dimensionColumnPage, numberOfRows);
}
return setFilteredIndexToBitSet(dimensionColumnPage, numberOfRows);
}
/**
* Method will scan the block and finds the range start index from which all members
* will be considered for applying range filters. this method will be called if the
* column is not supported by default so column index mapping will be present for
* accessing the members from the block.
*
* @param dimensionColumnPage
* @param numberOfRows
* @return BitSet.
*/
private BitSet setFilteredIndexToBitSetWithColumnIndex(
DimensionColumnPage dimensionColumnPage, int numberOfRows) {
BitSet bitSet = new BitSet(numberOfRows);
int start = 0;
int startIndex = 0;
int startMin = 0;
int endMax = 0;
byte[][] filterValues = this.filterRangesValues;
// For Range expression we expect two values. The First is the Min Value and Second is the
// Max value.
// Get the Min Value
if (!startBlockMinIsDefaultStart) {
start = CarbonUtil
.getFirstIndexUsingBinarySearch(dimensionColumnPage, startIndex, numberOfRows - 1,
filterValues[0], greaterThanExp);
if (greaterThanExp && start >= 0) {
start = CarbonUtil
.nextGreaterValueToTarget(start, dimensionColumnPage, filterValues[0],
numberOfRows);
}
if (start < 0) {
start = -(start + 1);
if (start == numberOfRows) {
start = start - 1;
}
// Method will compare the tentative index value after binary search, this tentative
// index needs to be compared by the filter member if its >= filter then from that
// index the bitset will be considered for filtering process.
if ((ByteUtil.compare(filterValues[0], dimensionColumnPage
.getChunkData(dimensionColumnPage.getInvertedIndex(start)))) > 0) {
start = start + 1;
}
}
startMin = start;
} else {
startMin = startIndex;
}
// Get the Max value
if (!endBlockMaxisDefaultEnd) {
start = CarbonUtil
.getFirstIndexUsingBinarySearch(dimensionColumnPage, startIndex, numberOfRows - 1,
filterValues[1], lessThanEqualExp);
if (lessThanExp && start >= 0) {
start =
CarbonUtil.nextLesserValueToTarget(start, dimensionColumnPage, filterValues[1]);
}
if (start < 0) {
start = -(start + 1);
if (start == numberOfRows) {
start = start - 1;
}
// In case the start is less than 0, then positive value of start is pointing to the next
// value of the searched key. So move to the previous one.
if ((ByteUtil.compare(filterValues[1],
dimensionColumnPage.getChunkData(dimensionColumnPage.getInvertedIndex(start)))
< 0)) {
start = start - 1;
}
}
endMax = start;
} else {
endMax = numberOfRows - 1;
}
for (int j = startMin; j <= endMax; j++) {
bitSet.set(dimensionColumnPage.getInvertedIndex(j));
}
// Binary Search cannot be done on '@NU#LL$!", so need to check and compare for null on
// matching row.
if (dimensionColumnPage.isNoDictionaryColumn() && !dimensionColumnPage.isAdaptiveEncoded()) {
updateForNoDictionaryColumn(startMin, endMax, dimensionColumnPage, bitSet);
}
return bitSet;
}
private void updateForNoDictionaryColumn(int start, int end, DimensionColumnPage dataChunk,
BitSet bitset) {
for (int j = start; j <= end; j++) {
if (dataChunk.compareTo(j, CarbonCommonConstants.MEMBER_DEFAULT_VAL_ARRAY) == 0
|| dataChunk.compareTo(j, CarbonCommonConstants.EMPTY_BYTE_ARRAY) == 0) {
bitset.flip(j);
}
}
}
/**
* Method will scan the block and finds the range start index from which all
* members will be considered for applying range filters. this method will
* be called if the column is sorted default so column index
* mapping will be present for accessing the members from the block.
*
* @param dimensionColumnPage
* @param numberOfRows
* @return BitSet.
*/
private BitSet setFilteredIndexToBitSet(DimensionColumnPage dimensionColumnPage,
int numberOfRows) {
BitSet bitSet = new BitSet(numberOfRows);
// if (dimensionColumnPage instanceof FixedLengthDimensionColumnPage) {
byte[][] filterValues = this.filterRangesValues;
if (dimensionColumnPage.isExplicitSorted()) {
int start = 0;
int startMin = 0;
int endMax = 0;
int startIndex = 0;
// For Range expression we expect two values. The First is the Min Value and Second is the
// Max value.
if (!startBlockMinIsDefaultStart) {
start = CarbonUtil
.getFirstIndexUsingBinarySearch(dimensionColumnPage, startIndex, numberOfRows - 1,
filterValues[0], greaterThanExp);
if (greaterThanExp && start >= 0) {
start = CarbonUtil
.nextGreaterValueToTarget(start, dimensionColumnPage, filterValues[0],
numberOfRows);
}
if (start < 0) {
start = -(start + 1);
if (start == numberOfRows) {
start = start - 1;
}
// Method will compare the tentative index value after binary search, this tentative
// index needs to be compared by the filter member if its >= filter then from that
// index the bitset will be considered for filtering process.
if ((ByteUtil.compare(filterValues[0], dimensionColumnPage.getChunkData(start)))
> 0) {
start = start + 1;
}
}
startMin = start;
} else {
startMin = startIndex;
}
if (!endBlockMaxisDefaultEnd) {
start = CarbonUtil
.getFirstIndexUsingBinarySearch(dimensionColumnPage, startIndex, numberOfRows - 1,
filterValues[1], lessThanEqualExp);
if (lessThanExp && start >= 0) {
start =
CarbonUtil.nextLesserValueToTarget(start, dimensionColumnPage, filterValues[1]);
}
if (start < 0) {
start = -(start + 1);
if (start == numberOfRows) {
start = start - 1;
}
// In case the start is less than 0, then positive value of start is pointing to the next
// value of the searched key. So move to the previous one.
if ((ByteUtil.compare(filterValues[1], dimensionColumnPage.getChunkData(start))
< 0)) {
start = start - 1;
}
}
endMax = start;
} else {
endMax = numberOfRows - 1;
}
for (int j = startMin; j <= endMax; j++) {
bitSet.set(j);
}
// Binary Search cannot be done on '@NU#LL$!", so need to check and compare for null on
// matching row.
if (dimensionColumnPage.isNoDictionaryColumn()) {
updateForNoDictionaryColumn(startMin, endMax, dimensionColumnPage, bitSet);
}
} else {
byte[] defaultValue = null;
if (dimColEvaluatorInfo.getDimension().getDataType() == DataTypes.DATE) {
defaultValue =
FilterUtil.getDefaultNullValue(dimColEvaluatorInfo.getDimension());
} else if (dimColEvaluatorInfo.getDimension().getDataType() == DataTypes.STRING) {
defaultValue = CarbonCommonConstants.MEMBER_DEFAULT_VAL_ARRAY;
} else if (!dimensionColumnPage.isAdaptiveEncoded()) {
defaultValue = CarbonCommonConstants.EMPTY_BYTE_ARRAY;
}
// evaluate result for lower range value first and then perform and operation in the
// upper range value in order to compute the final result
bitSet = evaluateGreaterThanFilterForUnsortedColumn(dimensionColumnPage, filterValues[0],
numberOfRows);
BitSet upperRangeBitSet =
evaluateLessThanFilterForUnsortedColumn(dimensionColumnPage, filterValues[1],
numberOfRows);
bitSet.and(upperRangeBitSet);
FilterUtil.removeNullValues(dimensionColumnPage, bitSet, defaultValue);
}
return bitSet;
}
/**
* This method will evaluate the result for filter column based on the lower range value
*
* @param dimensionColumnPage
* @param filterValue
* @param numberOfRows
* @return
*/
private BitSet evaluateGreaterThanFilterForUnsortedColumn(
DimensionColumnPage dimensionColumnPage, byte[] filterValue, int numberOfRows) {
BitSet bitSet = new BitSet(numberOfRows);
if (greaterThanExp) {
for (int i = 0; i < numberOfRows; i++) {
if ((ByteUtil.compare(dimensionColumnPage.getChunkData(i), filterValue) > 0)) {
bitSet.set(i);
}
}
} else if (greaterThanEqualExp) {
for (int i = 0; i < numberOfRows; i++) {
if ((ByteUtil.compare(dimensionColumnPage.getChunkData(i), filterValue) >= 0)) {
bitSet.set(i);
}
}
}
return bitSet;
}
/**
* This method will evaluate the result for filter column based on the upper range value
*
* @param dimensionColumnPage
* @param filterValue
* @param numberOfRows
* @return
*/
private BitSet evaluateLessThanFilterForUnsortedColumn(
DimensionColumnPage dimensionColumnPage, byte[] filterValue, int numberOfRows) {
BitSet bitSet = new BitSet(numberOfRows);
if (lessThanExp) {
for (int i = 0; i < numberOfRows; i++) {
if ((ByteUtil.compare(dimensionColumnPage.getChunkData(i), filterValue) < 0)) {
bitSet.set(i);
}
}
} else if (lessThanEqualExp) {
for (int i = 0; i < numberOfRows; i++) {
if ((ByteUtil.compare(dimensionColumnPage.getChunkData(i), filterValue) <= 0)) {
bitSet.set(i);
}
}
}
return bitSet;
}
/**
* Method to read the blocks.
* @param rawBlockletColumnChunks
* @throws IOException
*/
@Override
public void readColumnChunks(RawBlockletColumnChunks rawBlockletColumnChunks) throws IOException {
if (isDimensionPresentInCurrentBlock) {
int chunkIndex = segmentProperties.getDimensionOrdinalToChunkMapping()
.get(dimColEvaluatorInfo.getColumnIndex());
if (null == rawBlockletColumnChunks.getDimensionRawColumnChunks()[chunkIndex]) {
rawBlockletColumnChunks.getDimensionRawColumnChunks()[chunkIndex] =
rawBlockletColumnChunks.getDataBlock().readDimensionChunk(
rawBlockletColumnChunks.getFileReader(), chunkIndex);
}
}
}
}