ODPS_ele—UDF Python API
自定义函数(UDF)
UDF全称User Defined Function,即用户自定义函数。ODPS提供了很多内建函数来满足用户的计算需求,同时用户还可以通过创建自定义函数来满足不同的计算需求。UDF在使用上与普通的 SQL内建函数 类似。
在ODPS中,用户可以扩展的UDF有三种,分别是:
UDF 分类 | 描述
User Defined Scalar Function 通常也称之为UDF
自定义函数,准确的说是用户自定义标量函数 (User Defined Scalar Function)。UDF的输入与输 出是一对一的关系,即读入一行数据, 写出一条输出值。UDAF(User Defined Aggregation Function)
自定义聚合函数,其输入与输出是多对一的关系, 即将多条输入记录聚合成一条输出值。可以与 SQL中的Group By语句联用。具体语法请参考聚合函数 。UDTF(User Defined Table Valued Function)
自定义表函数,是用来解决一次函数调用输出 多行数据场景的,也是唯一能返回多个字段的自定 义函数。而UDF及UDAF只能一次计算输出一条 返回值。
注解
UDF广义的说法代表了自定义标量函数,自定义聚合函数及自定义表函数三种类型的自定义函数的集合。狭义来说,仅代表用户自定义标量函数。文档会经常使用这一名词,请读者根据文档上下文判断具体含义。
受限环境
ODPS UDF的Python版本为2.7,并以沙箱模式执行用户代码,即代码是在一个受限的运行环境中执行的,在这个环境中,被禁止的行为包括:
- 读写本地文件
- 启动子进程
- 启动线程
- 使用socket通信
- 其他系统调用
基于上述原因,用户上传的代码必须都是纯Python实现,C扩展模块是被禁止的。
此外,Python的标准库中也不是所有模块都可用,涉及到上述功能的模块都会被禁止。具体标准库可用模块说明如下:
- 所有纯Python实现(不依赖扩展模块)的模块都可用
- C实现的扩展模块中下列模块可用
|
- 部分模块功能受限。比如沙箱限制了用户代码最多能往标准输出和标准错误输出写出数据的大小,即``sys.stdout/sys.stderr``最多能写20Kb,多余的字符会被忽略。
第三方库
运行环境中还安装了除标准库以外比较常用的三方库,做为标准库的补充。支持的三方库列表如下:
- numpy
警告
三方库的使用同样受到禁止本地、网络IO或其他在受限环境下的限制,因此三方库中涉及到相关功能的API也是被禁止的。
参数与返回值类型
@odps.udf.annotate(signature)
Python UDF目前支持ODPS SQL数据类型有:bigint, string, double, boolean和datetime。SQL语句在执行之前,所有函数的参数类型和返回值类型必须确定。因此对于Python这一动态类型语言,需要通过对UDF类加decorator的方式指定函数签名。
函数签名signature通过字符串指定,语法如下:
arg_type_list '->' type_list |
- 箭头左边表示参数类型,右边表示返回值类型。
- 只有UDTF的返回值可以是多列, UDF和UDAF只能返回一列。
- ‘*’代表变长参数,使用变长参数,UDF/UDTF/UDAF可以匹配任意输入参数。
下面是合法的signature的例子:
'bigint,double->string' # 参数为bigint、double,返回值为string # UDTF参数为bigint、boolean,返回值为string,datetime '*->string' # 变长参数, 输入参数任意 ,返回值为string |
Query语义解析阶段会将检查到不符合函数签名的用法,抛出错误禁止执行。执行期,UDF函数的参数会以函数签名指定的类型传给用户。用户的返回值类型也要与函数签名指定的类型一致,否则检查到类型不匹配时也会报错。ODPS SQL数据类型对应Python类型如下:
注解
|
odps.udf.int(value[, silent=True])
Python builtin函数 int 的修改。增加了参数 silent 。当 silent 为 True 时,如果 value 无法转为 int ,不会抛出异常,而是返回 None 。
UDF
实现Python UDF非常简单,只需要定义一个new-style class,并实现 evaluate 方法。下面是一个例子:
from odps.udf import annotate @annotate("bigint,bigint->bigint") |
注解:Python UDF必须通过annotate指定函数签名
UDAF
- class odps.udf.BaseUDAF
-
继承此类实现Python UDAF。
- BaseUDAF.new_buffer()
-
实现此方法返回聚合函数的中间值的buffer。buffer必须是mutable object(比如list, dict),并且buffer的大小不应该随数据量递增,在极限情况下,buffer marshal过后的大小不应该超过2Mb。
- BaseUDAF.iterate(buffer[, args, ...])
-
实现此方法将args聚合到中间值buffer中。
- BaseUDAF.merge(buffer, pbuffer)
-
实现此方法将两个中间值buffer聚合到一起,即将pbuffer merge到buffer中。
- BaseUDAF.terminate(buffer)
-
实现此方法将中间值buffer转换为ODPS SQL基本类型。
下面是一个UDAF求平均值的例子。
#coding:utf-8 |
UDTF
- class odps.udf.BaseUDTF
-
Python UDTF的基类,用户继承此类,并实现 process, close 等方法。
- BaseUDTF.__init__()
-
初始化方法,继承类如果实现这个方法,则必须在一开始调用基类的初始化方法 super(BaseUDTF,self).__init__() 。
__init__ 方法在整个UDTF生命周期中只会被调用一次,即在处理第一条记录之前。当UDTF需要保存内部状态时,可以在这个方法中初始化所有状态。
- BaseUDTF.process([args, ...])
-
这个方法由ODPS SQL框架调用,SQL中每一条记录都会对应调用一次 process , process 的参数为SQL语句中指定的UDTF输入参数。
- BaseUDTF.forward([args, ...])
-
UDTF的输出方法,此方法由用户代码调用。每调用一次 forward ,就会输出一条记录。 forward 的参数为SQL语句中指定的UDTF的输出参数。
- BaseUDTF.close()
-
UDTF的结束方法,此方法由ODPS SQL框架调用,并且只会被调用一次,即在处理完最后一条记录之后。
下面是一个UDTF的例子。
#coding:utf-8 from odps.udf import annotate |
注解
Python UDTF也可以不加annotate指定参数类型和返回值类型。这样,函数在SQL中使用时可以匹配任意输入参数,但返回值类型无法推导,所有输出参数都将认为是string类型。因此在调用 forward 时,就必须将所有输出值转成 str 类型。
引用资源
Python UDF可以通过 odps.distcache 模块引用资源文件,目前支持引用文件资源和表资源。
- odps.distcache.get_cache_file(resource_name)
-
release-2012.09.03 新版功能.
返回指定名字的资源内容。 resource_name 为 str 类型,对应当前Project中已存在的资源名。如果资源名非法或者没有相应的资源,会抛出异常。
返回值为 file-like object ,在使用完这个object后,调用者有义务调用 close 方法释放打开的资源文件。
下面是使用 get_cache_file 的例子:
from odps.udf import annotate |
odps.distcache.get_cache_table(resource_name)
release-2012.11.14 新版功能.
返回指定资源表的内容。 resource_name 为 str 类型,对应当前Project中已存在的资源表名。如果资源名非法或者没有相应的资源,会抛出异常。
返回值为 generator 类型,调用者通过遍历获取表的内容,每次遍历得到的是以 tuple 形式存在的表中的一条记录。
下面是使用 get_cache_table 的例子:
from odps.udf import annotate |
注意事项
表达式优化
当一个Query中有多个相同UDF,并且他们的参数也都一致时,这些UDF在执行时会被优化成只执行一次。例如:
random.seed(12345)
@annotate('bigint->bigint')
class MyRand(object):
def evaluate(self, a):
return random.randint(0, 10)
实现一个Rand函数,希望每次调用Rand时返回一个随机值。
> select MyRand(c_int_a), MyRand(c_int_a) from udf_test;
+------------+------------+
| _c0 | _c1 |
+------------+------------+
| 4 | 4 |
| 0 | 0 |
| 9 | 9 |
| 3 | 3 |
+------------+------------+
可以看到默认情况下,同一行的两次Rand调用返回值结果一样,这是因为被优化后只执行一次导致的。如果不想要这个优化,可以通过设置配置项odps.sql.udf.optimize.reuse 取消这个优化:
> set odps.sql.udf.optimize.reuse=false;
> select MyRand(c_int_a), MyRand(c_int_a) from udf_test;
+------------+------------+
| _c0 | _c1 |
+------------+------------+
| 4 | 0 |
| 9 | 3 |
| 4 | 2 |
| 6 | 1 |
+------------+------------+
总结
ODPS为Python提供的类有
1. 参数与返回值类型
@odps.udf.annotate(signature),ODPS SQL数据类型对应Python类型如下:
odps.udf.int(value[, silent=True])
2. UDF
# 定义一个new-style class,并实现 evaluate 方法
from odps.udf import annotate |
3. UDAF
class odps.udf.BaseUDAF—继承此类实现Python UDAF。
BaseUDAF类拥有的四个方法如下:
- BaseUDAF.new_buffer()
- BaseUDAF.iterate(buffer[, args, ...])
- BaseUDAF.merge(buffer, pbuffer)
- BaseUDAF.terminate(buffer)¶
-
下面是一个UDAF求平均值的例子。
#coding:utf-8 |
4.UDTF
class odps.udf.BaseUDTF—Python UDTF的基类,用户继承此类,并实现 process , close 等方法。
BaseUDTF类拥有的四个方法
- BaseUDTF.__init__()
- BaseUDTF.process([args, ...])
- BaseUDTF.forward([args, ...])
- BaseUDTF.close()
- 下面是一个UDTF的例子。
#coding:utf-8 from odps.udf import annotate |
ODPS_ele—UDF Python API的更多相关文章
- 《Spark Python API 官方文档中文版》 之 pyspark.sql (一)
摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...
- 《Spark Python API 官方文档中文版》 之 pyspark.sql (四)
摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...
- 如何在 Apache Flink 中使用 Python API?
本文根据 Apache Flink 系列直播课程整理而成,由 Apache Flink PMC,阿里巴巴高级技术专家 孙金城 分享.重点为大家介绍 Flink Python API 的现状及未来规划, ...
- Appium python API 总结
Appium python api 根据testerhome的文章,再补充一些文章里面没有提及的API [TOC] [1]find element driver 的方法 注意:这几个方法只能通过sel ...
- The novaclient Python API
The novaclient Python API Usage First create a client instance with your credentials: >>> f ...
- Openstack python api 学习文档 api创建虚拟机
Openstack python api 学习文档 转载请注明http://www.cnblogs.com/juandx/p/4953191.html 因为需要学习使用api接口调用openstack ...
- BotVS开发基础—Python API
代码 import json def main(): # python API列表 https://www.botvs.com/bbs-topic/443 #状态信息 LogStatus(" ...
- 《Spark Python API 官方文档中文版》 之 pyspark.sql (二)
摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...
- HBase Python API
HBase Python API HBase通过thrift机制可以实现多语言编程,信息通过端口传递,因此Python是个不错的选择 吐槽 博主在Mac上配置HBase,奈何Zoomkeeper一直报 ...
随机推荐
- Jenkins 构建运行java程序
我们将在Jenkins建立执行一个简单的 HelloWorld 应用程序,构建和运行Java程序.打开网址:http://localhost:8080/jenkins 第1步- 转到Jenkins 仪 ...
- UE4中Timeline的使用
UE4中经常需要一些和时间相联系的功能,例如在一段时间内完成一个动作,播放一段动画,或者只是单纯的延迟函数的执行时间,即调整事件的执行顺序.在UE4的蓝图自带函数中有一个很好用的函数可以完美地解决这些 ...
- 在CentOS上搭建PHP服务器环境(可用)
原文:https://www.cnblogs.com/zy2009/p/7047828.html 1,先安装apache: yum install httpd 配置ServerName vi /etc ...
- 第一周:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
姓名:吕松鸿 学号:20135229 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- 2013337朱荟潼 Linux第十八章读书笔记——调试
第十八章 调试 0.总结 oops 内核的调试配置 用Git进行二分搜索 bug总会有,简洁描述发给LKML 1. 准备开始 在用户级的程序里,bug表现比较直接:在内核中却不清晰. 2. 内核中的b ...
- Java单元测试框架 JUnit
Java单元测试框架 JUnit JUnit是一个Java语言的单元测试框架.它由Kent Beck和Erich Gamma建立,逐渐成为源于KentBeck的sUnit的xUnit家族中为最成功的一 ...
- 数学口袋精灵app(小学生四则运算app)开发需求
数学口袋精灵APP,摒除了传统乏味无趣学习数学四则运算的模式,采用游戏的形式,让小朋友在游戏中学习,培养了小朋友对数学的兴趣,让小朋友在游戏中运算能力得到充分提升.快乐学习,成长没烦恼! 项目名字:“ ...
- 使用HTTP协议向服务器传参的方式及django中获取参数的方式
使用HTTP协议向服务器传参的四种方式 URL路径携带参数,形如/weather/beijing/2018; 查询字符串(query string),形如key1=value1&key2=va ...
- Python3的bytes和str之别
Python3不会以任意隐式的方式混用str和bytes,正是这使得:两者的区分特别清晰,在使用Python时不能拼接字符串和字节包,也无法搜索字节包里面的字符串(反之亦然),也不能讲字符串传入参数为 ...
- js用currentStyle和getComputedStyle获取css样式(非行间) 兼容ie与火狐
用js的style属性可以获得html标签的样式,但是不能获取非行间样式.那么怎么用js获取css的非行间样式呢?在IE下可以用currentStyle,而在火狐下面我们需要用到getComputed ...