Skip to content

Optimize encoded numeric range bitsets#16160

Merged
romseygeek merged 7 commits into
apache:mainfrom
costin:lucene/gcd-bound-transform-simd
Jul 2, 2026
Merged

Optimize encoded numeric range bitsets#16160
romseygeek merged 7 commits into
apache:mainfrom
costin:lucene/gcd-bound-transform-simd

Conversation

@costin

@costin costin commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

CD- and delta-encoded dense NumericDocValues currently decode every value inside rangeIntoBitSet(), even though the encoded packed values are already available. This PR transforms the query bounds into the encoded domain once per call, then delegates to the existing DocValuesRangeSupport path.

This keeps the implementation provider-neutral: the default scalar provider still works, while the existing Panama Vector API provider can handle the encoded values through the same optimized range-into-bitset path.
Overflow during bound transformation (ArithmeticException _ ) falls back to the previous scalar decoded loop.

The scope is dense singleton numeric doc values. SortedNumericDocValuesField.newSlowRangeQuery benefits for singleton fields because Lucene unwraps them to NumericDocValues before using BatchDocValuesRangeIterator. True multi-valued sorted numerics need a separate value-level-to-doc-level bitset algorithm, but can reuse the same bound transformation idea.

Benchmarks

GcdDeltaRangeIntoBitSetBenchmark

Platform: JDK 25, 1M docs, 1 fork, 3 iters x 2s

default: scalar provider, no --add-modules jdk.incubator.vector panama: SIMD via Panama Vector API

AMD EPYC (c5a.2xlarge, AVX2)

encoding selectivity default (ops/s) panama (ops/s) panama vs default
none 0.01 171.9 306.4 1.78x
none 0.1 153.1 265.7 1.73x
none 0.5 161.7 340.0 2.10x
delta_only 0.01 171.7 305.2 1.78x
delta_only 0.1 156.8 265.0 1.69x
delta_only 0.5 166.6 338.6 2.03x
gcd_1000 0.01 172.5 306.3 1.78x
gcd_1000 0.1 155.5 265.3 1.71x
gcd_1000 0.5 168.7 340.3 2.02x
gcd_100_delta 0.01 171.4 304.0 1.77x
gcd_100_delta 0.1 155.6 265.2 1.70x
gcd_100_delta 0.5 168.9 337.8 2.00x

Intel Ice Lake (c6i.2xlarge, AVX-512)

encoding selectivity default (ops/s) panama (ops/s) panama vs default
none 0.01 177.1 539.4 3.05x
none 0.1 155.2 381.3 2.46x
none 0.5 163.9 526.9 3.22x
delta_only 0.01 173.0 537.0 3.10x
delta_only 0.1 156.9 376.4 2.40x
delta_only 0.5 160.5 530.0 3.30x
gcd_1000 0.01 176.6 538.7 3.05x
gcd_1000 0.1 156.2 379.7 2.43x
gcd_1000 0.5 159.0 536.9 3.38x
gcd_100_delta 0.01 178.4 537.2 3.01x
gcd_100_delta 0.1 156.5 376.0 2.40x
gcd_100_delta 0.5 158.8 530.5 3.34x

Below a comparison on the gains AVX-512 from larger registers than AVX-2

AVX-512 vs AVX2, Panama provider

encoding selectivity AMD (ops/s) AVX-512 (ops/s) AVX-512 vs AMD
none 0.01 306.4 539.4 1.76x
none 0.1 265.7 381.3 1.44x
none 0.5 340.0 526.9 1.55x
delta_only 0.01 305.2 537.0 1.76x
delta_only 0.1 265.0 376.4 1.42x
delta_only 0.5 338.6 530.0 1.57x
gcd_1000 0.01 306.3 538.7 1.76x
gcd_1000 0.1 265.3 379.7 1.43x
gcd_1000 0.5 340.3 536.9 1.58x
gcd_100_delta 0.01 304.0 537.2 1.77x
gcd_100_delta 0.1 265.2 376.0 1.42x
gcd_100_delta 0.5 337.8 530.5 1.57x

@costin costin force-pushed the lucene/gcd-bound-transform-simd branch from 6bdad46 to 281a1f5 Compare June 1, 2026 19:29
@github-actions github-actions Bot added this to the 11.0.0 milestone Jun 1, 2026
Comment thread lucene/CHANGES.txt Outdated
@salvatore-campagna

salvatore-campagna commented Jun 10, 2026

Copy link
Copy Markdown

Really nice and clever trick. Pushing the query bounds into the encoded domain once so the existing SIMD kernel can run unmodified on packed values is very clean, and the overflow fallback is a nice escape hatch.

It also got me thinking about other filter pushdown opportunities. Anywhere we have an invertible monotone transform between stored and decoded values (delta + scale, ordinal dictionaries, scaled values, etc...) the same idea should apply.

costin added 2 commits June 15, 2026 22:46
GCD- and delta-encoded dense NumericDocValues can reuse the
existing range-into-bitset fast path by transforming query bounds
into the encoded domain once per call. Open bounds are saturated
so they keep the SIMD path even when the bound transformation
would otherwise overflow.
@costin costin force-pushed the lucene/gcd-bound-transform-simd branch from 281a1f5 to 82f3c35 Compare June 15, 2026 21:39
@costin

costin commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@salvatore-campagna Grazie! It took some time to wrap my head around the encoding (wasn't sure I've got the full gist of it). You're right, there might be other places where this recipe might come in handy: rewrite the query bounds in the encoded domain once, hand the encoded ticket scan to the SIMD kernel.
I'll reach out once I have some follow-ups.

@salvatore-campagna

Copy link
Copy Markdown

LGTM thanks, I like that it works on open bounds now too.

@github-actions github-actions Bot modified the milestones: 11.0.0, 10.6.0 Jun 29, 2026
@costin

costin commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Good catch @romseygeekMatchAllDocsQuery was getting rewritten away, so the benchmark was measuring the standalone range query path, not DenseConjunction.

Replaced with a TermQuery on an indexed StringField that matches all docs. The TermQuery survives rewrite and forces the conjunction scorer, so rangeIntoBitSet is exercised on every iteration.

Applied same fix to the sorted-numeric benchmark in #16285.

@costin

costin commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Reran the benchmark (just on AVX2), the numbers hold.

AMD EPYC 7R32 (c5a.2xlarge) — AVX2, 256-bit. JDK 25, 1M docs, 1 fork, 3 iters × 3s.

encoding selectivity default (ops/s) panama (ops/s) panama vs default
none 0.01 167.1 356.9 2.14x
none 0.1 150.3 260.9 1.74x
none 0.5 165.3 335.0 2.03x
delta_only 0.01 169.3 348.2 2.06x
delta_only 0.1 152.6 261.2 1.71x
delta_only 0.5 165.8 334.8 2.02x
gcd_1000 0.01 166.6 349.0 2.10x
gcd_1000 0.1 154.0 261.5 1.70x
gcd_1000 0.5 169.3 334.4 1.97x
gcd_100_delta 0.01 165.9 349.6 2.11x
gcd_100_delta 0.1 154.7 261.1 1.69x
gcd_100_delta 0.5 169.2 331.1 1.96x

@costin costin requested a review from romseygeek June 30, 2026 12:26
@romseygeek romseygeek merged commit 9b68f63 into apache:main Jul 2, 2026
13 checks passed
romseygeek pushed a commit that referenced this pull request Jul 2, 2026
GCD- and delta-encoded dense NumericDocValues can reuse the
existing range-into-bitset fast path by transforming query bounds
into the encoded domain once per call. Open bounds are saturated
so they keep the SIMD path even when the bound transformation
would otherwise overflow.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants