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 坑,都用本文的类型映射做解释,会非常连贯。

相关推荐
热心不起来的市民小周几秒前
测测你的牌:基于 MobileNetV2 的车牌内容检测
python·深度学习·计算机视觉
BinaryBoss3 分钟前
Python 从Maxcompute导出海量数据到文本文件(txt)或Excel
chrome·python·odps
落羽凉笙5 分钟前
Python基础(4)| 详解程序选择结构:单分支、双分支与多分支逻辑(附代码)
android·服务器·python
数据光子10 分钟前
【YOLO数据集】国内交通信号检测
人工智能·python·安全·yolo·目标检测·目标跟踪
百***787516 分钟前
2026 优化版 GPT-5.2 国内稳定调用指南:API 中转实操与成本优化
开发语言·人工智能·python
Amelia11111129 分钟前
day48
python
小北方城市网32 分钟前
第 6 课:云原生架构终极落地|K8s 全栈编排与高可用架构设计实战
大数据·人工智能·python·云原生·架构·kubernetes·geo
智航GIS36 分钟前
10.1 网站防爬与伪装策略
python
belldeep42 分钟前
python:pyTorch 入门教程
pytorch·python·ai·torch
YJlio44 分钟前
Registry Usage (RU) 学习笔记(15.5):注册表内存占用体检与 Hive 体量分析
服务器·windows·笔记·python·学习·tcp/ip·django