/**
* 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.predicate;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.linkedin.pinot.core.common.predicate.RangePredicate;
import com.linkedin.pinot.core.operator.filter.predicate.PredicateEvaluator;
import com.linkedin.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory;
import com.linkedin.pinot.core.segment.index.readers.ImmutableDictionaryReader;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class RangeOfflineDictionaryPredicateEvaluatorTest {
private static final int DICT_LEN = 10;
@Test
public void testRanges() {
int rangeStart, rangeEnd;
{
// (2,5)
rangeStart = 2;
rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, true, rangeEnd, true);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertTrue(evaluator.apply(rangeStart));
Assert.assertTrue(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
Assert.assertFalse(evaluator.apply(rangeEnd+1));
int[] dictIds = new int[]{1, 3, 7};
Assert.assertTrue(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart, rangeEnd);
}
{
// [2,5)
rangeStart = 2; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, false, rangeEnd, true);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertFalse(evaluator.apply(rangeStart));
Assert.assertTrue(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
Assert.assertFalse(evaluator.apply(rangeEnd+1));
int[] dictIds = new int[]{1, 3, 7};
Assert.assertTrue(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart + 1, rangeEnd);
}
{
// (2,5]
rangeStart = 2; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, true, rangeEnd, false);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertTrue(evaluator.apply(rangeStart));
Assert.assertFalse(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
Assert.assertFalse(evaluator.apply(rangeEnd + 1));
int[] dictIds = new int[]{1, 3, 7};
Assert.assertTrue(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart, rangeEnd - 1);
}
{
// [2,5]
rangeStart = 2; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, false, rangeEnd, false);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertFalse(evaluator.apply(rangeStart));
Assert.assertFalse(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
Assert.assertFalse(evaluator.apply(rangeEnd + 1));
int[] dictIds = new int[]{1, 3, 7};
Assert.assertTrue(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart + 1, rangeEnd - 1);
}
}
private void verifyDictId(int[] dictIds, int start, int end) {
Assert.assertEquals(dictIds.length, end - start +1);
for (int i = 0; i < dictIds.length; i++) {
Assert.assertEquals(dictIds[i], start);
start++;
}
}
@Test
public void testBoundaries() {
int rangeStart, rangeEnd;
{
// (0,5]
rangeStart = 0; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, true, rangeEnd, false);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertTrue(evaluator.apply(rangeStart));
Assert.assertFalse(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeEnd+1));
int[] dictIds = new int[]{5, 7, 9};
Assert.assertFalse(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart, rangeEnd - 1);
}
{
// (0,5)
rangeStart = 0; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, true, rangeEnd, true);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertTrue(evaluator.apply(rangeStart));
Assert.assertTrue(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeEnd+1));
}
{
// (6, DICT_LEN-1)
rangeStart = 6; rangeEnd = DICT_LEN-1;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, true, rangeEnd, true);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertTrue(evaluator.apply(rangeStart));
Assert.assertTrue(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart + 1));
Assert.assertFalse(evaluator.apply(rangeStart - 1));
int[] dictIds = new int[]{5, 7, 9};
Assert.assertTrue(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart, rangeEnd);
}
{
// [6, DICT_LEN-1)
rangeStart = 6; rangeEnd = DICT_LEN-1;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, false, rangeEnd, true);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertFalse(evaluator.alwaysFalse());
Assert.assertFalse(evaluator.apply(rangeStart));
Assert.assertTrue(evaluator.apply(rangeEnd));
Assert.assertTrue(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
}
}
@Test
public void testZeroRange() {
int rangeStart, rangeEnd;
{
rangeStart = 4; rangeEnd = 5;
ImmutableDictionaryReader reader = createReader(rangeStart, rangeEnd);
RangePredicate predicate = createPredicate(rangeStart, false, rangeEnd, false);
PredicateEvaluator evaluator = RangePredicateEvaluatorFactory.newOfflineDictionaryBasedEvaluator(predicate, reader);
Assert.assertTrue(evaluator.alwaysFalse());
Assert.assertFalse(evaluator.apply(rangeStart));
Assert.assertFalse(evaluator.apply(rangeEnd));
Assert.assertFalse(evaluator.apply(rangeStart+1));
Assert.assertFalse(evaluator.apply(rangeStart-1));
int[] dictIds = new int[]{5, 7, 9};
Assert.assertFalse(evaluator.apply(dictIds));
Assert.assertFalse(evaluator.apply(dictIds, 1));
dictIds = evaluator.getMatchingDictionaryIds();
verifyDictId(dictIds, rangeStart+1, rangeEnd-1);
}
}
private ImmutableDictionaryReader createReader(int rangeStart, int rangeEnd) {
ImmutableDictionaryReader reader = mock(ImmutableDictionaryReader.class);
when(reader.indexOf("lower")).thenReturn(rangeStart);
when(reader.indexOf("upper")).thenReturn(rangeEnd);
when(reader.length()).thenReturn(DICT_LEN);
return reader;
}
private RangePredicate createPredicate(int lower, boolean inclLower, int upper, boolean inclUpper) {
RangePredicate predicate = mock(RangePredicate.class);
when(predicate.includeLowerBoundary()).thenReturn(inclLower);
when(predicate.includeUpperBoundary()).thenReturn(inclUpper);
String lowerStr = "lower";
if (lower == 0) {
lowerStr = "*";
}
String upperStr = "upper";
if (upper == DICT_LEN-1) {
upperStr = "*";
}
when(predicate.getLowerBoundary()).thenReturn(lowerStr);
when(predicate.getUpperBoundary()).thenReturn(upperStr);
return predicate;
}
}