/** * 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.realtime.impl.dictionary; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.linkedin.pinot.common.data.FieldSpec; import com.linkedin.pinot.core.segment.index.readers.Dictionary; import java.util.concurrent.atomic.AtomicInteger; public abstract class MutableDictionaryReader implements Dictionary { private final String column; protected BiMap<Integer, Object> dictionaryIdBiMap; protected boolean hasNull = false; private final AtomicInteger dictionaryIdGenerator; public MutableDictionaryReader(String column) { this.column = column; this.dictionaryIdBiMap = HashBiMap.<Integer, Object> create(); dictionaryIdGenerator = new AtomicInteger(-1); } protected void addToDictionaryBiMap(Object val) { if (!dictionaryIdBiMap.inverse().containsKey(val)) { dictionaryIdBiMap.put(dictionaryIdGenerator.incrementAndGet(), val); } } @Override public int length() { return dictionaryIdGenerator.get() + 1; } @Override public void readIntValues(int[] dictionaryIds, int startPos, int limit, int[] outValues, int outStartPos) { readValues(dictionaryIds, startPos, limit, outValues, outStartPos, FieldSpec.DataType.INT); } @Override public void readLongValues(int[] dictionaryIds, int startPos, int limit, long[] outValues, int outStartPos) { readValues(dictionaryIds, startPos, limit, outValues, outStartPos, FieldSpec.DataType.LONG); } @Override public void readFloatValues(int[] dictionaryIds, int startPos, int limit, float[] outValues, int outStartPos) { readValues(dictionaryIds, startPos, limit, outValues, outStartPos, FieldSpec.DataType.FLOAT); } @Override public void readDoubleValues(int[] dictionaryIds, int startPos, int limit, double[] outValues, int outStartPos) { readValues(dictionaryIds, startPos, limit, outValues, outStartPos, FieldSpec.DataType.DOUBLE); } @Override public void readStringValues(int[] dictionaryIds, int startPos, int limit, String[] outValues, int outStartPos) { readValues(dictionaryIds, startPos, limit, outValues, outStartPos, FieldSpec.DataType.STRING); } protected void readValues(int[] dictionaryIds, int startPos, int limit, Object values, int outStartPos, FieldSpec.DataType type) { int endPos = startPos + limit; switch (type) { case INT: { int[] outValues = (int[]) values; for (int iter = startPos; iter < endPos; ++iter) { int dictId = dictionaryIds[iter]; outValues[outStartPos++] = getIntValue(dictId); } } break; case LONG: { long[] outValues = (long[]) values; for (int iter = startPos; iter < endPos; ++iter) { int dictId = dictionaryIds[iter]; outValues[outStartPos++] = getLongValue(dictId); } } break; case FLOAT: { float[] outValues = (float[]) values; for (int iter = startPos; iter < endPos; ++iter) { int dictId = dictionaryIds[iter]; outValues[outStartPos++] = getFloatValue(dictId); } } break; case DOUBLE: { double[] outValues = (double[]) values; for (int iter = startPos; iter < endPos; ++iter) { int dictId = dictionaryIds[iter]; outValues[outStartPos++] = getDoubleValue(dictId); } } break; case STRING: { String[] outValues = (String[]) values; for (int iter = startPos; iter < endPos; ++iter) { int dictId = dictionaryIds[iter]; outValues[outStartPos++] = getStringValue(dictId); } } break; } } public abstract Object getSortedValues(); protected Integer getIndexOfFromBiMap(Object val) { Integer ret = dictionaryIdBiMap.inverse().get(val); if (ret == null) { ret = -1; } return ret; } protected Object getRawValueFromBiMap(int dictionaryId) { return dictionaryIdBiMap.get(new Integer(dictionaryId)); } public boolean hasNull() { return hasNull; } public abstract Object getMinVal(); public abstract Object getMaxVal(); public abstract void index(Object rawValue); @Override public abstract int indexOf(Object rawValue); public abstract boolean contains(Object o); @Override public abstract Object get(int dictionaryId); public abstract boolean inRange(String lower, String upper, int indexOfValueToCompare, boolean includeLower, boolean includeUpper); public boolean inRange(String lower, String upper, int valueToCompare) { return inRange(lower, upper, valueToCompare, true, true); } @Override public abstract long getLongValue(int dictionaryId); @Override public abstract double getDoubleValue(int dictionaryId); @Override public abstract int getIntValue(int dictionaryId); @Override public abstract float getFloatValue(int dictionaryId); public void print() { System.out.println("************* printing dictionary for column : " + column + " ***************"); for (Integer key : dictionaryIdBiMap.keySet()) { System.out.println(key + "," + dictionaryIdBiMap.get(key)); } System.out.println("************************************"); } public boolean isEmpty() { return dictionaryIdBiMap.isEmpty(); } }