Skip to content

Commit 42e77ea

Browse files
[python] Add as-of joins for multimodal scans (#9536)
1 parent 6948dd5 commit 42e77ea

9 files changed

Lines changed: 2623 additions & 14 deletions

File tree

‎docs/docs/pypaimon/multimodal-reading.md‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,45 @@ with docs.scan().where("category = 'lake'").to_arrow_batch_reader() as reader:
5050
consume(batch)
5151
```
5252

53+
### As-of joins
54+
55+
`join_asof` preserves each left row and matches at most one right row in the
56+
same `by` group. Chain calls to align multiple streams lazily.
57+
58+
```python
59+
from datetime import timedelta
60+
from pypaimon.multimodal import join_asof
61+
62+
aligned = join_asof(
63+
actions.scan().select(["episode_id", "event_time", "action"]),
64+
images.scan().where("camera = 'left'").select("image"),
65+
on="event_time",
66+
by="episode_id",
67+
direction="nearest",
68+
tolerance=timedelta(milliseconds=20),
69+
).join_asof(
70+
topics.scan().where("topic = '/robot/state'").select("value"),
71+
direction="backward",
72+
tolerance=timedelta(milliseconds=50),
73+
)
74+
75+
for batch in aligned.to_arrow_batch_reader(batch_size=128):
76+
train(batch)
77+
```
78+
79+
`direction` is `backward`, `forward`, or `nearest`; tolerance is inclusive and
80+
zero means exact. Nearest ties use the earlier time. For duplicate timestamps,
81+
backward uses the last row and forward uses the first. Nearest uses the last
82+
row for an exact match; otherwise it uses the backward or forward candidate's
83+
rule. Misses return null.
84+
85+
Keys must be non-null with matching types. Use `right_on` for a different right
86+
timestamp and `suffix` for conflicts. Select the right timestamp to compute the
87+
match delta.
88+
89+
Inputs are snapshot-pinned (`resolved_snapshots`). Left rows stream, right join
90+
keys stay in memory, and BLOBs remain descriptors.
91+
5392
### Reading BLOB columns
5493

5594
`scan().read_blobs(column)` bulk-fetches a BLOB column's bytes for the filtered

‎paimon-python/pypaimon/multimodal/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
text_route,
4343
vector_route,
4444
)
45+
from pypaimon.multimodal.temporal import (
46+
AsOfJoin,
47+
join_asof,
48+
)
4549
from pypaimon.multimodal.video import VideoFrameCollator
4650
from pypaimon.table.row.blob import Blob, BlobDescriptor, VideoFrameDescriptor
4751
from pypaimon.table.data_evolution_merge_into import (
@@ -51,6 +55,7 @@
5155
)
5256

5357
__all__ = [
58+
"AsOfJoin",
5459
"Blob",
5560
"BlobDescriptor",
5661
"BlobObject",
@@ -71,6 +76,7 @@
7176
"VideoFrameCollator",
7277
"VideoFrameDescriptor",
7378
"connect",
79+
"join_asof",
7480
"lit",
7581
"source_col",
7682
"target_col",

0 commit comments

Comments
 (0)