Sangkyoon Nam created FLINK-41016:
-------------------------------------
Summary: Missing uids on the operators PyFlink adds for key_by,
partition_custom and KeyedStream can prevent submission with auto-generated
UIDs disabled
Key: FLINK-41016
URL: https://issues.apache.org/jira/browse/FLINK-41016
Project: Flink
Issue Type: Bug
Components: API / Python
Affects Versions: 2.2.1, 2.2.0, 2.3.0
Reporter: Sangkyoon Nam
The Python DataStream API adds helper operators that get no uid unless the user
can reach them. {{key_by}} adds {{_stream_key_by_map_operator}} before the
partitioning, and {{partition_custom}} adds {{_partition_custom_map_operator}}
before it. {{KeyedStream.print}}, {{add_sink}}, {{union}} and {{project}} call
{{_values()}}, which adds {{_keyed_stream_values_operator}}, and
{{DataStream.union}} does the same for each {{KeyedStream}} argument.
{{partition_custom}} also adds a values helper after the partitioning, but that
one is the stream it returns and can be given a uid. FLINK-40829 covers the
same problem for the operators {{assign_timestamps_and_watermarks}} hides.
*With auto-generated UIDs disabled, a job can fail to submit even with a uid on
every operator the user can reach.* Reproduced with PyFlink 2.2.1, with a uid
on the source, every Python {{map}} and the sink; row 4 also gives the stream
{{partition_custom}} returns a uid. The helper creation, uid check and Python
fusion code is the same in 2.2.0, 2.3.0 and master:
|| Pipeline || Result ||
| Java source, {{key_by}}, keyed {{map}} | {{IllegalStateException}} for
{{_stream_key_by_map_operator}} |
| One Java source, two branches each with {{key_by}} and a keyed {{map}} |
{{IllegalStateException}} for {{_stream_key_by_map_operator}} |
| Java source, {{key_by}}, {{print}} | {{IllegalStateException}} for
{{_stream_key_by_map_operator}} |
| Java source, {{partition_custom}} with a uid, {{map}} |
{{IllegalStateException}} for {{_partition_custom_map_operator}} |
| Java source, Python {{map}}, {{key_by}}, keyed {{map}} | submits |
The last row passes because {{PythonOperatorChainingOptimizer}} fuses the
key-by helper into the preceding Python {{map}}, and the fused operator keeps
that map's uid.
*Proposal.* In {{PythonConfigUtil.configPythonOperator}}, derive a uid for each
helper that has neither a uid nor a hash: {{<input uid>-key-by}}, {{<input
uid>-partition-custom}} and {{<input uid>-values}}, with {{-2}}, {{-3}} for
further helpers of the same kind on the same input. The input is the upstream
transformation past any {{PartitionTransformation}}; a helper whose input has
no uid is left alone. Do it only when auto-generated UIDs are disabled, so jobs
that run with them enabled keep their operator IDs. I tried this on master with
unit tests. With a {{flink-python}} jar built from {{release-2.2}} plus this
change, used with PyFlink 2.2.1, all five rows submit, and so does the
{{partition_custom}} pipeline without a uid on the stream it returns.
*Separate decision: ignored downstream uids.* When the optimizer fuses a values
helper with a following Python operator, it gives the fused operator the
helper's uid, even when that is null, and drops the downstream operator's uid.
With stock PyFlink 2.2.1 and auto-generated UIDs enabled, changing {{x}} from
{{"map"}} to {{"other"}} in {{source.partition_custom(...).map(...).uid(x)}},
without a uid on the {{partition_custom}} stream, left every generated operator
ID unchanged; with {{key_by}} instead, the keyed {{map}}'s ID changed. I
compared {{getGeneratedOperatorID()}} values in the job graphs and didn't test
a restore. The proposal doesn't fix this: with auto-generated UIDs disabled,
the fused operator gets the derived values uid in that example, or the returned
stream's uid in row 4, and with them enabled nothing changes. Keeping the
downstream operator's own uid when a values helper is fused into it would fix
it, but it changes the generated IDs of existing fused operators, so savepoint
compatibility needs its own decision.
[~dianfu], does the derived-uid approach work for you for the first part? I'd
like to work on it, and I'd file the ignored-uid part as its own ticket unless
you'd rather handle both here.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)