PyFlink Table API Data Types DataType 是什么、UDF 类型声明怎么写、Python / Pandas 类型映射一文搞懂

1. DataType 是什么:逻辑类型,不等于物理存储类型

DataType 描述的是 表生态里一个值的逻辑类型(Logical Type) ,比如 BIGINTVARCHARDECIMAL(10,2)ROW<...>

关键理解点:

  • DataType 只定义"是什么类型",不暗示它在网络传输或存储时怎么编码(那是物理表示层的事情)。
  • PyFlink 中所有预定义类型都在 pyflink.table.types,并且推荐用 DataTypes 工具类来构造。

典型写法:

python 复制代码
from pyflink.table.types import DataTypes

DataTypes.BIGINT()
DataTypes.STRING()
DataTypes.ROW([DataTypes.FIELD("id", DataTypes.BIGINT()),
               DataTypes.FIELD("name", DataTypes.STRING())])

在写 UDF 时,你常会看到两种声明方式:

  • 用字符串:result_type='ROW<id BIGINT, data STRING>'
  • 用 DataTypes:result_type=DataTypes.ROW([...])

两者都行;工程里建议 DataTypes 写法更安全(IDE 友好,拼写不易错)。

2. DataType 与 Python 类型映射:UDF 参数/返回值怎么落地

当你在 UDF 声明了 DataType,Flink 会做两件事:

1)把输入列值转换成对应的 Python 对象传给你

2)要求你的返回值类型匹配你声明的 DataType(否则运行时会报类型/序列化问题)

你给的映射表可以直接当"速查表"。

2.1 标量 UDF:DataType → Python Type

Data Type Python Type
BOOLEAN bool
TINYINT / SMALLINT / INT / BIGINT int
FLOAT / DOUBLE float
VARCHAR str
VARBINARY bytes
DECIMAL decimal.Decimal
DATE datetime.date
TIME datetime.time
TimestampType datetime.datetime
LocalZonedTimestampType datetime.datetime
INTERVAL YEAR TO MONTH int(注意:pandas 不支持)
INTERVAL DAY TO SECOND datetime.timedelta(注意:pandas 不支持)
ARRAY list
MULTISET list(Not Supported Yet in pandas)
MAP dict(Not Supported Yet in pandas)
ROW pyflink.common.Row

2.2 向量化 pandas UDF:输入/输出是 pandas.Series(元素类型由 DataType 决定)

文档里的核心点是:

对于 vectorized Python UDF,输入类型和输出类型是 pandas.Series,Series 里每个元素类型对应你声明的 DataType。

映射中 pandas type 这一列很关键:

Data Type Pandas Type
BOOLEAN numpy.bool_
INT numpy.int32
BIGINT numpy.int64
FLOAT numpy.float32
DOUBLE numpy.float64
VARCHAR str
VARBINARY bytes
DECIMAL decimal.Decimal
DATE / TIME / Timestamp datetime.*
ARRAY numpy.ndarray
ROW dict

注意:表里也写了很多 Not Supported Yet ,比如 MAP/MULTISET/INTERVAL 在 pandas UDF 场景还不支持或不完整,生产里尽量绕开或提前验证。

3. 复合类型在 UDF 中的使用:ARRAY / MAP / ROW

这是工程里最容易踩坑的部分:复合类型传到 Python 侧会变成什么?

3.1 ARRAY:Python 侧是 list(pandas 侧是 ndarray)

  • 标量 UDF:拿到的是 list
  • pandas UDF:单元格可能是 numpy.ndarray

示例(标量 UDF):

python 复制代码
from pyflink.table.udf import udf
from pyflink.table.types import DataTypes

@udf(
    input_types=[DataTypes.ARRAY(DataTypes.INT())],
    result_type=DataTypes.INT()
)
def array_len(arr):
    return len(arr) if arr is not None else 0

3.2 MAP:Python 侧是 dict(pandas UDF 暂不支持)

MAP 在 Python 标量 UDF 中是 dict,但 pandas UDF 不支持(表里明确写了 Not Supported Yet),如果你需要向量化处理 MAP,通常要先在 SQL/Table 层把 MAP 展开/转换成基础列。

3.3 ROW:Python 侧是 Row(pandas UDF 侧是 dict)

  • 标量 UDF:ROW → pyflink.common.Row
  • pandas UDF:ROW → dict

这也是为什么你在 Row-based Operations 里看到两种写法:

  • def func2(r: Row) -> Row: ...
  • pandas 模式下 DataFrame 里取列,再拼 DataFrame 返回

4. 为什么"声明类型"很重要:类型决定运行时转换与序列化

在 PyFlink 里,很多问题的根源都是"类型不明确":

  • 你写 UDF 返回了 Python int,但声明的是 STRING
  • 你返回 Row 的字段数量/顺序与声明的 ROW<...> 不一致
  • pandas UDF 返回列的 dtype 跟 DataType 冲突
  • 你用了 pandas UDF 但传了 MAP/INTERVAL 等 pandas 不支持类型

最稳的做法是:

  • UDF 明确写 input_types / result_type(不要只靠推断)
  • 复合类型尽量用 DataTypes.ROW/ARRAY/... 明确结构
  • pandas UDF 场景优先用基础数值/字符串/时间类型

5. 给你一套"UDF 类型声明模板"(生产更稳)

5.1 标量 UDF:建议用 DataTypes 写清楚

python 复制代码
from pyflink.table.udf import udf
from pyflink.table.types import DataTypes

@udf(
    input_types=[DataTypes.BIGINT(), DataTypes.STRING()],
    result_type=DataTypes.ROW([
        DataTypes.FIELD("id", DataTypes.BIGINT()),
        DataTypes.FIELD("data", DataTypes.STRING())
    ])
)
def enrich(id_, data):
    from pyflink.common import Row
    return Row(id_, data + "_x")

5.2 pandas UDF:牢记输入输出是 Series/DataFrame(元素类型由 DataType 控制)

python 复制代码
import pandas as pd
from pyflink.table.udf import udf
from pyflink.table.types import DataTypes

@udf(
    result_type=DataTypes.ROW([
        DataTypes.FIELD("id", DataTypes.BIGINT()),
        DataTypes.FIELD("data", DataTypes.STRING())
    ]),
    func_type="pandas"
)
def enrich_vec(df: pd.DataFrame) -> pd.DataFrame:
    return pd.concat([df["id"], df["data"] + "_x"], axis=1)

如果你接下来要写 CSDN 系列文章,我建议你把这一篇作为"类型基础篇",下一篇可以直接承接你前面写的 Row-based Operations:把每种算子(map/flat_map/aggregate/flat_aggregate)里涉及到的 result_typeinput_types、ROW 扁平化、pandas 模式的 dtype 坑,都用本文的类型映射做解释,会非常连贯。

相关推荐
functionflux4 分钟前
kafka-python:Python 生态中最成熟的 Kafka 客户端
分布式·python·其他·kafka
帅小伙―苏12 分钟前
239. 滑动窗口最大值
python·力扣
浩风祭月18 分钟前
我用 AI 辅助重构了遗留项目的认证模块:从明文存储到 OAuth 2.0 的安全升级
后端·php·ai编程
爱吃苹果的梨叔23 分钟前
2026年KVM over IP采购指南:BIOS级接管、并发和审计怎么验收
ide·python·tcp/ip·github
Cloud_Shy61829 分钟前
解读《Effective Python 3rd Edition》:从练气到老魔(第六章 Item 40 - 43)
android·开发语言·人工智能·笔记·python·学习方法
装不满的克莱因瓶30 分钟前
掌握生成对抗网络(GAN)的优化目标与评估指标——从博弈函数到生成质量衡量体系
人工智能·python·深度学习·算法·机器学习
半只小闲鱼35 分钟前
配置计划模块通用办公设备家具批复数合计计算
开发语言·python
是阿千呀!35 分钟前
A股市场风格切换研究:基于 Barra 风险模型的量化框架
python·量化
大蚂蚁2号1 小时前
短视频批量生成技术深度解析与实战方案
python·aigc·音视频
努力写A题的小菜鸡1 小时前
PyTorch 两种卷积写法彻底对比:F.conv2d 函数式 vs nn.Conv2d 类实战(超详细入门笔记)
python