-
Couldn't load subscription status.
- Fork 28.9k
[SPARK-53614][PYTHON] Add Iterator[pandas.DataFrame] support to applyInPandas
#52716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[SPARK-53614][PYTHON] Add Iterator[pandas.DataFrame] support to applyInPandas
#52716
Conversation
applyInPandasIterator[pandas.DataFrame] support to applyInPandas
Iterator[pandas.DataFrame] support to applyInPandasIterator[pandas.DataFrame] support to applyInPandas
Iterator[pandas.DataFrame] support to applyInPandasIterator[pandas.DataFrame] support to applyInPandas
Iterator[pandas.DataFrame] support to applyInPandasIterator[pandas.DataFrame] support to applyInPandas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, only a few minor comments
python/pyspark/sql/connect/group.py
Outdated
| from pyspark.sql.connect.udf import UserDefinedFunction | ||
| from pyspark.sql.connect.dataframe import DataFrame | ||
| from pyspark.sql.pandas.typehints import infer_group_pandas_eval_type_from_func | ||
| import warnings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import warnings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
| self.assertEqual(expected, result) | ||
|
|
||
| def test_apply_in_pandas_iterator_with_keys_batch_slicing(self): | ||
| from typing import Iterator, Tuple, Any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
such imports should be move to the head of the file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved
|
|
||
| def test_apply_in_pandas_iterator_process_multiple_input_batches(self): | ||
| from typing import Iterator | ||
| import builtins |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why we need import builtins?
I think there is no name conflict if we use sf.max/min/sum in this file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
somehow when I use sum directly it would use column.sum. Do you know the reason? I changed to use builtins to avoid this conflict
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved typing import
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't have column.sum, do you mean sf.sum?
in some test files, sum is imported, so the builtin sum is overridden
| ) | ||
|
|
||
| # Verify that all rows are present after concatenation | ||
| self.assertEqual(len(result), 6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's directly compare the rows
self.assertEqual(result, [Row(...), Row(...), ...])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
What changes were proposed in this pull request?
This PR adds support for the
Iterator[pandas.DataFrame] APIingroupBy().applyInPandas(), enabling batch-by-batch processing of grouped data for improved memory efficiency and scalability.Key Changes:
New PythonEvalType: Added
SQL_GROUPED_MAP_PANDAS_ITER_UDFto distinguish iterator-based UDFs from standard grouped map UDFsType Inference: Implemented automatic detection of iterator signatures:
Iterator[pd.DataFrame] -> Iterator[pd.DataFrame]Tuple[Any, ...], Iterator[pd.DataFrame] -> Iterator[pd.DataFrame]Streaming Serialization: Created
GroupPandasIterUDFSerializerthat streams results without materializing all DataFrames in memoryConfiguration Change: Updated
FlatMapGroupsInPandasExecwhich was hardcodingpythonEvalType = 201instead of extracting it from the UDF expression (mirrored fix fromFlatMapGroupsInArrowExec)Why are the changes needed?
The existing
applyInPandas()API loads entire groups into memory as single DataFrames. For large groups, this can cause OOM errors. The iterator API allows:applyInArrow()iterator API designDoes this PR introduce any user-facing changes?
Yes, this PR adds a new API variant for
applyInPandas():Before (existing API, still supported):
After (new iterator API):
With Grouping Keys:
Backward Compatibility: The existing DataFrame-to-DataFrame API is fully preserved and continues to work without changes.
How was this patch tested?
test_apply_in_pandas_iterator_basic- Basic functionality testtest_apply_in_pandas_iterator_with_keys- Test with grouping keystest_apply_in_pandas_iterator_batch_slicing- Pressure test with 10M rows, 20 columnstest_apply_in_pandas_iterator_with_keys_batch_slicing- Pressure test with keysWas this patch authored or co-authored using generative AI tooling?
Yes, tests generated by Cursor.