/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* 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.linkedin.pinot.core.operator.filter.predicate;
import com.linkedin.pinot.common.data.FieldSpec;
import com.linkedin.pinot.core.common.predicate.EqPredicate;
import com.linkedin.pinot.core.segment.index.readers.Dictionary;
/**
* Factory for equality predicate evaluators.
*/
public class EqualsPredicateEvaluatorFactory {
// Private constructor
private EqualsPredicateEvaluatorFactory() {
}
/**
* Returns a new instance of dictionary based equality predicate evaluator.
* @param predicate Predicate to evaluate
* @param dictionary Dictionary for the column
* @return Dictionary based equality predicate evaluator
*/
public static PredicateEvaluator newDictionaryBasedEvaluator(EqPredicate predicate, Dictionary dictionary) {
return new DictionaryBasedEqualsPredicateEvaluator(predicate, dictionary);
}
/**
* Returns a new instance of no-dictionary based equality predicate evaluator.
* @param predicate Predicate to evaluate
* @param dataType Data type for the column
* @return No Dictionary based equality predicate evaluator
*/
public static PredicateEvaluator newNoDictionaryBasedEvaluator(EqPredicate predicate, FieldSpec.DataType dataType) {
switch (dataType) {
case INT:
return new IntNoDictionaryBasedEqualsEvaluator(predicate);
case LONG:
return new LongNoDictionaryBasedEqualsEvaluator(predicate);
case FLOAT:
return new FloatNoDictionaryBasedEqualsEvaluator(predicate);
case DOUBLE:
return new DoubleNoDictionaryBasedEqualsEvaluator(predicate);
case STRING:
return new StringNoDictionaryBasedEqualsEvaluator(predicate);
default:
throw new UnsupportedOperationException(
"No dictionary based Equals predicate evaluator not supported for datatype:" + dataType);
}
}
/**
*
* No dictionary equality evaluator for int data type.
*/
private static final class IntNoDictionaryBasedEqualsEvaluator extends BasePredicateEvaluator {
int _expectedValue;
public IntNoDictionaryBasedEqualsEvaluator(EqPredicate predicate) {
_expectedValue = Integer.parseInt(predicate.getEqualsValue());
}
@Override
public boolean apply(int inputValue) {
return (_expectedValue == inputValue);
}
@Override
public boolean apply(int[] inputValues) {
return apply(inputValues, inputValues.length);
}
@Override
public boolean apply(int[] inputValues, int length) {
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int i = 0; i < length; i++) {
int inputValue = inputValues[i];
if (_expectedValue == inputValue) {
return true;
}
}
return false;
}
}
/**
*
* No dictionary equality evaluator for long data type.
*/
private static final class LongNoDictionaryBasedEqualsEvaluator extends BasePredicateEvaluator {
long _expectedValue;
public LongNoDictionaryBasedEqualsEvaluator(EqPredicate predicate) {
_expectedValue = Long.parseLong(predicate.getEqualsValue());
}
@Override
public boolean apply(long inputValue) {
return (_expectedValue == inputValue);
}
@Override
public boolean apply(long[] inputValues) {
return apply(inputValues, inputValues.length);
}
@Override
public boolean apply(long[] inputValues, int length) {
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int i = 0; i < length; i++) {
long inputValue = inputValues[i];
if (_expectedValue == inputValue) {
return true;
}
}
return false;
}
}
/**
*
* No dictionary equality evaluator for float data type.
*/
private static final class FloatNoDictionaryBasedEqualsEvaluator extends BasePredicateEvaluator {
float _expectedValue;
public FloatNoDictionaryBasedEqualsEvaluator(EqPredicate predicate) {
_expectedValue = Float.parseFloat(predicate.getEqualsValue());
}
@Override
public boolean apply(float inputValue) {
return (_expectedValue == inputValue);
}
@Override
public boolean apply(float[] inputValues) {
return apply(inputValues, inputValues.length);
}
@Override
public boolean apply(float[] inputValues, int length) {
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int i = 0; i < length; i++) {
float inputValue = inputValues[i];
if (_expectedValue == inputValue) {
return true;
}
}
return false;
}
}
/**
*
* No dictionary equality evaluator for double data type.
*/
private static final class DoubleNoDictionaryBasedEqualsEvaluator extends BasePredicateEvaluator {
double _expectedValue;
public DoubleNoDictionaryBasedEqualsEvaluator(EqPredicate predicate) {
_expectedValue = Double.parseDouble(predicate.getEqualsValue());
}
@Override
public boolean apply(double inputValue) {
return (_expectedValue == inputValue);
}
@Override
public boolean apply(double[] inputValues) {
return apply(inputValues, inputValues.length);
}
@Override
public boolean apply(double[] inputValues, int length) {
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int i = 0; i < length; i++) {
double inputValue = inputValues[i];
if (_expectedValue == inputValue) {
return true;
}
}
return false;
}
}
/**
*
* No dictionary equality evaluator for string data type.
*/
private static final class StringNoDictionaryBasedEqualsEvaluator extends BasePredicateEvaluator {
String _expectedValue;
public StringNoDictionaryBasedEqualsEvaluator(EqPredicate predicate) {
_expectedValue = predicate.getEqualsValue();
}
@Override
public boolean apply(String inputValue) {
return (_expectedValue.equals(inputValue));
}
@Override
public boolean apply(String[] inputValues) {
return apply(inputValues, inputValues.length);
}
@Override
public boolean apply(String[] inputValues, int length) {
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int i = 0; i < length; i++) {
String inputValue = inputValues[i];
if (_expectedValue.equals(inputValue)) {
return true;
}
}
return false;
}
}
/**
*
* Dictionary Based Equals predicate Evaluator
*
*/
private static final class DictionaryBasedEqualsPredicateEvaluator extends BasePredicateEvaluator {
private int[] _matchingIds;
private int _equalsMatchDictId;
private EqPredicate _predicate;
public DictionaryBasedEqualsPredicateEvaluator(EqPredicate predicate, Dictionary dictionary) {
_predicate = predicate;
_equalsMatchDictId = dictionary.indexOf(predicate.getEqualsValue());
if (_equalsMatchDictId >= 0) {
_matchingIds = new int[1];
_matchingIds[0] = _equalsMatchDictId;
} else {
_matchingIds = new int[0];
}
}
@Override
public boolean apply(int dictionaryId) {
return (dictionaryId == _equalsMatchDictId);
}
@Override
public boolean apply(int[] dictionaryIds) {
if (_equalsMatchDictId < 0) {
return false;
}
// we cannot do binary search since the multi-value columns are not sorted in the raw segment
for (int dictId : dictionaryIds) {
if (dictId == _equalsMatchDictId) {
return true;
}
}
return false;
}
@Override
public int[] getMatchingDictionaryIds() {
return _matchingIds;
}
@Override
public int[] getNonMatchingDictionaryIds() {
throw new UnsupportedOperationException(
"Returning non matching values is expensive for predicateType:" + _predicate.getType());
}
@Override
public boolean apply(int[] dictionaryIds, int length) {
for (int i = 0; i < length; i++) {
int dictId = dictionaryIds[i];
if (dictId == _equalsMatchDictId) {
return true;
}
}
return false;
}
@Override
public boolean alwaysFalse() {
return _equalsMatchDictId < 0;
}
}
}