/** * 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.docidsets; import com.linkedin.pinot.common.utils.Pairs; import com.linkedin.pinot.core.common.BlockDocIdIterator; import com.linkedin.pinot.core.common.BlockDocIdSet; import com.linkedin.pinot.core.operator.dociditerators.BitmapDocIdIterator; import com.linkedin.pinot.core.operator.dociditerators.OrDocIdIterator; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.roaringbitmap.IntIterator; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmap; public final class OrBlockDocIdSet implements FilterBlockDocIdSet { /** * */ final public AtomicLong timeMeasure = new AtomicLong(0); private List<FilterBlockDocIdSet> docIdSets; private int maxDocId = Integer.MIN_VALUE; private int minDocId = Integer.MAX_VALUE; private IntIterator intIterator; private BlockDocIdIterator[] docIdIterators; public OrBlockDocIdSet(List<FilterBlockDocIdSet> blockDocIdSets) { this.docIdSets = blockDocIdSets; updateMinMaxRange(); } private void updateMinMaxRange() { for (FilterBlockDocIdSet blockDocIdSet : docIdSets) { minDocId = Math.min(minDocId, blockDocIdSet.getMinDocId()); maxDocId = Math.max(maxDocId, blockDocIdSet.getMaxDocId()); } for (FilterBlockDocIdSet blockDocIdSet : docIdSets) { blockDocIdSet.setStartDocId(minDocId); blockDocIdSet.setEndDocId(maxDocId); } } @Override public int getMaxDocId() { return maxDocId; } @Override public int getMinDocId() { return minDocId; } @Override public BlockDocIdIterator iterator() { List<BlockDocIdIterator> rawIterators = new ArrayList<>(); boolean useBitmapOr = false; for (BlockDocIdSet docIdSet : docIdSets) { if (docIdSet instanceof BitmapDocIdSet) { useBitmapOr = true; } } if (useBitmapOr) { List<ImmutableRoaringBitmap> allBitmaps = new ArrayList<ImmutableRoaringBitmap>(); for (BlockDocIdSet docIdSet : docIdSets) { if (docIdSet instanceof SortedDocIdSet) { MutableRoaringBitmap bitmap = new MutableRoaringBitmap(); SortedDocIdSet sortedDocIdSet = (SortedDocIdSet) docIdSet; List<Pairs.IntPair> pairs = sortedDocIdSet.getRaw(); for (Pairs.IntPair pair : pairs) { bitmap.add(pair.getLeft(), pair.getRight() + 1); //add takes [start, end) i.e inclusive start, exclusive end. } allBitmaps.add(bitmap); } else if (docIdSet instanceof BitmapDocIdSet) { BitmapDocIdSet bitmapDocIdSet = (BitmapDocIdSet) docIdSet; ImmutableRoaringBitmap childBitmap = bitmapDocIdSet.getRaw(); allBitmaps.add(childBitmap); } else { BlockDocIdIterator iterator = docIdSet.iterator(); rawIterators.add(iterator); } } MutableRoaringBitmap answer = allBitmaps.get(0).toMutableRoaringBitmap(); for (int i = 1; i < allBitmaps.size(); i++) { answer.or(allBitmaps.get(i)); } intIterator = answer.getIntIterator(); BitmapDocIdIterator singleBitmapBlockIdIterator = new BitmapDocIdIterator(intIterator); singleBitmapBlockIdIterator.setStartDocId(minDocId); singleBitmapBlockIdIterator.setEndDocId(maxDocId); rawIterators.add(singleBitmapBlockIdIterator); docIdIterators = new BlockDocIdIterator[rawIterators.size()]; rawIterators.toArray(docIdIterators); } else { docIdIterators = new BlockDocIdIterator[docIdSets.size()]; for (int srcId = 0; srcId < docIdSets.size(); srcId++) { docIdIterators[srcId] = docIdSets.get(srcId).iterator(); } } // if (docIdIterators.length == 1) { // return docIdIterators[0]; // } else { OrDocIdIterator orDocIdIterator = new OrDocIdIterator(docIdIterators); orDocIdIterator.setStartDocId(minDocId); orDocIdIterator.setEndDocId(maxDocId); return orDocIdIterator; // } } @SuppressWarnings("unchecked") @Override public <T> T getRaw() { return (T) this.docIdSets; } @Override public void setStartDocId(int startDocId) { minDocId = Math.min(minDocId, startDocId); updateMinMaxRange(); } @Override public void setEndDocId(int endDocId) { maxDocId = Math.max(maxDocId, endDocId); updateMinMaxRange(); } @Override public long getNumEntriesScannedInFilter() { long numEntriesScannedInFilter = 0L; for (FilterBlockDocIdSet docIdSet : docIdSets) { numEntriesScannedInFilter += docIdSet.getNumEntriesScannedInFilter(); } return numEntriesScannedInFilter; } }