在每个函数调用上导入 Redshift Python UDF
Posted
技术标签:
【中文标题】在每个函数调用上导入 Redshift Python UDF【英文标题】:Redshift Python UDFs Import on Every Function Call 【发布时间】:2016-08-12 19:29:44 【问题描述】:我开始学习 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 字段值的函数,则结果可以是从字符串到整数或布尔值的任何内容。有没有办法在函数返回类型上创建自动检测?
【问题讨论】:
【参考方案1】:执行
是的,import
每次都会执行。
避免这种情况的一种方法是使用IMMUTABLE
作为函数的易变性。这允许 Redshift 缓存给定输入值的函数输出,避免将来需要为相同的输入值运行 Python 函数。
返回值
返回值的数据类型是固定的,不能更改。 可以为不同的函数名或不同的输入类型定义不同的返回值(例如定义一个函数,它接受一个整数并返回一个整数,然后是另一个具有相同名称但输入类型为字符串的函数,该函数返回一个字符串作为输出)。
此外,使用返回不同输出数据类型的函数将非常困难——调用 UDF 的 SQL 语句需要特定的数据类型,而不是更改的数据类型。
【讨论】:
【参考方案2】:进口
是和不是。 Redshift 在语句中重用 udf 执行环境(甚至可能在整个事务中,但我还没有测试过)。虽然确实每次在处理导入语句时调用函数时都会处理导入语句,但 cpython 会快速检查模块是否已导入,如果已导入,则使用已导入的模块。像这样的函数本地(后期)导入经常用于解决循环依赖问题,因此必须具有高性能。我还使用它来解决 udf 中缺少全局初始化的问题,方法是执行以下操作:
if '_cache' not in globals():
import thing
globals()['_cache'] = thing.build_cache()
return _cache.get(arg)
除了 udf 之外,我不会在任何地方做任何事情,但这并不是完全通用的代码。
关于 udf 执行环境,它显然是 impl-detail,不应过分依赖,但实际上它不太可能很快发生重大变化。无法保证任何特定进程的寿命有多长/它将处理多少行,但只要他们可以保留它们符合他们的利益,因为 cpython 进程(和容器)的创建并不便宜 - 当然对每一行来说太重了。他们依赖 lxc 进行隔离,并为您提供一个真实的(如果是沙盒)Linux 环境来执行(如果您考虑一下,这对于用户安装的本机扩展确实是必要的)。文件系统上甚至还有一些文档可供那些愿意挖掘的人使用:)
返回值
虽然返回值的数据类型确实无法更改,但 redshift(现在?)支持参数和返回类型的 ANYELEMENT 数据类型。如上一个答案所述,它仍然需要一个明确的类型化参数,因为仍然不支持返回类型多态性,但它至少可以省去为要返回的每种类型创建单独函数的麻烦。
【讨论】:
以上是关于在每个函数调用上导入 Redshift Python UDF的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 中,我可以调用导入模块的 main() 吗?
使用 NodeJS 将 RabbitMQ 导入 AWS Redshift