You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@spark.apache.org by "Allison Wang (Jira)" <ji...@apache.org> on 2025/08/28 21:34:00 UTC
[jira] [Created] (SPARK-53426) Support named argument for Arrow Python UDTFs
Allison Wang created SPARK-53426:
------------------------------------
Summary: Support named argument for Arrow Python UDTFs
Key: SPARK-53426
URL: https://issues.apache.org/jira/browse/SPARK-53426
Project: Spark
Issue Type: Sub-task
Components: PySpark
Affects Versions: 4.1.0
Reporter: Allison Wang
Named argument does not work for Python UDTFs table arguments:
{code:java}
def test_arrow_udtf_with_named_arguments(self):
@arrow_udtf(returnType="result_id bigint, multiplier_used int")
class NamedArgsUDTF:
def eval(
self,
table_data: "pa.RecordBatch",
multiplier: "pa.Array"
) -> Iterator["pa.Table"]:
assert isinstance(
table_data, pa.RecordBatch
), f"Expected pa.RecordBatch for table_data, got {type(table_data)}"
assert isinstance(
multiplier, pa.Array
), f"Expected pa.Array for multiplier, got {type(multiplier)}" multiplier_val = multiplier[0].as_py() # Convert record batch to table
table = pa.table(table_data)
id_column = table.column("id") # Multiply each id by the multiplier
multiplied_ids = pa.compute.multiply(id_column, pa.scalar(multiplier_val)) result_table = pa.table({
"result_id": multiplied_ids,
"multiplier_used": pa.array([multiplier_val] * table.num_rows, type=pa.int32())
})
yield result_table # Test with DataFrame API using named arguments
input_df = self.spark.range(3) # [0, 1, 2]
> result_df = NamedArgsUDTF(table_data=input_df.asTable(), multiplier=lit(5))python/pyspark/sql/tests/arrow/test_arrow_udtf.py:812:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
python/pyspark/sql/udtf.py:450: in __call__
j_named_arg = sc._jvm.PythonSQLUtils.namedArgumentExpression(key, j_arg)
../../.virtualenvs/spark/lib/python3.11/site-packages/py4j/java_gateway.py:1322: in __call__
return_value = get_return_value(
python/pyspark/errors/exceptions/captured.py:288: in deco
return f(*a, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _answer = 'xspy4j.Py4JException: Method namedArgumentExpression([class java.lang.String, class org.apache.spark.sql.TableArg]) d....ClientServerConnection.run(ClientServerConnection.java:108)\\n\tat java.base/java.lang.Thread.run(Thread.java:840)\\n'
gateway_client = <py4j.clientserver.JavaClient object at 0x109e20090>
target_id = 'z:org.apache.spark.sql.api.python.PythonSQLUtils', name = 'namedArgumentExpression' def get_return_value(answer, gateway_client, target_id=None, name=None):
"""Converts an answer received from the Java gateway into a Python object. For example, string representation of integers are converted to Python
integer, string representation of objects are converted to JavaObject
instances, etc. :param answer: the string returned by the Java gateway
:param gateway_client: the gateway client used to communicate with the Java
Gateway. Only necessary if the answer is a reference (e.g., object,
list, map)
:param target_id: the name of the object from which the answer comes from
(e.g., *object1* in `object1.hello()`). Optional.
:param name: the name of the member from which the answer comes from
(e.g., *hello* in `object1.hello()`). Optional.
"""
if is_error(answer)[0]:
if len(answer) > 1:
type = answer[1]
value = OUTPUT_CONVERTER[type](answer[2:], gateway_client)
if answer[1] == REFERENCE_TYPE:
raise Py4JJavaError(
"An error occurred while calling {0}{1}{2}.\n".
format(target_id, ".", name), value)
else:
> raise Py4JError(
"An error occurred while calling {0}{1}{2}. Trace:\n{3}\n".
format(target_id, ".", name, value))
E py4j.protocol.Py4JError: An error occurred while calling z:org.apache.spark.sql.api.python.PythonSQLUtils.namedArgumentExpression. Trace:
E py4j.Py4JException: Method namedArgumentExpression([class java.lang.String, class org.apache.spark.sql.TableArg]) does not exist
E at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:321)
E at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:342)
E at py4j.Gateway.invoke(Gateway.java:276)
E at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
E at py4j.commands.CallCommand.execute(CallCommand.java:79)
E at py4j.ClientServerConnection.waitForCommands(ClientServerConnection.java:184)
E at py4j.ClientServerConnection.run(ClientServerConnection.java:108)
E at java.base/java.lang.Thread.run(Thread.java:840) {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@spark.apache.org
For additional commands, e-mail: issues-help@spark.apache.org