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
[Python] Allow lazy evaluation of filters in Dataset and add Datset.filter method #31969
To keep the Dataset api compatible with the Table one in terms of analytics capabilities, we should add a Dataset.filter method. The initial POC was based on _table_filter but that required materialising all the Dataset content after filtering as it returned an {}InMemoryDataset{}.
Given that Scanner can filter a dataset without actually materialising the data until a final step happens, it would be good to have Dataset.filter return some form of lazy dataset when the filter is only stored aside and the Scanner is created when data is actually retrieved.
PS: Also update test_dataset_filter test to use the Dataset.filter method
Will Jones / @wjones127:
I'm a little cautious about the idea of Dataset.filter() returning a Dataset, since it mixes up the purpose of Dataset and Scanner. If it did, what would this return then?
I think it might be better if Dataset.filter() returned a scanner with that filter. And then Scanner could also have filter() and project() methods to allow chaining. So you could do:
Alessandro Molina / @amol-:
I'm not fond of relying on Scanner because it looks like violating the single responsibility principle as it would have to grow nearly the same capabilities of Dataset (for example if I want to do a join over filtered data, we would have to implement Scanner.join which doesn't seem to make much sense).
Another direction I thought about was going toward having a FilteredDataset class, that would still inherit from Dataset but more clearly provide a separation of concerns.
Neal Richardson / @nealrichardson:
In the R package we handle this by building a separate query object that contains the Dataset (or RecordBatchReader, or Table, or whatever), and the query object contains the filtering etc. methods. So here, Dataset.filter would first create the query object from the Dataset and then calls the filter method on it.
That said, going that route (or the FilteredDataset path, for that matter) feels like a path to essentially creating ibis in pyarrow. I'd caution you to think twice before adding APIs like this since they become sticky and hard to remove later (look at how long ParquetDataset has lived past the creation of the general Dataset class).
In the R package we handle this by building a separate query object that contains the Dataset (or RecordBatchReader, or Table, or whatever), and the query object contains the filtering etc. methods.
Yeah, I think it seems like the PR as-is would be trying to make Dataset into this kind of query object, which I don't think is it's purpose. Scanner seems closer to that to me, but it's also a bit of a mismatch.
That said, going that route (or the FilteredDataset path, for that matter) feels like a path to essentially creating ibis in pyarrow.
IMO we need to have a larger conversation about how much of Acero we want to expose in PyArrow. We might want a low-level API for creating exec plans, and maybe even some high-level functions like this. But seems like we should have a design doc to think about what our vision in here and how that does relate to developments in Ibis.
Scanner is one-shot though, you can't filter to create a Scanner and then filter it again, you can only Scan.
Yeah, then I think we would need some other query class for representing deferred computations with Acero. Which again goes into the question of PyArrow vs Ibis purpose.
Alessandro Molina / @amol-:
I don't see much of a conflict with Ibis on long term. Ibis is an interface to multiple query engines and the queries you build there can be run against different targets. It serves the purpose of having a single interface to an infrastructure agnostic environment. Write your Ibis code locally and deploy it against a production system that might run something very different from a Acero in-memory.
PyArrow instead only exposes the features that are already available in Arrow itself, and it's something all the other bindings are doing too (R and Java do expose access to the compute engine). What you write in pyarrow won't be able to really grow too much in the direction of scaling on multiple nodes, so it's better positioned for quick data discovery without having to involve external dependencies than for the actual final product which will probably want to be based on IBIS.
Weston Pace / @westonpace:
I agree that scanner should not be used. The term "scanner", in general, should probably go away from the public API. The scanner in python is more of a record batch reader.
I'm not sure I have much to add to the "dataset" vs "query" terminology.
Activity
asfimport commentedon Jun 21, 2022
Will Jones / @wjones127:
I'm a little cautious about the idea of
Dataset.filter()returning aDataset, since it mixes up the purpose ofDatasetandScanner. If it did, what would this return then?I think it might be better if
Dataset.filter()returned a scanner with that filter. And thenScannercould also havefilter()andproject()methods to allow chaining. So you could do:What do you think of that?
asfimport commentedon Jun 22, 2022
Alessandro Molina / @amol-:
I'm not fond of relying on
Scannerbecause it looks like violating the single responsibility principle as it would have to grow nearly the same capabilities ofDataset(for example if I want to do a join over filtered data, we would have to implementScanner.joinwhich doesn't seem to make much sense).Another direction I thought about was going toward having a
FilteredDatasetclass, that would still inherit fromDatasetbut more clearly provide a separation of concerns.asfimport commentedon Jun 22, 2022
Neal Richardson / @nealrichardson:
In the R package we handle this by building a separate query object that contains the Dataset (or RecordBatchReader, or Table, or whatever), and the query object contains the filtering etc. methods. So here, Dataset.filter would first create the query object from the Dataset and then calls the filter method on it.
That said, going that route (or the FilteredDataset path, for that matter) feels like a path to essentially creating ibis in pyarrow. I'd caution you to think twice before adding APIs like this since they become sticky and hard to remove later (look at how long ParquetDataset has lived past the creation of the general Dataset class).
asfimport commentedon Jun 22, 2022
Will Jones / @wjones127:
asfimport commentedon Jun 22, 2022
Neal Richardson / @nealrichardson:
Scanner is one-shot though, you can't filter to create a Scanner and then filter it again, you can only Scan.
asfimport commentedon Jun 22, 2022
Will Jones / @wjones127:
asfimport commentedon Jun 22, 2022
Alessandro Molina / @amol-:
I don't see much of a conflict with Ibis on long term. Ibis is an interface to multiple query engines and the queries you build there can be run against different targets. It serves the purpose of having a single interface to an infrastructure agnostic environment. Write your Ibis code locally and deploy it against a production system that might run something very different from a Acero in-memory.
PyArrow instead only exposes the features that are already available in Arrow itself, and it's something all the other bindings are doing too (R and Java do expose access to the compute engine). What you write in pyarrow won't be able to really grow too much in the direction of scaling on multiple nodes, so it's better positioned for quick data discovery without having to involve external dependencies than for the actual final product which will probably want to be based on IBIS.
asfimport commentedon Jun 27, 2022
Weston Pace / @westonpace:
I agree that scanner should not be used. The term "scanner", in general, should probably go away from the public API. The scanner in python is more of a record batch reader.
I'm not sure I have much to add to the "dataset" vs "query" terminology.
asfimport commentedon Jul 25, 2022
Krisztian Szucs / @kszucs:
Postponing to 10.0, feel free to include it when the PR is ready.
asfimport commentedon Dec 12, 2022
Alessandro Molina / @amol-:
Issue resolved by pull request 13409
#13409