Skip to content

Commit 8137db1

Browse files
committed
Speed up loading dense singleton keyword fields
1 parent 8278266 commit 8137db1

File tree

8 files changed

+321
-100
lines changed

8 files changed

+321
-100
lines changed

server/src/main/java/org/elasticsearch/index/codec/tsdb/es819/ES819TSDBDocValuesProducer.java

Lines changed: 120 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ public SortedDocValues getSorted(FieldInfo field) throws IOException {
345345
}
346346

347347
private SortedDocValues getSorted(SortedEntry entry, boolean valuesSorted) throws IOException {
348+
if (entry.ordsEntry.docsWithFieldOffset == -2) {
349+
return DocValues.emptySorted();
350+
}
351+
348352
final NumericDocValues ords = getNumeric(entry.ordsEntry, entry.termsDictEntry.termsDictSize);
349353
return new BaseSortedDocValues(entry) {
350354

@@ -380,19 +384,29 @@ public long cost() {
380384

381385
@Override
382386
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
383-
if (valuesSorted && ords instanceof BaseDenseNumericValues denseOrds) {
384-
int firstDoc = docs.get(offset);
385-
denseOrds.advanceExact(firstDoc);
386-
long startValue = denseOrds.longValue();
387-
final int docCount = docs.count();
388-
int lastDoc = docs.get(docCount - 1);
389-
long lastValue = denseOrds.lookAheadValueAt(lastDoc);
390-
if (lastValue == startValue) {
391-
BytesRef b = lookupOrd(Math.toIntExact(startValue));
392-
return factory.constantBytes(BytesRef.deepCopyOf(b), docCount - offset);
387+
if (ords instanceof BaseDenseNumericValues denseOrds) {
388+
if (valuesSorted || entry.termsDictEntry.termsDictSize == 1) {
389+
int firstDoc = docs.get(offset);
390+
denseOrds.advanceExact(firstDoc);
391+
long startValue = denseOrds.longValue();
392+
final int docCount = docs.count();
393+
int lastDoc = docs.get(docCount - 1);
394+
long lastValue = denseOrds.lookAheadValueAt(lastDoc);
395+
if (lastValue == startValue) {
396+
BytesRef b = lookupOrd(Math.toIntExact(startValue));
397+
return factory.constantBytes(BytesRef.deepCopyOf(b), docCount - offset);
398+
}
399+
// TODO: Since ordinals are sorted, start at 0 (offset by startValue), scan until lastValue,
400+
// then fill remaining positions with lastValue.
401+
return null;
402+
}
403+
try (var builder = factory.singletonOrdinalsBuilder(this, docs.count() - offset, true)) {
404+
BlockLoader.SingletonLongBuilder delegate = new SingletonLongToSingletonOrdinalDelegate(builder);
405+
var result = denseOrds.tryRead(delegate, docs, offset);
406+
if (result != null) {
407+
return result;
408+
}
393409
}
394-
// TODO: Since ordinals are sorted, start at 0 (offset by startValue), scan until lastValue,
395-
// then fill remaining positions with lastValue.
396410
}
397411
return null;
398412
}
@@ -442,6 +456,10 @@ public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.D
442456

443457
abstract static class BaseDenseNumericValues extends NumericDocValues implements BlockLoader.OptionalColumnAtATimeReader {
444458
abstract long lookAheadValueAt(int targetDoc) throws IOException;
459+
460+
BlockLoader.Block tryRead(BlockLoader.SingletonLongBuilder builder, BlockLoader.Docs docs, int offset) throws IOException {
461+
return null;
462+
}
445463
}
446464

447465
abstract static class BaseSortedSetDocValues extends SortedSetDocValues {
@@ -1256,41 +1274,49 @@ public long longValue() throws IOException {
12561274

12571275
@Override
12581276
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
1259-
assert maxOrd == -1 : "unexpected maxOrd[" + maxOrd + "]";
1277+
try (BlockLoader.SingletonLongBuilder builder = factory.singletonLongs(docs.count() - offset)) {
1278+
return tryRead(builder, docs, offset);
1279+
}
1280+
}
1281+
1282+
@Override
1283+
BlockLoader.Block tryRead(BlockLoader.SingletonLongBuilder builder, BlockLoader.Docs docs, int offset) throws IOException {
12601284
final int docsCount = docs.count();
12611285
doc = docs.get(docsCount - 1);
1262-
try (BlockLoader.SingletonLongBuilder builder = factory.singletonLongs(docs.count() - offset)) {
1263-
for (int i = offset; i < docsCount;) {
1264-
int index = docs.get(i);
1265-
final int blockIndex = index >>> ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SHIFT;
1266-
final int blockInIndex = index & ES819TSDBDocValuesFormat.NUMERIC_BLOCK_MASK;
1267-
if (blockIndex != currentBlockIndex) {
1268-
assert blockIndex > currentBlockIndex : blockIndex + " < " + currentBlockIndex;
1269-
// no need to seek if the loading block is the next block
1270-
if (currentBlockIndex + 1 != blockIndex) {
1271-
valuesData.seek(indexReader.get(blockIndex));
1272-
}
1273-
currentBlockIndex = blockIndex;
1286+
for (int i = offset; i < docsCount;) {
1287+
int index = docs.get(i);
1288+
final int blockIndex = index >>> ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SHIFT;
1289+
final int blockInIndex = index & ES819TSDBDocValuesFormat.NUMERIC_BLOCK_MASK;
1290+
if (blockIndex != currentBlockIndex) {
1291+
assert blockIndex > currentBlockIndex : blockIndex + " < " + currentBlockIndex;
1292+
// no need to seek if the loading block is the next block
1293+
if (currentBlockIndex + 1 != blockIndex) {
1294+
valuesData.seek(indexReader.get(blockIndex));
1295+
}
1296+
currentBlockIndex = blockIndex;
1297+
if (bitsPerOrd == -1) {
12741298
decoder.decode(valuesData, currentBlock);
1299+
} else {
1300+
decoder.decodeOrdinals(valuesData, currentBlock, bitsPerOrd);
12751301
}
1302+
}
12761303

1277-
// Try to append more than just one value:
1278-
// Instead of iterating over docs and find the max length, take an optimistic approach to avoid as
1279-
// many comparisons as there are remaining docs and instead do at most 7 comparisons:
1280-
int length = 1;
1281-
int remainingBlockLength = Math.min(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE - blockInIndex, docsCount - i);
1282-
for (int newLength = remainingBlockLength; newLength > 1; newLength = newLength >> 1) {
1283-
int lastIndex = i + newLength - 1;
1284-
if (isDense(index, docs.get(lastIndex), newLength)) {
1285-
length = newLength;
1286-
break;
1287-
}
1304+
// Try to append more than just one value:
1305+
// Instead of iterating over docs and find the max length, take an optimistic approach to avoid as
1306+
// many comparisons as there are remaining docs and instead do at most 7 comparisons:
1307+
int length = 1;
1308+
int remainingBlockLength = Math.min(ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE - blockInIndex, docsCount - i);
1309+
for (int newLength = remainingBlockLength; newLength > 1; newLength = newLength >> 1) {
1310+
int lastIndex = i + newLength - 1;
1311+
if (isDense(index, docs.get(lastIndex), newLength)) {
1312+
length = newLength;
1313+
break;
12881314
}
1289-
builder.appendLongs(currentBlock, blockInIndex, length);
1290-
i += length;
12911315
}
1292-
return builder.build();
1316+
builder.appendLongs(currentBlock, blockInIndex, length);
1317+
i += length;
12931318
}
1319+
return builder.build();
12941320
}
12951321

12961322
@Override
@@ -1624,4 +1650,59 @@ private static class TermsDictEntry {
16241650
int maxBlockLength;
16251651
}
16261652

1653+
static final class SingletonLongToSingletonOrdinalDelegate implements BlockLoader.SingletonLongBuilder {
1654+
private final BlockLoader.SingletonOrdinalsBuilder builder;
1655+
1656+
SingletonLongToSingletonOrdinalDelegate(BlockLoader.SingletonOrdinalsBuilder builder) {
1657+
this.builder = builder;
1658+
}
1659+
1660+
@Override
1661+
public BlockLoader.SingletonLongBuilder appendLong(long value) {
1662+
throw new UnsupportedOperationException();
1663+
}
1664+
1665+
@Override
1666+
public BlockLoader.SingletonLongBuilder appendLongs(long[] values, int from, int length) {
1667+
// Unfortunately, no array copy here...
1668+
// Since we need to loop here, let's also keep track of min/max.
1669+
int minOrd = Integer.MAX_VALUE;
1670+
int maxOrd = Integer.MIN_VALUE;
1671+
int counter = 0;
1672+
int[] convertedOrds = new int[length];
1673+
int end = from + length;
1674+
for (int j = from; j < end; j++) {
1675+
int ord = Math.toIntExact(values[j]);
1676+
convertedOrds[counter++] = ord;
1677+
minOrd = Math.min(minOrd, ord);
1678+
maxOrd = Math.max(maxOrd, ord);
1679+
}
1680+
builder.appendOrds(convertedOrds, 0, length, minOrd, maxOrd);
1681+
return this;
1682+
}
1683+
1684+
@Override
1685+
public BlockLoader.Block build() {
1686+
return builder.build();
1687+
}
1688+
1689+
@Override
1690+
public BlockLoader.Builder appendNull() {
1691+
throw new UnsupportedOperationException();
1692+
}
1693+
1694+
@Override
1695+
public BlockLoader.Builder beginPositionEntry() {
1696+
throw new UnsupportedOperationException();
1697+
}
1698+
1699+
@Override
1700+
public BlockLoader.Builder endPositionEntry() {
1701+
throw new UnsupportedOperationException();
1702+
}
1703+
1704+
@Override
1705+
public void close() {}
1706+
}
1707+
16271708
}

server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throw
756756
return block;
757757
}
758758
}
759-
try (var builder = factory.singletonOrdinalsBuilder(ordinals, docs.count() - offset)) {
759+
try (var builder = factory.singletonOrdinalsBuilder(ordinals, docs.count() - offset, false)) {
760760
for (int i = offset; i < docs.count(); i++) {
761761
int doc = docs.get(i);
762762
if (doc < ordinals.docID()) {

server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ interface BlockFactory {
447447
/**
448448
* Build a reader for reading {@link SortedDocValues}
449449
*/
450-
SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int count);
450+
SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int count, boolean isDense);
451451

452452
/**
453453
* Build a reader for reading {@link SortedSetDocValues}
@@ -548,6 +548,8 @@ interface SingletonOrdinalsBuilder extends Builder {
548548
* Appends an ordinal to the builder.
549549
*/
550550
SingletonOrdinalsBuilder appendOrd(int value);
551+
552+
SingletonOrdinalsBuilder appendOrds(int[] values, int from, int length, int minOrd, int maxOrd);
551553
}
552554

553555
interface SortedSetOrdinalsBuilder extends Builder {

0 commit comments

Comments
 (0)