我开始在Redshift中学习Python用户定义的函数,我有几个问题需要澄清。假设我已经定义了以下函数:
CREATE OR REPLACE FUNCTION f_parse_url_query_string(url VARCHAR(MAX))
RETURNS varchar(max)
STABLE
AS $$
from urlparse import urlparse, parse_qsl
import json
return json.dumps(dict(parse_qsl(urlparse(url)[4])))
$$ LANGUAGE plpythonu;
每次调用该函数时这是运行imports
还是由Redshift编译并且只导入一次?
我的第二个问题是是否有办法返回可变数据类型。例如,如果我想创建一个抓取嵌套json字段值的函数,结果可以是从字符串到整数或布尔值的任何内容。有没有在函数返回类型上创建自动检测?
答案 0 :(得分:1)
<强>执行强>
是的,import
每次都会执行。
避免这种情况的一种方法是使用IMMUTABLE
作为函数的波动率。这允许Redshift为给定的输入值缓存函数的输出,从而避免将来为相同的输入值运行Python函数。
返回值
返回值的数据类型是固定的,不能更改。可以为不同的函数名称或不同的输入类型定义不同的返回值(例如,定义一个接收的函数)整数并返回一个整数,然后是另一个具有相同名称的函数,但字符串输入类型返回一个字符串作为输出。)
此外,使用返回不同输出数据类型的函数将非常困难 - 调用UDF的SQL语句将需要特定的数据类型,而不是更改的类型。
答案 1 :(得分:1)
<强>进口强>
是和否。 Redshift在语句中重用udf执行环境(甚至可能在整个事务中,但我还没有测试过)。虽然每次在处理导入语句时调用函数都会处理import语句,但cpython会快速检查模块是否已导入并使用已导入的模块(如果已导入)。像这样的函数本地(后期)导入经常用于解决循环依赖问题,因此必须具有高性能。我也使用它来解决udf中缺少全局初始化的问题,方法如下:
if '_cache' not in globals():
import thing
globals()['_cache'] = thing.build_cache()
return _cache.get(arg)
除了udf之外,这不是我要做的事情,但这不是通用代码。
关于udf执行环境,它显然是非常详细的,不应过分依赖,但实际上它不太可能很快改变。无法保证任何特定进程的使用寿命/它将处理多少行,但是只要它们可以保持它们,因为cpython进程(和容器)创建并不是很便宜 - 当然每一行都太重了。他们依靠lxc进行隔离,并为您提供一个真正的(如果是沙盒的)Linux环境(如果您考虑的话,这对于用户安装的本机扩展非常必要)。对于那些关心挖掘的人来说,文件系统上甚至还有一些文档:)
返回值
虽然确实无法更改返回值的数据类型,但redshift(now?)支持参数和返回类型的ANYELEMENT数据类型。正如前面的答案所描述的那样,它仍然需要一个消除歧义的类型参数,因为仍然不支持返回类型多态,但它至少可以省去为每个要返回的类型创建单独函数的麻烦。