@@ -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}
0 commit comments