|
@@ -24,6 +24,7 @@ import org.apache.lucene.index.ImpactsEnum;
|
|
|
import org.apache.lucene.index.IndexFileNames;
|
|
|
import org.apache.lucene.index.NumericDocValues;
|
|
|
import org.apache.lucene.index.PostingsEnum;
|
|
|
+import org.apache.lucene.index.SegmentInfo;
|
|
|
import org.apache.lucene.index.SegmentReadState;
|
|
|
import org.apache.lucene.index.SortedDocValues;
|
|
|
import org.apache.lucene.index.SortedNumericDocValues;
|
|
@@ -31,6 +32,7 @@ import org.apache.lucene.index.SortedSetDocValues;
|
|
|
import org.apache.lucene.index.TermsEnum;
|
|
|
import org.apache.lucene.internal.hppc.IntObjectHashMap;
|
|
|
import org.apache.lucene.search.DocIdSetIterator;
|
|
|
+import org.apache.lucene.search.SortField;
|
|
|
import org.apache.lucene.store.ByteArrayDataInput;
|
|
|
import org.apache.lucene.store.ChecksumIndexInput;
|
|
|
import org.apache.lucene.store.DataInput;
|
|
@@ -53,7 +55,7 @@ import static org.elasticsearch.index.codec.tsdb.es819.ES819TSDBDocValuesFormat.
|
|
|
|
|
|
final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
final IntObjectHashMap<NumericEntry> numerics;
|
|
|
- private int primarySortFieldNumber = -1;
|
|
|
+ private final int primarySortFieldNumber;
|
|
|
final IntObjectHashMap<BinaryEntry> binaries;
|
|
|
final IntObjectHashMap<SortedEntry> sorted;
|
|
|
final IntObjectHashMap<SortedSetEntry> sortedSets;
|
|
@@ -73,11 +75,13 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
this.sortedNumerics = new IntObjectHashMap<>();
|
|
|
this.skippers = new IntObjectHashMap<>();
|
|
|
this.maxDoc = state.segmentInfo.maxDoc();
|
|
|
+ this.primarySortFieldNumber = primarySortFieldNumber(state.segmentInfo, state.fieldInfos);
|
|
|
this.merging = false;
|
|
|
|
|
|
// read in the entries from the metadata file.
|
|
|
int version = -1;
|
|
|
String metaName = IndexFileNames.segmentFileName(state.segmentInfo.name, state.segmentSuffix, metaExtension);
|
|
|
+
|
|
|
try (ChecksumIndexInput in = state.directory.openChecksumInput(metaName)) {
|
|
|
Throwable priorE = null;
|
|
|
|
|
@@ -92,14 +96,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
);
|
|
|
|
|
|
readFields(in, state.fieldInfos);
|
|
|
- final var indexSort = state.segmentInfo.getIndexSort();
|
|
|
- if (indexSort != null && indexSort.getSort().length > 0) {
|
|
|
- var primarySortField = indexSort.getSort()[0];
|
|
|
- var sortField = state.fieldInfos.fieldInfo(primarySortField.getField());
|
|
|
- if (sortField != null) {
|
|
|
- primarySortFieldNumber = sortField.number;
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
} catch (Throwable exception) {
|
|
|
priorE = exception;
|
|
|
} finally {
|
|
@@ -148,6 +145,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
IndexInput data,
|
|
|
int maxDoc,
|
|
|
int version,
|
|
|
+ int primarySortFieldNumber,
|
|
|
boolean merging
|
|
|
) {
|
|
|
this.numerics = numerics;
|
|
@@ -159,6 +157,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
this.data = data.clone();
|
|
|
this.maxDoc = maxDoc;
|
|
|
this.version = version;
|
|
|
+ this.primarySortFieldNumber = primarySortFieldNumber;
|
|
|
this.merging = merging;
|
|
|
}
|
|
|
|
|
@@ -174,6 +173,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
data,
|
|
|
maxDoc,
|
|
|
version,
|
|
|
+ primarySortFieldNumber,
|
|
|
true
|
|
|
);
|
|
|
}
|
|
@@ -467,6 +467,47 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
}
|
|
|
|
|
|
abstract static class BaseDenseNumericValues extends NumericDocValues implements BlockLoader.OptionalColumnAtATimeReader {
|
|
|
+ private final int maxDoc;
|
|
|
+ protected int doc = -1;
|
|
|
+
|
|
|
+ BaseDenseNumericValues(int maxDoc) {
|
|
|
+ this.maxDoc = maxDoc;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int docID() {
|
|
|
+ return doc;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int nextDoc() throws IOException {
|
|
|
+ return advance(doc + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int advance(int target) throws IOException {
|
|
|
+ if (target >= maxDoc) {
|
|
|
+ return doc = NO_MORE_DOCS;
|
|
|
+ }
|
|
|
+ return doc = target;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final boolean advanceExact(int target) {
|
|
|
+ doc = target;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final long cost() {
|
|
|
+ return maxDoc;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
abstract long lookAheadValueAt(int targetDoc) throws IOException;
|
|
|
|
|
|
BlockLoader.Block tryRead(BlockLoader.SingletonLongBuilder builder, BlockLoader.Docs docs, int offset) throws IOException {
|
|
@@ -474,6 +515,39 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ abstract static class BaseSparseNumericValues extends NumericDocValues {
|
|
|
+ protected final IndexedDISI disi;
|
|
|
+
|
|
|
+ BaseSparseNumericValues(IndexedDISI disi) {
|
|
|
+ this.disi = disi;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int advance(int target) throws IOException {
|
|
|
+ return disi.advance(target);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final boolean advanceExact(int target) throws IOException {
|
|
|
+ return disi.advanceExact(target);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int nextDoc() throws IOException {
|
|
|
+ return disi.nextDoc();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int docID() {
|
|
|
+ return disi.docID();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final long cost() {
|
|
|
+ return disi.cost();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
abstract static class BaseSortedSetDocValues extends SortedSetDocValues {
|
|
|
|
|
|
final SortedSetEntry entry;
|
|
@@ -939,6 +1013,24 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
data.close();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the field number of the primary sort field for the given segment,
|
|
|
+ * if the field is sorted in ascending order. Returns {@code -1} if not found.
|
|
|
+ */
|
|
|
+ static int primarySortFieldNumber(SegmentInfo segmentInfo, FieldInfos fieldInfos) {
|
|
|
+ final var indexSort = segmentInfo.getIndexSort();
|
|
|
+ if (indexSort != null && indexSort.getSort().length > 0) {
|
|
|
+ SortField sortField = indexSort.getSort()[0];
|
|
|
+ if (sortField.getReverse() == false) {
|
|
|
+ FieldInfo fieldInfo = fieldInfos.fieldInfo(sortField.getField());
|
|
|
+ if (fieldInfo != null) {
|
|
|
+ return fieldInfo.number;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
private void readFields(IndexInput meta, FieldInfos infos) throws IOException {
|
|
|
for (int fieldNumber = meta.readInt(); fieldNumber != -1; fieldNumber = meta.readInt()) {
|
|
|
FieldInfo info = infos.fieldInfo(fieldNumber);
|
|
@@ -988,9 +1080,14 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
entry.numDocsWithField = meta.readInt();
|
|
|
if (entry.numValues > 0) {
|
|
|
final int indexBlockShift = meta.readInt();
|
|
|
- // Special case, -1 means there are no blocks, so no need to load the metadata for it
|
|
|
- // -1 is written when there the cardinality of a field is exactly one.
|
|
|
- if (indexBlockShift != -1) {
|
|
|
+ if (indexBlockShift == -1) {
|
|
|
+ // single ordinal, no block index
|
|
|
+ } else if (indexBlockShift == -2) {
|
|
|
+ // encoded ordinal range, no block index
|
|
|
+ final int numOrds = meta.readVInt();
|
|
|
+ final int blockShift = meta.readByte();
|
|
|
+ entry.sortedOrdinals = DirectMonotonicReader.loadMeta(meta, numOrds + 1, blockShift);
|
|
|
+ } else {
|
|
|
entry.indexMeta = DirectMonotonicReader.loadMeta(
|
|
|
meta,
|
|
|
1 + ((entry.numValues - 1) >>> ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SHIFT),
|
|
@@ -1103,6 +1200,49 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
abstract long advance(long index) throws IOException;
|
|
|
}
|
|
|
|
|
|
+ static final class SortedOrdinalReader {
|
|
|
+ final long maxOrd;
|
|
|
+ final DirectMonotonicReader startDocs;
|
|
|
+ private long currentIndex = -1;
|
|
|
+ private long rangeEndExclusive = -1;
|
|
|
+
|
|
|
+ SortedOrdinalReader(long maxOrd, DirectMonotonicReader startDocs) {
|
|
|
+ this.maxOrd = maxOrd;
|
|
|
+ this.startDocs = startDocs;
|
|
|
+ }
|
|
|
+
|
|
|
+ long readValueAndAdvance(int doc) {
|
|
|
+ if (doc < rangeEndExclusive) {
|
|
|
+ return currentIndex;
|
|
|
+ }
|
|
|
+ // move to the next range
|
|
|
+ if (doc == rangeEndExclusive) {
|
|
|
+ currentIndex++;
|
|
|
+ } else {
|
|
|
+ currentIndex = searchRange(doc);
|
|
|
+ }
|
|
|
+ rangeEndExclusive = startDocs.get(currentIndex + 1);
|
|
|
+ return currentIndex;
|
|
|
+ }
|
|
|
+
|
|
|
+ private long searchRange(int doc) {
|
|
|
+ long index = startDocs.binarySearch(currentIndex + 1, maxOrd, doc);
|
|
|
+ if (index < 0) {
|
|
|
+ index = -2 - index;
|
|
|
+ }
|
|
|
+ assert index < maxOrd : "invalid range " + index + " for doc " + doc + " in maxOrd " + maxOrd;
|
|
|
+ return index;
|
|
|
+ }
|
|
|
+
|
|
|
+ long lookAheadValue(int targetDoc) {
|
|
|
+ if (targetDoc < rangeEndExclusive) {
|
|
|
+ return currentIndex;
|
|
|
+ } else {
|
|
|
+ return searchRange(targetDoc);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private NumericDocValues getNumeric(NumericEntry entry, long maxOrd) throws IOException {
|
|
|
if (entry.docsWithFieldOffset == -2) {
|
|
|
// empty
|
|
@@ -1113,56 +1253,17 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
// Special case for maxOrd 1, no need to read blocks and use ordinal 0 as only value
|
|
|
if (entry.docsWithFieldOffset == -1) {
|
|
|
// Special case when all docs have a value
|
|
|
- return new BaseDenseNumericValues() {
|
|
|
-
|
|
|
- private final int maxDoc = ES819TSDBDocValuesProducer.this.maxDoc;
|
|
|
- private int doc = -1;
|
|
|
-
|
|
|
+ return new BaseDenseNumericValues(maxDoc) {
|
|
|
@Override
|
|
|
public long longValue() {
|
|
|
// Only one ordinal!
|
|
|
return 0L;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public int docID() {
|
|
|
- return doc;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int nextDoc() throws IOException {
|
|
|
- return advance(doc + 1);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int advance(int target) throws IOException {
|
|
|
- if (target >= maxDoc) {
|
|
|
- return doc = NO_MORE_DOCS;
|
|
|
- }
|
|
|
- return doc = target;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean advanceExact(int target) {
|
|
|
- doc = target;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public long cost() {
|
|
|
- return maxDoc;
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
long lookAheadValueAt(int targetDoc) throws IOException {
|
|
|
return 0L; // Only one ordinal!
|
|
|
}
|
|
|
-
|
|
|
- @Override
|
|
|
- public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset)
|
|
|
- throws IOException {
|
|
|
- return null;
|
|
|
- }
|
|
|
};
|
|
|
} else {
|
|
|
final IndexedDISI disi = new IndexedDISI(
|
|
@@ -1173,36 +1274,47 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
entry.denseRankPower,
|
|
|
entry.numValues
|
|
|
);
|
|
|
- return new NumericDocValues() {
|
|
|
-
|
|
|
- @Override
|
|
|
- public int advance(int target) throws IOException {
|
|
|
- return disi.advance(target);
|
|
|
- }
|
|
|
-
|
|
|
+ return new BaseSparseNumericValues(disi) {
|
|
|
@Override
|
|
|
- public boolean advanceExact(int target) throws IOException {
|
|
|
- return disi.advanceExact(target);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int nextDoc() throws IOException {
|
|
|
- return disi.nextDoc();
|
|
|
+ public long longValue() throws IOException {
|
|
|
+ return 0L; // Only one ordinal!
|
|
|
}
|
|
|
-
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } else if (entry.sortedOrdinals != null) {
|
|
|
+ final var ordinalsReader = new SortedOrdinalReader(
|
|
|
+ maxOrd,
|
|
|
+ DirectMonotonicReader.getInstance(
|
|
|
+ entry.sortedOrdinals,
|
|
|
+ data.randomAccessSlice(entry.valuesOffset, entry.valuesLength),
|
|
|
+ true
|
|
|
+ )
|
|
|
+ );
|
|
|
+ if (entry.docsWithFieldOffset == -1) {
|
|
|
+ return new BaseDenseNumericValues(maxDoc) {
|
|
|
@Override
|
|
|
- public int docID() {
|
|
|
- return disi.docID();
|
|
|
+ long lookAheadValueAt(int targetDoc) {
|
|
|
+ return ordinalsReader.lookAheadValue(targetDoc);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public long cost() {
|
|
|
- return disi.cost();
|
|
|
+ public long longValue() {
|
|
|
+ return ordinalsReader.readValueAndAdvance(doc);
|
|
|
}
|
|
|
-
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ final var disi = new IndexedDISI(
|
|
|
+ data,
|
|
|
+ entry.docsWithFieldOffset,
|
|
|
+ entry.docsWithFieldLength,
|
|
|
+ entry.jumpTableEntryCount,
|
|
|
+ entry.denseRankPower,
|
|
|
+ entry.numValues
|
|
|
+ );
|
|
|
+ return new BaseSparseNumericValues(disi) {
|
|
|
@Override
|
|
|
public long longValue() {
|
|
|
- return 0L;
|
|
|
+ return ordinalsReader.readValueAndAdvance(disi.docID());
|
|
|
}
|
|
|
};
|
|
|
}
|
|
@@ -1218,10 +1330,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
final int bitsPerOrd = maxOrd >= 0 ? PackedInts.bitsRequired(maxOrd - 1) : -1;
|
|
|
if (entry.docsWithFieldOffset == -1) {
|
|
|
// dense
|
|
|
- return new BaseDenseNumericValues() {
|
|
|
-
|
|
|
- private final int maxDoc = ES819TSDBDocValuesProducer.this.maxDoc;
|
|
|
- private int doc = -1;
|
|
|
+ return new BaseDenseNumericValues(maxDoc) {
|
|
|
private final TSDBDocValuesEncoder decoder = new TSDBDocValuesEncoder(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE);
|
|
|
private long currentBlockIndex = -1;
|
|
|
private final long[] currentBlock = new long[ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE];
|
|
@@ -1230,35 +1339,6 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
private long[] lookaheadBlock;
|
|
|
private IndexInput lookaheadData = null;
|
|
|
|
|
|
- @Override
|
|
|
- public int docID() {
|
|
|
- return doc;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int nextDoc() throws IOException {
|
|
|
- return advance(doc + 1);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int advance(int target) throws IOException {
|
|
|
- if (target >= maxDoc) {
|
|
|
- return doc = NO_MORE_DOCS;
|
|
|
- }
|
|
|
- return doc = target;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean advanceExact(int target) {
|
|
|
- doc = target;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public long cost() {
|
|
|
- return maxDoc;
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public long longValue() throws IOException {
|
|
|
final int index = doc;
|
|
@@ -1374,37 +1454,11 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
entry.denseRankPower,
|
|
|
entry.numValues
|
|
|
);
|
|
|
- return new NumericDocValues() {
|
|
|
-
|
|
|
+ return new BaseSparseNumericValues(disi) {
|
|
|
private final TSDBDocValuesEncoder decoder = new TSDBDocValuesEncoder(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE);
|
|
|
private long currentBlockIndex = -1;
|
|
|
private final long[] currentBlock = new long[ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE];
|
|
|
|
|
|
- @Override
|
|
|
- public int advance(int target) throws IOException {
|
|
|
- return disi.advance(target);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean advanceExact(int target) throws IOException {
|
|
|
- return disi.advanceExact(target);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int nextDoc() throws IOException {
|
|
|
- return disi.nextDoc();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int docID() {
|
|
|
- return disi.docID();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public long cost() {
|
|
|
- return disi.cost();
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public long longValue() throws IOException {
|
|
|
final int index = disi.index();
|
|
@@ -1610,6 +1664,7 @@ final class ES819TSDBDocValuesProducer extends DocValuesProducer {
|
|
|
DirectMonotonicReader.Meta indexMeta;
|
|
|
long valuesOffset;
|
|
|
long valuesLength;
|
|
|
+ DirectMonotonicReader.Meta sortedOrdinals;
|
|
|
}
|
|
|
|
|
|
static class BinaryEntry {
|