blob: e0b126d94ffe11f12ada75aadd19a1875c29c78b [file] [log] [blame]
package org.apache.lucene.index.values;
/**
* 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.
*/
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.ReaderUtil;
/**
* A wrapper for compound IndexReader providing access to per segment
* {@link IndexDocValues}
*
* @lucene.experimental
*/
public class MultiIndexDocValues extends IndexDocValues {
public static class DocValuesIndex {
public final static DocValuesIndex[] EMPTY_ARRAY = new DocValuesIndex[0];
final int start;
final int length;
final IndexDocValues docValues;
public DocValuesIndex(IndexDocValues docValues, int start, int length) {
this.docValues = docValues;
this.start = start;
this.length = length;
}
}
private DocValuesIndex[] docValuesIdx;
private int[] starts;
public MultiIndexDocValues() {
starts = new int[0];
docValuesIdx = new DocValuesIndex[0];
}
public MultiIndexDocValues(DocValuesIndex[] docValuesIdx) {
reset(docValuesIdx);
}
@Override
public ValuesEnum getEnum(AttributeSource source) throws IOException {
return new MultiValuesEnum(docValuesIdx, starts);
}
@Override
public Source load() throws IOException {
return new MultiSource(docValuesIdx, starts);
}
public IndexDocValues reset(DocValuesIndex[] docValuesIdx) {
int[] start = new int[docValuesIdx.length];
for (int i = 0; i < docValuesIdx.length; i++) {
start[i] = docValuesIdx[i].start;
}
this.starts = start;
this.docValuesIdx = docValuesIdx;
return this;
}
public static class DummyDocValues extends IndexDocValues {
final int maxDoc;
final Source emptySoruce;
public DummyDocValues(int maxDoc, ValueType type) {
this.maxDoc = maxDoc;
this.emptySoruce = new EmptySource(type);
}
@Override
public ValuesEnum getEnum(AttributeSource attrSource) throws IOException {
return emptySoruce.getEnum(attrSource);
}
@Override
public Source load() throws IOException {
return emptySoruce;
}
@Override
public ValueType type() {
return emptySoruce.type();
}
}
private static class MultiValuesEnum extends ValuesEnum {
private DocValuesIndex[] docValuesIdx;
private final int maxDoc;
private int currentStart;
private int currentMax;
private int currentDoc = -1;
private ValuesEnum currentEnum;
private final int[] starts;
public MultiValuesEnum(DocValuesIndex[] docValuesIdx, int[] starts)
throws IOException {
super(docValuesIdx[0].docValues.type());
this.docValuesIdx = docValuesIdx;
final DocValuesIndex last = docValuesIdx[docValuesIdx.length - 1];
maxDoc = last.start + last.length;
final DocValuesIndex idx = docValuesIdx[0];
currentEnum = idx.docValues.getEnum(this.attributes());
currentEnum.copyFrom(this);
intsRef = currentEnum.intsRef;
currentMax = idx.length;
currentStart = 0;
this.starts = starts;
}
@Override
public void close() throws IOException {
currentEnum.close();
}
@Override
public int advance(int target) throws IOException {
assert target > currentDoc : "target " + target
+ " must be > than the current doc " + currentDoc;
int relativeDoc = target - currentStart;
do {
if (target >= maxDoc) {// we are beyond max doc
return currentDoc = NO_MORE_DOCS;
}
if (target >= currentMax) {
final int idx = ReaderUtil.subIndex(target, starts);
currentEnum.close();
currentEnum = docValuesIdx[idx].docValues.getEnum();
currentEnum.copyFrom(this);
currentStart = docValuesIdx[idx].start;
currentMax = currentStart + docValuesIdx[idx].length;
relativeDoc = target - currentStart;
}
target = currentMax; // make sure that we advance to the next enum if the current is exhausted
} while ((relativeDoc = currentEnum.advance(relativeDoc)) == NO_MORE_DOCS);
return currentDoc = currentStart + relativeDoc;
}
@Override
public int docID() {
return currentDoc;
}
@Override
public int nextDoc() throws IOException {
return advance(currentDoc + 1);
}
}
private static class MultiSource extends Source {
private int numDocs = 0;
private int start = 0;
private Source current;
private final int[] starts;
private final DocValuesIndex[] docValuesIdx;
public MultiSource(DocValuesIndex[] docValuesIdx, int[] starts) {
this.docValuesIdx = docValuesIdx;
this.starts = starts;
assert docValuesIdx.length != 0;
}
public long getInt(int docID) {
final int doc = ensureSource(docID);
return current.getInt(doc);
}
private final int ensureSource(int docID) {
if (docID >= start && docID < start+numDocs) {
return docID - start;
} else {
final int idx = ReaderUtil.subIndex(docID, starts);
assert idx >= 0 && idx < docValuesIdx.length : "idx was " + idx
+ " for doc id: " + docID + " slices : " + Arrays.toString(starts);
assert docValuesIdx[idx] != null;
try {
current = docValuesIdx[idx].docValues.getSource();
} catch (IOException e) {
throw new RuntimeException("load failed", e); // TODO how should we
// handle this
}
start = docValuesIdx[idx].start;
numDocs = docValuesIdx[idx].length;
return docID - start;
}
}
public double getFloat(int docID) {
final int doc = ensureSource(docID);
return current.getFloat(doc);
}
public BytesRef getBytes(int docID, BytesRef bytesRef) {
final int doc = ensureSource(docID);
return current.getBytes(doc, bytesRef);
}
@Override
public ValuesEnum getEnum(AttributeSource attrSource) throws IOException {
throw new UnsupportedOperationException(); // TODO
}
@Override
public ValueType type() {
return docValuesIdx[0].docValues.type();
}
}
private static class EmptySource extends Source {
private final ValueType type;
public EmptySource(ValueType type) {
this.type = type;
}
@Override
public BytesRef getBytes(int docID, BytesRef ref) {
ref.length = 0;
return ref;
}
@Override
public double getFloat(int docID) {
return 0d;
}
@Override
public long getInt(int docID) {
return 0;
}
@Override
public ValuesEnum getEnum(AttributeSource attrSource) throws IOException {
return ValuesEnum.emptyEnum(type);
}
@Override
public ValueType type() {
return type;
}
}
@Override
public ValueType type() {
return this.docValuesIdx[0].docValues.type();
}
}