@@ -220,13 +220,27 @@ public BlockLoader.Block tryRead(
220220 boolean toInt
221221 ) throws IOException {
222222 int count = docs .count () - offset ;
223- try (var builder = factory .bytesRefs (count )) {
224- for (int i = offset ; i < docs .count (); i ++) {
225- doc = docs .get (i );
226- bytesSlice .readBytes ((long ) doc * length , bytes .bytes , 0 , length );
227- builder .appendBytesRef (bytes );
223+ int firstDocId = docs .get (offset );
224+ int lastDocId = docs .get (count - 1 );
225+ doc = lastDocId ;
226+
227+ if (isDense (firstDocId , lastDocId , count )) {
228+ try (var builder = factory .singletonBytesRefs (count )) {
229+ int bulkLength = length * count ;
230+ byte [] bytes = new byte [bulkLength ];
231+ bytesSlice .readBytes ((long ) firstDocId * length , bytes , 0 , bulkLength );
232+ builder .appendBytesRefs (bytes , length );
233+ return builder .build ();
234+ }
235+ } else {
236+ try (var builder = factory .bytesRefs (count )) {
237+ for (int i = offset ; i < docs .count (); i ++) {
238+ int docId = docs .get (i );
239+ bytesSlice .readBytes ((long ) docId * length , bytes .bytes , 0 , length );
240+ builder .appendBytesRef (bytes );
241+ }
242+ return builder .build ();
228243 }
229- return builder .build ();
230244 }
231245 }
232246 };
@@ -255,15 +269,39 @@ public BlockLoader.Block tryRead(
255269 boolean toInt
256270 ) throws IOException {
257271 int count = docs .count () - offset ;
258- try (var builder = factory .bytesRefs (count )) {
259- for (int i = offset ; i < docs .count (); i ++) {
260- doc = docs .get (i );
261- long startOffset = addresses .get (doc );
262- bytes .length = (int ) (addresses .get (doc + 1L ) - startOffset );
263- bytesSlice .readBytes (startOffset , bytes .bytes , 0 , bytes .length );
264- builder .appendBytesRef (bytes );
272+ int firstDocId = docs .get (offset );
273+ int lastDocId = docs .get (count - 1 );
274+ doc = lastDocId ;
275+
276+ if (isDense (firstDocId , lastDocId , count )) {
277+ try (var builder = factory .singletonBytesRefs (count )) {
278+ long [] offsets = new long [count + 1 ];
279+
280+ // Normalize offsets so that first offset is 0
281+ long startOffset = addresses .get (firstDocId );
282+ for (int i = offset , j = 1 ; i < docs .count (); i ++, j ++) {
283+ int docId = docs .get (i );
284+ long nextOffset = addresses .get (docId + 1 ) - startOffset ;
285+ offsets [j ] = nextOffset ;
286+ }
287+
288+ int length = Math .toIntExact (addresses .get (lastDocId + 1L ) - startOffset );
289+ byte [] bytes = new byte [length ];
290+ bytesSlice .readBytes (startOffset , bytes , 0 , length );
291+ builder .appendBytesRefs (bytes , offsets );
292+ return builder .build ();
293+ }
294+ } else {
295+ try (var builder = factory .bytesRefs (count )) {
296+ for (int i = offset ; i < docs .count (); i ++) {
297+ int docId = docs .get (i );
298+ long startOffset = addresses .get (docId );
299+ bytes .length = (int ) (addresses .get (docId + 1L ) - startOffset );
300+ bytesSlice .readBytes (startOffset , bytes .bytes , 0 , bytes .length );
301+ builder .appendBytesRef (bytes );
302+ }
303+ return builder .build ();
265304 }
266- return builder .build ();
267305 }
268306 }
269307 };
@@ -1556,13 +1594,6 @@ long lookAheadValueAt(int targetDoc) throws IOException {
15561594 return lookaheadBlock [valueIndex ];
15571595 }
15581596
1559- static boolean isDense (int firstDocId , int lastDocId , int length ) {
1560- // This does not detect duplicate docids (e.g [1, 1, 2, 4] would be detected as dense),
1561- // this can happen with enrich or lookup. However this codec isn't used for enrich / lookup.
1562- // This codec is only used in the context of logsdb and tsdb, so this is fine here.
1563- return lastDocId - firstDocId == length - 1 ;
1564- }
1565-
15661597 @ Override
15671598 SortedOrdinalReader sortedOrdinalReader () {
15681599 return null ;
@@ -1681,6 +1712,13 @@ public BlockLoader.Block tryRead(
16811712 }
16821713 }
16831714
1715+ private static boolean isDense (int firstDocId , int lastDocId , int length ) {
1716+ // This does not detect duplicate docids (e.g [1, 1, 2, 4] would be detected as dense),
1717+ // this can happen with enrich or lookup. However this codec isn't used for enrich / lookup.
1718+ // This codec is only used in the context of logsdb and tsdb, so this is fine here.
1719+ return lastDocId - firstDocId == length - 1 ;
1720+ }
1721+
16841722 private NumericDocValues getRangeEncodedNumericDocValues (NumericEntry entry , long maxOrd ) throws IOException {
16851723 final var ordinalsReader = new SortedOrdinalReader (
16861724 maxOrd ,
0 commit comments