@@ -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
0 commit comments