UDF基本概念
- udf
一条输入对应一条输出。
select concat('a','b') from cid_dd
// 结果 ab
- UDTF
一条输入对应着多条输出
select bi_udtf:split_rows("a,b") from cid_dd
// 结果: a
// b
- UDAF:
多条输入对应一条输出
select wm_concat(col, ',') from cid_dd
// 结果 a,b
限制
环境限制
MaxCompute UDF的python版本为2.7,并以沙箱模式执行用户代码,即代码是在一个受限的运行环境中执行的。以下行为是被禁止的
- 读写本地文件
- 启动子进程
- 启动线程
- 使用Socket通信
- 其他系统的调用
参数和返回值类型
参数和返回值指定方式如下:
@odps.udf.annotate(signature)
Python UDF 目前支持的数据类型包含 bigint, string, double, boolean, datetime
。sql语句在执行之前,必须确认所有函数的参数类型和返回值类型。因此对于python动态类型语言,需要通过对UDF类加上Decorator方式指定函数签名。
合法的Signature示例如下:
'bigint,double->string' # 参数为bigint、double,返回值为string。
'bigint,boolean->string,datetime' # UDTF参数为bigint、boolean,返回值为string,datetime。
'*->string' # 变长参数,输入参数任意,返回值为string。
'->double' # 参数为空,返回值为double。
MaxCompute SQL数据类型对应的Python类型如下
UDF 开发
实现Python UDF非常简单,只需要定义一个 new-style class,并实现evaluate
方法
from odps.udf import annotate
# 标记输入的参数类型
@annotate("string->string")
class Hello(object):
def evaluate(self, arg0):
return arg0 + 'Hello'
如何调试和查看输出
Hello("dankun_")
// 结果 dankun_Hello
UDTF
from odps.udf import annotate
from odps.udf import BaseUDTF
@annotate('string -> string')
class Explode(BaseUDTF):
"""将string按逗号分隔输出成多条记录。
def process(self, arg):
props = arg.split(',')
for p in props:
self.forward(p)
- class odps.udf.BaseUDTF: Python UDTF 的基类,实现
process
,close
等方法 - BaseUDTF.init(): 初始化方法。继承类如果需要实现这个方法,必须在一开始调用基类的初始化方法
super(BaseUDTF, self).__init__()
。init方法在整个UDTF生命周期中只会被调用一次,即在处理第一条记录之前。当UDTF需要保存内部状态时,可以在这个方法中初始化所有状态 - BaseUDTF.process([args, ...]),这个方法由框架调用,SQL中每一条记录都会对应调用一次
process
,process
的参数为SQL语句中指定的UDTF输入参数 - BaseUDTF.forward([args, ...]): UDTF的输出方法(类似于return ),由用户代码调用。每调用一次
forward
,便会输出一条记录。forward
的参数为SQL语句中指定的UDTF的输出参数 - BaseUDTF.close(): UDTF的结束方法。此方法由MaxCompute SQL框架调用,并且只会被调用一次,即在处理完最后一条记录之后。
UDAF
from odps.udf import annotate
from odps.udf import BaseUDAF
@annotate('double->double')
class Average(BaseUDAF):
def new_buffer(self):
return [0, 0]
def iterate(self, buffer, number):
if number is not None:
buffer[0] += number
buffer[1] += 1
def merge(self, buffer, pbuffer):
buffer[0] += pbuffer[0]
buffer[1] += pbuffer[1]
def terminate(self, buffer):
if buffer[1] == 0:
return 0.0
return buffer[0] / buffer[1]
-
class odps.udf.BaseUDAF
:继承此类实现Python UDAF。 -
BaseUDAF.new_buffer()
:实现此方法返回聚合函数的中间值的buffer
。buffer
必须是marshallableObject(例如LIST、DICT),并且buffer
的大小不应该随数据量递增。在极限情况下,buffer
Marshal过后的大小不应该超过2MB。 -
BaseUDAF.iterate(buffer[, args, ...])
:实现此方法将args
聚合到中间值buffer
中。 -
BaseUDAF.merge(buffer, pbuffer)
:实现此方法将两个中间值buffer
聚合到一起,即将pbuffer
合并到buffer
中。 -
BaseUDAF.terminate(buffer)
:实现此方法将中间值buffer
转换为MaxCompute SQL的基本类型。