You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
support FFI query result streams that do not pre-collect #1011
Is your feature request related to a problem or challenge? Please describe what you are trying to do.
I'm trying to pass the result of a query into my rust code. Some of the queries I'm doing produce a lot of data, and I would like to process this in a streaming way, without first loading the entire query result into memory (where it might not even fit).
Dataframe has a function __arrow_c_stream__(), which can be used to cross the FFI boundary and get dataframe results into a native component. Unfortunately, this calls .collect() internally. This means I can't actually stream over the results while keeping the memory footprint low. I need to be able to load my entire dataset in memory, and the rest of my processing logic has to wait for this to complete before it can start.
Describe the solution you'd like
I would like __arrow_c_stream__() or a similar function to produce a RecordBatchReader or even a RecordBatchStream (which also appears to be FFI-wrapped), which streams the query result without first collecting into memory.
Describe alternatives you've considered
The alternative is accepting that using results from python in rust will always require a collect on the python side first. Given that the infrastructure seems to be in place to pass around readers and streams, this seems silly.
changed the title [-]support query result streams that do not pre-collect[/-][+]support FFI query result streams that do not pre-collect[/+]on Feb 3, 2025
The Arrow C Data Interface and the PyCapsule Interface (of which __arrow_c_stream__ is a part), are synchronous-only. You could in theory create a RecordBatchIterator in Rust that under the hood blocks using tokio in each next() call, but that will of course be blocking.
Alternatively, you can use RecordBatchStream. That holds a DataFusion RecordBatchStream, and so it shouldn't pre-collect. However then it's impossible to transfer via FFI to another library because Arrow doesn't define an async FFI protocol. I added async iteration support to RecordBatchStream, which may help you.
All this means is that you have to do the iteration via Python. So you can do sync or async iteration over the RecordBatchStream, and then for each produced RecordBatch you can use FFI to convert that to whatever library you're using.
I realize that FFI source is a specific concept for DF/python, but in the broader sense this is a legitimate request, not having to materialize the full source data when performing an aggregation for example.
having the same problem, datafusion keep consuming more memory till it crashes
df = ctx.sql("""
select
* EXCLUDE("I","XX","SETTLEMENTDATE"),
CAST(to_timestamp_seconds("SETTLEMENTDATE",'%Y/%m/%d %H:%M:%S') AS TIMESTAMP(6)) as SETTLEMENTDATE,
cast(EXTRACT(YEAR FROM CAST(to_timestamp_seconds("SETTLEMENTDATE",'%Y/%m/%d %H:%M:%S') AS TIMESTAMP(6))) as integer) as year
from arrow_dataset
where "I" ='D' and "UNIT"='DUNIT' and "VERSION" ='3'
""")
write_deltalake(f"{table_root}/T{total_files}/datafusion", df,mode="overwrite",partition_by=['year'])
Activity
[-]Make __arrow_c_stream__() not collect internally[/-][+]support query result streams that do not pre-collect[/+][-]support query result streams that do not pre-collect[/-][+]support FFI query result streams that do not pre-collect[/+]kylebarron commentedon Feb 5, 2025
The Arrow C Data Interface and the PyCapsule Interface (of which
__arrow_c_stream__is a part), are synchronous-only. You could in theory create aRecordBatchIteratorin Rust that under the hood blocks using tokio in eachnext()call, but that will of course be blocking.Alternatively, you can use
RecordBatchStream. That holds a DataFusionRecordBatchStream, and so it shouldn't pre-collect. However then it's impossible to transfer via FFI to another library because Arrow doesn't define an async FFI protocol. I added async iteration support toRecordBatchStream, which may help you.All this means is that you have to do the iteration via Python. So you can do sync or async iteration over the
RecordBatchStream, and then for each producedRecordBatchyou can use FFI to convert that to whatever library you're using.aditanase commentedon Apr 25, 2025
For what it's worth, you can do this to some degree with duckdb:
I realize that FFI source is a specific concept for DF/python, but in the broader sense this is a legitimate request, not having to materialize the full source data when performing an aggregation for example.
kylebarron commentedon Apr 25, 2025
FWIW I implemented this in kylebarron/arro3#313, where the
RecordBatchStreamcan be synchronously exported to anArrowArrayStreamdjouallah commentedon Jul 15, 2025
having the same problem, datafusion keep consuming more memory till it crashes
kylebarron commentedon Sep 3, 2025
#1222 would close this.
Dandandan commentedon Jan 14, 2026
This can be closed?
timsaucer commentedon Jan 14, 2026
Yes! Thanks @Dandandan for point it out.