Skip to content

Commit 80d730e

Browse files
kkrik-eselasticsearchmachinemartijnvg
authored
Push down loading of singleton dense double based field types to the … (#133397)
* Push down loading of singleton dense double based field types to the es819 doc value codec * Update docs/changelog/133397.yaml * use `SingletonDoubleBuilder` * add tests * [CI] Auto commit changes from spotless * Update test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java Co-authored-by: Martijn van Groningen <[email protected]> * add assert --------- Co-authored-by: elasticsearchmachine <[email protected]> Co-authored-by: Martijn van Groningen <[email protected]>
1 parent f85f59d commit 80d730e

File tree

19 files changed

+499
-39
lines changed

19 files changed

+499
-39
lines changed

docs/changelog/133397.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 133397
2+
summary: Push down loading of singleton dense double based field types to the …
3+
area: "Codec"
4+
type: enhancement
5+
issues: []

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ protected void registerParameters(ParameterChecker checker) throws IOException {
7878
checker.registerUpdateCheck(b -> b.field("coerce", false), m -> assertFalse(((ScaledFloatFieldMapper) m).coerce()));
7979
}
8080

81+
@Override
82+
protected boolean supportsBulkDoubleBlockReading() {
83+
return true;
84+
}
85+
8186
public void testExistsQueryDocValuesDisabled() throws IOException {
8287
MapperService mapperService = createMapperService(fieldMapping(b -> {
8388
minimalMapping(b);

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

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.apache.lucene.util.packed.PackedInts;
4646
import org.elasticsearch.core.IOUtils;
4747
import org.elasticsearch.index.codec.tsdb.TSDBDocValuesEncoder;
48+
import org.elasticsearch.index.mapper.BlockDocValuesReader;
4849
import org.elasticsearch.index.mapper.BlockLoader;
4950

5051
import java.io.IOException;
@@ -383,7 +384,13 @@ public long cost() {
383384
}
384385

385386
@Override
386-
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
387+
public BlockLoader.Block tryRead(
388+
BlockLoader.BlockFactory factory,
389+
BlockLoader.Docs docs,
390+
int offset,
391+
BlockDocValuesReader.ToDouble toDouble
392+
) throws IOException {
393+
assert toDouble == null;
387394
if (ords instanceof BaseDenseNumericValues denseOrds) {
388395
var block = tryReadAHead(factory, docs, offset);
389396
if (block != null) {
@@ -457,7 +464,12 @@ public TermsEnum termsEnum() throws IOException {
457464
}
458465

459466
@Override
460-
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
467+
public BlockLoader.Block tryRead(
468+
BlockLoader.BlockFactory factory,
469+
BlockLoader.Docs docs,
470+
int offset,
471+
BlockDocValuesReader.ToDouble toDouble
472+
) throws IOException {
461473
return null;
462474
}
463475

@@ -504,7 +516,12 @@ public final long cost() {
504516
}
505517

506518
@Override
507-
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
519+
public BlockLoader.Block tryRead(
520+
BlockLoader.BlockFactory factory,
521+
BlockLoader.Docs docs,
522+
int offset,
523+
BlockDocValuesReader.ToDouble toDouble
524+
) throws IOException {
508525
return null;
509526
}
510527

@@ -1365,7 +1382,18 @@ public long longValue() throws IOException {
13651382
}
13661383

13671384
@Override
1368-
public BlockLoader.Block tryRead(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
1385+
public BlockLoader.Block tryRead(
1386+
BlockLoader.BlockFactory factory,
1387+
BlockLoader.Docs docs,
1388+
int offset,
1389+
BlockDocValuesReader.ToDouble toDouble
1390+
) throws IOException {
1391+
if (toDouble != null) {
1392+
try (BlockLoader.SingletonDoubleBuilder builder = factory.singletonDoubles(docs.count() - offset)) {
1393+
SingletonLongToDoubleDelegate delegate = new SingletonLongToDoubleDelegate(builder, toDouble);
1394+
return tryRead(delegate, docs, offset);
1395+
}
1396+
}
13691397
try (BlockLoader.SingletonLongBuilder builder = factory.singletonLongs(docs.count() - offset)) {
13701398
return tryRead(builder, docs, offset);
13711399
}
@@ -1774,4 +1802,55 @@ public BlockLoader.Builder endPositionEntry() {
17741802
public void close() {}
17751803
}
17761804

1805+
// Block builder that consumes long values and converts them to double using the provided converter function.
1806+
static final class SingletonLongToDoubleDelegate implements BlockLoader.SingletonLongBuilder {
1807+
private final BlockLoader.SingletonDoubleBuilder doubleBuilder;
1808+
private final BlockDocValuesReader.ToDouble toDouble;
1809+
private final double[] buffer = new double[ES819TSDBDocValuesFormat.NUMERIC_BLOCK_SIZE];
1810+
1811+
// The passed builder is used to store the converted double values and produce the final block containing them.
1812+
SingletonLongToDoubleDelegate(BlockLoader.SingletonDoubleBuilder doubleBuilder, BlockDocValuesReader.ToDouble toDouble) {
1813+
this.doubleBuilder = doubleBuilder;
1814+
this.toDouble = toDouble;
1815+
}
1816+
1817+
@Override
1818+
public BlockLoader.SingletonLongBuilder appendLong(long value) {
1819+
throw new UnsupportedOperationException();
1820+
}
1821+
1822+
@Override
1823+
public BlockLoader.SingletonLongBuilder appendLongs(long[] values, int from, int length) {
1824+
assert length <= buffer.length : "length " + length + " > " + buffer.length;
1825+
for (int i = 0; i < length; i++) {
1826+
buffer[i] = toDouble.convert(values[from + i]);
1827+
}
1828+
doubleBuilder.appendDoubles(buffer, 0, length);
1829+
return this;
1830+
}
1831+
1832+
@Override
1833+
public BlockLoader.Block build() {
1834+
return doubleBuilder.build();
1835+
}
1836+
1837+
@Override
1838+
public BlockLoader.Builder appendNull() {
1839+
throw new UnsupportedOperationException();
1840+
}
1841+
1842+
@Override
1843+
public BlockLoader.Builder beginPositionEntry() {
1844+
throw new UnsupportedOperationException();
1845+
}
1846+
1847+
@Override
1848+
public BlockLoader.Builder endPositionEntry() {
1849+
throw new UnsupportedOperationException();
1850+
}
1851+
1852+
@Override
1853+
public void close() {}
1854+
}
1855+
17771856
}

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ public AllReader reader(LeafReaderContext context) throws IOException {
122122
}
123123
}
124124

125-
static class SingletonLongs extends BlockDocValuesReader {
125+
// Used for testing.
126+
interface NumericDocValuesAccessor {
127+
NumericDocValues numericDocValues();
128+
}
129+
130+
static class SingletonLongs extends BlockDocValuesReader implements NumericDocValuesAccessor {
126131
final NumericDocValues numericDocValues;
127132

128133
SingletonLongs(NumericDocValues numericDocValues) {
@@ -132,7 +137,7 @@ static class SingletonLongs extends BlockDocValuesReader {
132137
@Override
133138
public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boolean nullsFiltered) throws IOException {
134139
if (numericDocValues instanceof BlockLoader.OptionalColumnAtATimeReader direct) {
135-
BlockLoader.Block result = direct.tryRead(factory, docs, offset);
140+
BlockLoader.Block result = direct.tryRead(factory, docs, offset, null);
136141
if (result != null) {
137142
return result;
138143
}
@@ -169,6 +174,11 @@ public int docId() {
169174
public String toString() {
170175
return "BlockDocValuesReader.SingletonLongs";
171176
}
177+
178+
@Override
179+
public NumericDocValues numericDocValues() {
180+
return numericDocValues;
181+
}
172182
}
173183

174184
static class Longs extends BlockDocValuesReader {
@@ -387,7 +397,7 @@ public AllReader reader(LeafReaderContext context) throws IOException {
387397
}
388398
}
389399

390-
private static class SingletonDoubles extends BlockDocValuesReader {
400+
static class SingletonDoubles extends BlockDocValuesReader implements NumericDocValuesAccessor {
391401
private final NumericDocValues docValues;
392402
private final ToDouble toDouble;
393403

@@ -398,6 +408,12 @@ private static class SingletonDoubles extends BlockDocValuesReader {
398408

399409
@Override
400410
public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boolean nullsFiltered) throws IOException {
411+
if (docValues instanceof BlockLoader.OptionalColumnAtATimeReader direct) {
412+
BlockLoader.Block result = direct.tryRead(factory, docs, offset, toDouble);
413+
if (result != null) {
414+
return result;
415+
}
416+
}
401417
try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
402418
for (int i = offset; i < docs.count(); i++) {
403419
int doc = docs.get(i);
@@ -430,9 +446,14 @@ public int docId() {
430446
public String toString() {
431447
return "BlockDocValuesReader.SingletonDoubles";
432448
}
449+
450+
@Override
451+
public NumericDocValues numericDocValues() {
452+
return docValues;
453+
}
433454
}
434455

435-
private static class Doubles extends BlockDocValuesReader {
456+
static class Doubles extends BlockDocValuesReader {
436457
private final SortedNumericDocValues docValues;
437458
private final ToDouble toDouble;
438459

@@ -715,7 +736,7 @@ public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset, boole
715736
return readSingleDoc(factory, docs.get(offset));
716737
}
717738
if (ordinals instanceof BlockLoader.OptionalColumnAtATimeReader direct) {
718-
BlockLoader.Block block = direct.tryRead(factory, docs, offset);
739+
BlockLoader.Block block = direct.tryRead(factory, docs, offset, null);
719740
if (block != null) {
720741
return block;
721742
}

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ interface OptionalColumnAtATimeReader {
6565
/**
6666
* Attempts to read the values of all documents in {@code docs}
6767
* Returns {@code null} if unable to load the values.
68+
*
69+
* @param toDouble a function to convert long values to double, or null if no conversion is needed/supported
6870
*/
6971
@Nullable
70-
BlockLoader.Block tryRead(BlockFactory factory, Docs docs, int offset) throws IOException;
72+
BlockLoader.Block tryRead(BlockFactory factory, Docs docs, int offset, BlockDocValuesReader.ToDouble toDouble) throws IOException;
7173
}
7274

7375
interface RowStrideReader extends Reader {
@@ -435,6 +437,17 @@ interface BlockFactory {
435437
*/
436438
SingletonLongBuilder singletonLongs(int expectedCount);
437439

440+
/**
441+
* Build a specialized builder for singleton dense double based fields with the following constraints:
442+
* <ul>
443+
* <li>Only one value per document can be collected</li>
444+
* <li>No more than expectedCount values can be collected</li>
445+
* </ul>
446+
*
447+
* @param expectedCount The maximum number of values to be collected.
448+
*/
449+
SingletonDoubleBuilder singletonDoubles(int expectedCount);
450+
438451
/**
439452
* Build a builder to load only {@code null}s.
440453
*/
@@ -537,12 +550,20 @@ interface IntBuilder extends Builder {
537550
* Specialized builder for collecting dense arrays of long values.
538551
*/
539552
interface SingletonLongBuilder extends Builder {
540-
541553
SingletonLongBuilder appendLong(long value);
542554

543555
SingletonLongBuilder appendLongs(long[] values, int from, int length);
544556
}
545557

558+
/**
559+
* Specialized builder for collecting dense arrays of double values.
560+
*/
561+
interface SingletonDoubleBuilder extends Builder {
562+
SingletonDoubleBuilder appendDouble(double value);
563+
564+
SingletonDoubleBuilder appendDoubles(double[] values, int from, int length);
565+
}
566+
546567
interface LongBuilder extends Builder {
547568
/**
548569
* Appends a long to the current entry.

0 commit comments

Comments
 (0)