Add partition-local exact semi/anti filter stage#2213
Conversation
8a01786 to
f3ebc3e
Compare
| left = cudf.read_parquet(task.data, **self.read_kwargs) | ||
| reference = cudf.read_parquet( | ||
| reference_file, | ||
| columns=self.key_fields, | ||
| **self.reference_read_kwargs, | ||
| ) | ||
| self._require_key_fields(left, "left") |
There was a problem hiding this comment.
Left schema validated after full GPU load
The reference partition schema is validated via PyArrow before any cuDF read (lines 202–204), so a missing key column on the reference side is caught cheaply. The left partition, however, is fully loaded into GPU memory on line 205 before its schema is checked on line 211. For large left partitions that are missing a key column, all the data lands on the GPU before the ValueError is raised, wasting GPU memory and time. Pre-checking the left schema via pq.read_schema() on task.data[0] (or iterating task.data) before calling cudf.read_parquet would mirror the reference-side guard and catch the error cheaply.
| import cudf | ||
| import pyarrow.parquet as pq | ||
|
|
||
| with self.reference_fs.open(reference_file, "rb") as reference_stream: | ||
| reference_schema = pq.read_schema(reference_stream) | ||
| self._require_column_names(reference_schema.names, "reference") | ||
| left = cudf.read_parquet(task.data, **self.read_kwargs) | ||
| reference = cudf.read_parquet( | ||
| reference_file, | ||
| columns=self.key_fields, | ||
| **self.reference_read_kwargs, | ||
| ) |
There was a problem hiding this comment.
Reference file opened twice for remote filesystems
reference_file is opened once via self.reference_fs.open(reference_file, "rb") for the PyArrow schema check (line 202), then opened again by cudf.read_parquet(reference_file, ...) (line 206). For remote filesystems (S3, GCS, HDFS) this causes two separate I/O round-trips per partition. The schema could be extracted from the already-read cuDF DataFrame after the cudf.read_parquet call (reference.dtypes), or the file could be downloaded once into a local buffer that both PyArrow and cuDF consume, to avoid the duplicate remote I/O.
| reference_root = reference_path.rstrip("/") | ||
| output_root = output_path.rstrip("/") | ||
| if not reference_root or not output_root: | ||
| msg = "reference_path and output_path must be non-root directory paths" | ||
| raise ValueError(msg) | ||
| if _path_identity(reference_root) == _path_identity(output_root): | ||
| msg = "output_path must be distinct from reference_path" | ||
| raise ValueError(msg) |
There was a problem hiding this comment.
rstrip("/") may not strip Windows-style separators on non-POSIX paths
reference_path.rstrip("/") only strips forward slashes. If a caller passes a Windows-style path like C:\output\ or a mixed-separator path, the trailing backslash is not removed. The emptiness check on line 130 and the _path_identity comparison on line 133 would still work for the comparison, but self.reference_path and self.output_path would retain trailing backslashes, causing malformed file paths in _reference_partition_path and _output_partition_path. This is mostly academic for GPU workloads (Linux), but using path.rstrip("/\\") or os.path.normpath would be more robust.
de0bfe4 to
b1070ab
Compare
Signed-off-by: Vibhu Jawa <vjawa@nvidia.com>
Signed-off-by: Vibhu Jawa <vjawa@nvidia.com>
Signed-off-by: Vibhu Jawa <vjawa@nvidia.com>
Signed-off-by: Vibhu Jawa <vjawa@nvidia.com>
b1070ab to
e4ef030
Compare
Summary
Adds a focused
PartitionedExactFilterStagefor exact bucket-local exclusion or membership after two datasets have been partitioned with the existingShuffleStage.leftantiandleftsemijoins on one or more exact key columns.partition_index.Why this is the missing primitive
Current Curator already provides the compatible hash shuffle. Campaign-specific grouping can be composed from that shuffle plus workload-specific reducers, but Curator does not currently provide the reusable bucket-local exact semi/anti operation needed for scalable exclusion without broadcasting the complete reference set. This PR deliberately adds only that missing reducer and no scheduler, checkpoint, or workload-specific control plane.
Composition
Both shuffles must use identical keys, hashing, and partition count.
Validation
git diff --checkpassed.maincommit6fa52e3e597206849acb2ac119413fa6cbfe644d; the latter two are typing-only lint repairs.