Optimize readInts24 performance for DocIdsWriter
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 1.4k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 88
Description
### Description
While recently [working on numeric range queries](https://github.com/opensearch-project/OpenSearch/issues/9541), I noticed readInts24 to be consuming significant CPU cycles. When I looked into the code, I noticed [multiple consecutive invocations of readLong](https://github.com/apache/lucene/blob/main/lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java#L330).
Initially, it seems that the overhead from multiple syscalls should not be as much, but I tried quick patch by reading all the longs together and it seemed to help. Sharing the patch and numbers below (nyc_taxis range query):
```
diff --git a/lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java b/lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java
index 40db4c0069d..40ee7a1c968 100644
--- a/lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java
+++ b/lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java
@@ -325,11 +325,14 @@ final class DocIdsWriter {
private static void readInts24(IndexInput in, int count, IntersectVisitor visitor)
throws IOException {
+ long[] scratchLong = new long[(count/8) * 3];
+ in.readLongs(scratchLong, 0, (count/8) * 3);
int i;
for (i = 0; i < count - 7; i += 8) {
- long l1 = in.readLong();
- long l2 = in.readLong();
- long l3 = in.readLong();
+ int li = (i/8) * 3;
+ long l1 = scratchLong[li];
+ long l2 = scratchLong[li+1];
+ long l3 = scratchLong[li+2];
visitor.visit((int) (l1 >>> 40));
visitor.visit((int) (l1 >>> 16) & 0xffffff);
visitor.visit((int) (((l1 & 0xffff) << 8) | (l2 >>> 56)));
```
Without this change:
```
| Max Throughput | range | 0.71 | ops/s |
| 50th percentile latency | range | 245.533 | ms |
| 90th percentile latency | range | 248.005 | ms |
| 99th percentile latency | range | 254.824 | ms |
| 100th percentile latency | range | 256.902 | ms |
| 50th percentile service time | range | 243.585 | ms |
| 90th percentile service time | range | 246.178 | ms |
| 99th percentile service time | range | 252.672 | ms |
| 100th percentile service time | range | 255.072 | ms |
| error rate | range | 0 | % |
```
With this change:
```
| Median Throughput | range | 0.7 | ops/s |
| Max Throughput | range | 0.71 | ops/s |
| 50th percentile latency | range | 207.554 | ms |
| 90th percentile latency | range | 209.392 | ms |
| 99th percentile latency | range | 213.157 | ms |
| 100th percentile latency | range | 219.398 | ms |
| 50th percentile service time | range | 205.421 | ms |
| 90th percentile service time | range | 207.361 | ms |
| 99th percentile service time | range | 211.164 | ms |
| 100th percentile service time | range | 217.787 | ms |
| error rate | range | 0 | % |
```
Contributor guide
Research direction
Start in lucene/core/src/java/org/apache/lucene/util/bkd/DocIdsWriter.java at readInts24 and review how consecutive readLong calls process the encoded doc IDs. Reproduce the nyc_taxis numeric range-query comparison described in the issue, then verify that the optimized path preserves decoding behavior and improves latency without errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- performance, search
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100