Conversation
Fixes NVIDIA#14148. This commit adds support for the new BloomFilter v2 format that was added in Apache Spark 4.1.1 (via apache/spark@a08d8b0). The v1 format used INT32s for bit index calculation. When the number of items in the bloom-filter approaches INT_MAX, one sees a higher rate of collisions. The v2 format uses INT64 values for bit index calculations, allowing the full bit space to be addressed. Apparently, this reduces the false positive rates for large filters. Before the fix in this current PR was applied to spark-rapids, only certain bloom filter join tests would fail against Apache Spark 4.1.1; specifically: 1. `test_bloom_filter_join_cpu_build`, where the bloom filter is built on CPU and then probed on GPU. This failed because the CPU would produce a v2 filter that couldn't be treated as a v1 format on GPU. 2. `test_bloom_filter_join_split_cpu_build`, where the bloom filter is partially aggregated on CPU, then merged on GPU. Again, the GPU-side merging expected v1 format, while the CPU produced v2. Note that `test_bloom_filter_join_cpu_probe` and `test_bloom_filter_join` did not actually fail on 4.1.1. That is because: 1. `test_bloom_filter_join_cpu_probe` tests CPU probing, which supports v1 and v2 flexibly. 2. `test_bloom_filter_join` tests both the build and probe jointly being either on CPU, or GPU. The CPU ran v2 format, the GPU ran v1. Both produce the same query results, albeit with different formats. The fix in this commit allows for v1 and v2 formats to be jointly supported on GPU, depending on the Spark version. Signed-off-by: MithunR <mithunr@nvidia.com>
Greptile SummaryThis PR adds GPU-side support for the Spark BloomFilter v2 serialization format introduced in Apache Spark 4.1.1, which uses 64-bit indices for bit calculations instead of 32-bit, reducing false-positive rates for large filters. The fix prevents failures in Key changes:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[BloomFilterShims.convertToGpuImpl] -->|reads| B[BloomFilterConstantsShims.BLOOM_FILTER_FORMAT_VERSION]
B -->|spark330–402: returns 1| C[GpuBloomFilterAggregate version=1]
B -->|spark411: returns 2| D[GpuBloomFilterAggregate version=2]
C --> E[GpuBloomFilterUpdate version=1]
D --> F[GpuBloomFilterUpdate version=2]
E --> G[BloomFilter.create v1 on GPU]
F --> H[BloomFilter.create v2 on GPU]
I[CPU-built BloomFilter binary] --> J[GpuBloomFilter.deserialize]
J --> K{readVersionFromDevice: read bytes 0-3}
K -->|version=1| L[headerSize=12, copy buffer]
K -->|version=2| M[headerSize=16, copy buffer]
K -->|other| N[IllegalArgumentException]
L --> O[GpuBloomFilter probe / merge]
M --> O
Last reviewed commit: c9c8b4a |
|
|
||
| object BloomFilterConstantsShims { | ||
| val BLOOM_FILTER_FORMAT_VERSION: Int = 1 | ||
| } No newline at end of file |
There was a problem hiding this comment.
Missing newline at end of file
Both new BloomFilterConstantsShims.scala files (spark330 and spark411) are missing a trailing newline. This can cause issues with certain tools and doesn't follow standard POSIX text file convention. Please add a newline after the closing brace.
| } | |
| } |
The same applies to sql-plugin/src/main/spark411/scala/com/nvidia/spark/rapids/shims/BloomFilterConstantsShims.scala at line 24.
| version: Int = BloomFilter.VERSION_2, | ||
| seed: Int = BloomFilter.DEFAULT_SEED) extends GpuAggregateFunction { |
There was a problem hiding this comment.
Default version parameter targets wrong format for pre-4.11 shims
The default value for version is BloomFilter.VERSION_2, but this class (spark330/...) is compiled for all Spark versions from 3.3.0 through 4.1.1. For any code path that constructs GpuBloomFilterAggregate without explicitly passing version (e.g. direct instantiation in tests or future callers), the aggregate would produce a V2 filter even when running under a pre-4.1.1 Spark version.
While all current production paths go through BloomFilterShims.convertToGpuImpl() which explicitly passes BloomFilterConstantsShims.BLOOM_FILTER_FORMAT_VERSION, a safer default would be BloomFilter.VERSION_1 (or 1) to match the behaviour expected by Spark < 4.1.1, with the spark411 shim overriding this at construction time.
| version: Int = BloomFilter.VERSION_2, | |
| seed: Int = BloomFilter.DEFAULT_SEED) extends GpuAggregateFunction { | |
| version: Int = BloomFilter.VERSION_1, | |
| seed: Int = BloomFilter.DEFAULT_SEED) extends GpuAggregateFunction { |
Fixes #14148.
Depends on NVIDIA/spark-rapids-jni#4360.
Description
This commit adds support for the new BloomFilter v2 format that was added in Apache Spark 4.1.1 (via apache/spark@a08d8b0).
Background
The v1 format used INT32s for bit index calculation. When the number of items in the bloom-filter approaches INT_MAX, one sees a higher rate of collisions. The v2 format uses INT64 values for bit index calculations, allowing the full bit space to be addressed. Apparently, this reduces the false positive rates for large filters.
Before the fix in this current PR was applied to spark-rapids, only certain bloom filter join tests would fail against Apache Spark 4.1.1; specifically:
test_bloom_filter_join_cpu_build, where the bloom filter is built on CPU and then probed on GPU. This failed because the CPU would produce a v2 filter that couldn't be treated as a v1 format on GPU.test_bloom_filter_join_split_cpu_build, where the bloom filter is partially aggregated on CPU, then merged on GPU. Again, the GPU-side merging expected v1 format, while the CPU produced v2.Note that
test_bloom_filter_join_cpu_probeandtest_bloom_filter_joindid not actually fail on 4.1.1. That is because:test_bloom_filter_join_cpu_probetests CPU probing, which supports v1 and v2 flexibly.test_bloom_filter_jointests both the build and probe jointly being either on CPU, or GPU. The CPU ran v2 format, the GPU ran v1. Both produce the same query results, albeit with different formats.Effect
The fix in this commit allows for v1 and v2 formats to be jointly supported on GPU, depending on the Spark version.
Documentation
The change is not strictly user-facing. The bloom filter involved is an implementation detail, constructed in the background, and not exposed to the user. The user should see performance improvement for joins in the INT_MAX cases, but nothing else. No documentation need be updated.
Tests
The existing bloom filter test cases should really cover this.
test_bloom_filter_join_cpu_buildandtest_bloom_filter_join_split_cpu_buildhave been re-enabled for Spark version >= 4.1.1.Performance Tests
Testing is underway. Results will be updated here.
Checklists
(Please explain in the PR description how the new code paths are tested, such as names of the new/existing tests that cover them.)