{"value":"*Mike Kong, 亚马逊云科技专业服务团队*\n\n在数据仓库深度应用的场景下,仅靠 SQL 往往很难完成我们所需要的各种特殊数据分析处理,这时候,我们有必要使用其它一些方法去完成任务,其中一种方法就是使用 UDF(User-defined Functions)即用户自定义函数。\n\n[Amazon Redshift](https://aws.amazon.com/cn/redshift/?trk=cndc-detail) 是一种快速、完全托管式 PB 级数据仓库服务,它使得通过现有商业智能工具对您的所有数据进行高效分析变得简单而实惠。[Amazon Redshift](https://aws.amazon.com/cn/redshift/?trk=cndc-detail) 支持 UDF 功能,客户可以通过 Redshift UDF 完成一些面向报表或应用的数据转换工作,与数据湖的中后台处理相互结合;客户也可以把原有的 UDF 较容易地迁移到 Redshift UDF,有效降低迁移成本,例如将基于 Java 开发的 Hive UDF 迁移到 Redshift UDF。\n\n[Amazon Redshift](https://aws.amazon.com/cn/redshift/?trk=cndc-detail) 包含了三种 UDF 实现方式,分别是 SQL UDF,Scalar Python UDF 以及 Lambda UDF。这篇博客主要介绍了 [Amazon Redshift](https://aws.amazon.com/cn/redshift/?trk=cndc-detail) UDF 不同实现方式及其效果,并对比各种实现,帮助客户在不同场景下选择合适的 UDF 实现方式。\n\n\n#### **一、SQL UDF 的实现**\n\n\nSQL UDF 是最简单的一种 UDF 实现,它通过 SQL 实现。当业务场景比较简单时,我们可以选择 SQL UDF 以较少的代码量实现相应的功能。\n\n\n#### **1. 实现方式**\n\n\n**(1)创建函数示例**\n\n该示例是简单计算(参数 1 + 参数 2 * 0.5)/ 2,比如(10 + 18 * 0.5) / 2,结果为 9.5.\n\n```\\ncreate function sf_get_avg (float, float)\\n returns float immutable as \$\$\\n select (\$1 + \$2 * 0.5) / 2\\n\$\$ language sql;\\n```\n\n**(2)SQL 调用验证**\n\n```\\nselect sf_get_avg(10,18)\\n```\n\n**(3)返回结果**\n\n![image.png](https://dev-media.amazoncloud.cn/b170a6965eab4f26806fd9c989fd742f_image.png)\n\n\n#### **二、Python UDF 的实现**\n\n\nPython UDF 是通过 Redshift 内置的 python 实现 UDF,通过 python UDF 你可以实现各种相对复杂的数据分析处理需求。\n\n\n#### **1. 实现方式**\n\n\n**(1)创建函数示例**\n\n```\\nCREATE OR REPLACE FUNCTION f_get_avg (in_param_1 float, in_param_2 float) RETURNS float IMMUTABLE as \$\$ \\n def get_avg(in_param_1, in_param_2):\\n import logging\\n \\n logger = logging.getLogger()\\n try:\\n avg_result = (in_param_1 + in_param_2 * 0.5) / 2\\n except Exception as e:\\n logger.error(str(e))\\n\\n return avg_result\\n \\n return get_avg(in_param_1, in_param_2)\\n\$\$ LANGUAGE plpythonu;\\n```\n\n**(2)SQL 调用验证**\n\n```\\nselect f_get_avg(10,18)\\n```\n\n**(3)返回结果**\n\n![image.png](https://dev-media.amazoncloud.cn/33dac55a071c4e4095dc84e786624b33_image.png)\n\n\n#### **2. 环境配置**\n\n\n#### **2.1 安装依赖包**\n\n\nRedshift Python 已经包含了常见的数据处理包(如 numpy,pandas),如果需要使用其它依赖包(需要适配于版本 python 2.7),可以下载对应包并在压缩后上传 S3,然后通过 CREATE LIBRARY 创建自定义包库,Redshift 在后台会把需要安装的包会先放在本地路径(如/rdsdbdata/user_lib/),然后解压到内部依赖包路径(/rdsdbbin/opt/redshift/lib/python2.7/site-packages/)。上述中的 CREATE LIBRARY 有两种方式实现。\n\n**Option 1** – 创建自定义包库 SQL 代码示例如下:\n\n```\\nCREATE LIBRARY fuzzywuzzy LANGUAGE plpythonu FROM 's3://your-redshift-bucket/lib/fuzzywuzzy.zip' CREDENTIALS 'aws_access_key_id=xxx;aws_secret_access_key=xxx';\\n```\n\n**Option 2** – 使用 IM Role 作为 credentials(这里假设你的 IAM Role 已配置好相应的权限):\n\n```\\nCREATE LIBRARY fuzzywuzzy LANGUAGE plpythonu FROM 's3://your-redshift-bucket/lib/fuzzywuzzy.zip' CREDENTIALS 'aws_iam_role=arn:xxxxxxxx:role/your-lambda-service-role';\\n```\n\n对于 Redshift Python 内置依赖包清单及安装自定义包的详细过程,我们可参考附录“已安装依赖包清单及安装包过程” [1]。\n\n\n#### **2.2 调试**\n\n\n调试时,我们可通过 logging/logger 把日志打印到 svl_udf_log 里,查看自定义日志信息。查看示例如下:\n\n```\\nselect * from svl_udf_log order by created desc;\\n```\n\n\n#### **2.3 注意事项**\n\n\n(1)Redshift Python 目前使用定制的 python 2.7,所有的依赖包也是基于此版本,有些包的 function 可能在此版本下并不能很好地支持,如遇到此类情况可以考虑使用 Lambda UDF 或其它形式的代码组合处理。\n\n(2)定制的 python 2.7 版本与本地部署的环境有差异,部分函数即使在本地部署的 python 2.7 测试通过,仍需在 Redshift Python 下测试验证。\n\n(3)涉及到 UTF-8 编码(如中文处理),最好在 python 头加入如下标识,避免一些中文处理的异常:\n\n```\\n# -*- coding: utf-8 -*-\\n```\n\n(4)使用 python UDF,有一些限制条件,比如:a. 用户安装的依赖包大小不可超过 100 MB;b. 不支持 SUPER 和 HLLSKETCH 数据类型等。详细情况请参考 “UDF Constraints”[2]\n\n(5)python 的数据类型一般没有长度限制,但数据库接收的返回值的数据类型是有长度限制的,过长的返回内容会引起报错。\n\n\n#### **三、Lambda UDF 的实现**\n\n\nLambda UDF 是通过 Redshift 外部服务 Amazon Lambda 实现 UDF 功能,然后通过 CREATE EXTERNAL FUNCTION 关联到对应的 Lambda 函数。\n\nLambda UDF 在入参以及出参方面,与 Python UDF 相比有明显的不同,区别如下表所示:\n\n![I77L5GN7MLLDI`6GC.png](https://dev-media.amazoncloud.cn/dc47ca9b2477458892e7a3aa77db26a0_%5DI77%29L5GN7M%40LLD%28I%5D%60%406GC.png)\n\n\n#### **1. 实现方式**\n\n\n**(1)创建函数示例**\n\n\n##### **方式一**\n\n\n我们直接把上述的 Python UDF 转化成 Lambda UDF,代码示例如下:\n\n```\\nimport json\\n\\ndef get_avg(in_param_1, in_param_2):\\n avg_result = 0\\n error_msg = ''\\n try:\\n avg_result = str((in_param_1 + in_param_2 * 0.5) / 2)\\n except Exception as e:\\n error_msg = str(e)\\n return avg_result, error_msg\\n\\n\\ndef lambda_handler(event, context):\\n error_msg = ''\\n result = list()\\n for x in event['arguments']:\\n avg_result, error_msg = get_avg(x[0], x[1])\\n result.append(avg_result)\\n\\n if (error_msg is None) | (error_msg == ''):\\n ret_json = json.dumps({\\"results\\": result, \\"success\\": True})\\n else:\\n ret_json = json.dumps({\\"success\\": False, \\"error_msg\\": error_msg})\\n return ret_json\\n\\n```\n\n\n##### **方式二**\n\n\n以下代码示例通过 pandas 进行矢量化数据处理,从而有效地提高处理性能。\n\n```\\nimport json\\nimport numpy as np\\nimport pandas as pd\\n\\ndef get_avg(list_args):\\n avg_result = list()\\n error_msg = ''\\n try:\\n df = pd.DataFrame(list_args, columns = ['in_param_1', 'in_param_2'], dtype=np.float64)\\n avg_result = (df['in_param_1'] + df['in_param_2'] * 0.5) / 2\\n except Exception as e:\\n error_msg = str(e)\\n return avg_result.tolist(), error_msg\\n\\n\\ndef lambda_handler(event, context):\\n error_msg = ''\\navg_result, error_msg = get_avg(event['arguments'])\\navg_result = avg_result.astype(str)\\n\\n if (error_msg is None) | (error_msg == ''):\\n ret_json = json.dumps({\\"results\\": avg_result, \\"success\\": True})\\n else:\\n ret_json = json.dumps({\\"success\\": False, \\"error_msg\\": error_msg})\\n return ret_json\\n```\n\n**(2)关联函数示例**\n\n```\\nCREATE OR REPLACE EXTERNAL FUNCTION ef_get_avg(NUMERIC, NUMERIC) RETURNS VARCHAR IMMUTABLE\\nLAMBDA 'ef_get_avg' IAM_ROLE 'arn:xxxxxxxx:role/your-lambda-service-role';\\n```\n\n这里假设你的 IAM Role 已配置好相应的权限\n\n**(3)SQL 调用验证**\n\n```\\nselect ef_get_avg(10,18)\\n```\n\n**(4)返回结果**\n\n![image.png](https://dev-media.amazoncloud.cn/7fad20aed5f74653b8dd2316d5568b02_image.png)\n\n\n#### **2. 环境配置**\n\n\n#### **2.1 安装依赖包**\n\n\n在亚马逊云科技海外某些区域如 us-east-1, ap-northeast-1 等,可以直接选用 Layers DataWrangler,里面已经包含了很多常用的数据处理依赖包(如 pandas, pyarrow, boto3 等),具体可参考 “Data Wrangler Github”[3]。\n\n其它没有内置 DataWrangler 的区域(如中国区),如果也想使用此依赖包,可以自行创建对应依赖包并在压缩后加载到 custom layer,详细步骤可见 “Creating and sharing Lambda Layers” [4]。\n\n\n#### **2.2 调试**\n\n\n自定义调试或报错信息,可以放入返回结果的 error_msg 中查看返回错误信息。\n\n在 Lambda 调试时,可通过 Configure test event 进行单元测试,示例如下:\n\n![image.png](https://dev-media.amazoncloud.cn/bcf55cf42c8a4c00a238fcccea181b9a_image.png)\n\n\n#### **2.3 注意事项**\n\n\n(1)Lambda python runtime 基于 python 3,默认整个处理都是基于 UTF-8,无需如 Python UDF 使用 # -*- coding: UTF-8 -*-。\n\n(2)输入参数从 Redshift 传递到 Lambda 时,使用 Json 格式的 event,从 Lambda 返回 Redshift 亦如此,详细的 Json 格式可参考 “Creating a Lambda UDF” [5]。\n\n(3)以下语句可查看已创建的 UDF 清单:\n\n```\\nselect * from pg_proc_info where prokind='f' and proname like 'ef%'; -- ef\\n```\n\n在这里代表以 ef 开头的 lambda UDF(即 External Function)\n\n\n#### **四、三种 UDF 的比较**\n\n\n以上三种 Redshift UDF 实现,各有其优劣势及其适合的场景,在这里对它们进行简单的对比:\n\n![75f4534a673e843da4c4822131e3fa8.png](https://dev-media.amazoncloud.cn/39ddacf1569f4258936f4f5eb04bf6cf_75f4534a673e843da4c4822131e3fa8.png)\n\n\n#### **结论**\n\n\n通过本文,你可以了解三种 Redshift UDF 的不同实现方法及其适合的场景。上述的示例代码可以帮助客户快速实现 Redshift UDF 交付,支持各种复杂数据分析场景。\n\n如你有其它的问题、建议或经验,欢迎留言给我们。\n\n\n#### **参考**\n\n\n[1]已安装依赖包清单及安装包过程 – [https://docs.aws.amazon.com/redshift/latest/dg/udf-python-language-support.html](https://docs.aws.amazon.com/redshift/latest/dg/udf-python-language-support.html)\n\n[2] UDF Constraints of scalar Python UDF – [https://docs.aws.amazon.com/redshift/latest/dg/udf-constraints.html](https://docs.aws.amazon.com/redshift/latest/dg/udf-constraints.html)\n\n[3] Data Wrangler Github – [https://github.com/awslabs/aws-data-wrangler](https://github.com/awslabs/aws-data-wrangler)\n\n[4] Creating and sharing Lambda Layers – [https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html)\n\n[5] Creating a Lambda UDF – [https://docs.aws.amazon.com/redshift/latest/dg/udf-creating-a-lambda-sql-udf.html](https://docs.aws.amazon.com/redshift/latest/dg/udf-creating-a-lambda-sql-udf.html)\n\n\n#### **本篇作者**\n\n\n![image.png](https://dev-media.amazoncloud.cn/26b04771ba854ab6a547df45a0c53893_image.png)\n\n\n#### **孔庆强**\n\n\n亚马逊云科技专业服务团队的大数据顾问,十多年从事数据湖仓及数据分析,为客户提供数据建模、数据治理及整体专业数据解决方案。在个人爱好方面,喜爱健身、音乐、旅行。\n\n![image.png](https://dev-media.amazoncloud.cn/ad906daecdf240e69cec4191c71bd51d_image.png)\n\n\n#### **赵鑫**\n\n\n亚马逊云科技专业服务团队数据架构师,专注于生命科学、自动驾驶领域的数据架构与数据分析\n\n![image.png](https://dev-media.amazoncloud.cn/c91e60aceeb54f21b7a9f982c1ddcbb0_image.png)\n\n\n#### **李烨炜**\n\n\n亚马逊云科技专业服务团队大数据咨询顾问。专注于企业级客户云上数据架构与数据平台设计等相关咨询服务。","render":"<p><em>Mike Kong, 亚马逊云科技专业服务团队</em></p>\\n<p>在数据仓库深度应用的场景下,仅靠 SQL 往往很难完成我们所需要的各种特殊数据分析处理,这时候,我们有必要使用其它一些方法去完成任务,其中一种方法就是使用 UDF(User-defined Functions)即用户自定义函数。</p>\n<p>Amazon Redshift 是一种快速、完全托管式 PB 级数据仓库服务,它使得通过现有商业智能工具对您的所有数据进行高效分析变得简单而实惠。Amazon Redshift 支持 UDF 功能,客户可以通过 Redshift UDF 完成一些面向报表或应用的数据转换工作,与数据湖的中后台处理相互结合;客户也可以把原有的 UDF 较容易地迁移到 Redshift UDF,有效降低迁移成本,例如将基于 Java 开发的 Hive UDF 迁移到 Redshift UDF。</p>\n<p>Amazon Redshift 包含了三种 UDF 实现方式,分别是 SQL UDF,Scalar Python UDF 以及 Lambda UDF。这篇博客主要介绍了 Amazon Redshift UDF 不同实现方式及其效果,并对比各种实现,帮助客户在不同场景下选择合适的 UDF 实现方式。</p>\n<h4><a id=\\"SQL_UDF__9\\"></a><strong>一、SQL UDF 的实现</strong></h4>\\n<p>SQL UDF 是最简单的一种 UDF 实现,它通过 SQL 实现。当业务场景比较简单时,我们可以选择 SQL UDF 以较少的代码量实现相应的功能。</p>\n<h4><a id=\\"1__15\\"></a><strong>1. 实现方式</strong></h4>\\n<p><strong>(1)创建函数示例</strong></p>\\n<p>该示例是简单计算(参数 1 + 参数 2 * 0.5)/ 2,比如(10 + 18 * 0.5) / 2,结果为 9.5.</p>\n<pre><code class=\\"lang-\\">create function sf_get_avg (float, float)\\n returns float immutable as \$\$\\n select (\$1 + \$2 * 0.5) / 2\\n\$\$ language sql;\\n</code></pre>\\n<p><strong>(2)SQL 调用验证</strong></p>\\n<pre><code class=\\"lang-\\">select sf_get_avg(10,18)\\n</code></pre>\\n<p><strong>(3)返回结果</strong></p>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/b170a6965eab4f26806fd9c989fd742f_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"Python_UDF__40\\"></a><strong>二、Python UDF 的实现</strong></h4>\\n<p>Python UDF 是通过 Redshift 内置的 python 实现 UDF,通过 python UDF 你可以实现各种相对复杂的数据分析处理需求。</p>\n<h4><a id=\\"1__46\\"></a><strong>1. 实现方式</strong></h4>\\n<p><strong>(1)创建函数示例</strong></p>\\n<pre><code class=\\"lang-\\">CREATE OR REPLACE FUNCTION f_get_avg (in_param_1 float, in_param_2 float) RETURNS float IMMUTABLE as \$\$ \\n def get_avg(in_param_1, in_param_2):\\n import logging\\n \\n logger = logging.getLogger()\\n try:\\n avg_result = (in_param_1 + in_param_2 * 0.5) / 2\\n except Exception as e:\\n logger.error(str(e))\\n\\n return avg_result\\n \\n return get_avg(in_param_1, in_param_2)\\n\$\$ LANGUAGE plpythonu;\\n</code></pre>\\n<p><strong>(2)SQL 调用验证</strong></p>\\n<pre><code class=\\"lang-\\">select f_get_avg(10,18)\\n</code></pre>\\n<p><strong>(3)返回结果</strong></p>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/33dac55a071c4e4095dc84e786624b33_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"2__79\\"></a><strong>2. 环境配置</strong></h4>\\n<h4><a id=\\"21__82\\"></a><strong>2.1 安装依赖包</strong></h4>\\n<p>Redshift Python 已经包含了常见的数据处理包(如 numpy,pandas),如果需要使用其它依赖包(需要适配于版本 python 2.7),可以下载对应包并在压缩后上传 S3,然后通过 CREATE LIBRARY 创建自定义包库,Redshift 在后台会把需要安装的包会先放在本地路径(如/rdsdbdata/user_lib/),然后解压到内部依赖包路径(/rdsdbbin/opt/redshift/lib/python2.7/site-packages/)。上述中的 CREATE LIBRARY 有两种方式实现。</p>\n<p><strong>Option 1</strong> – 创建自定义包库 SQL 代码示例如下:</p>\\n<pre><code class=\\"lang-\\">CREATE LIBRARY fuzzywuzzy LANGUAGE plpythonu FROM 's3://your-redshift-bucket/lib/fuzzywuzzy.zip' CREDENTIALS 'aws_access_key_id=xxx;aws_secret_access_key=xxx';\\n</code></pre>\\n<p><strong>Option 2</strong> – 使用 IM Role 作为 credentials(这里假设你的 IAM Role 已配置好相应的权限):</p>\\n<pre><code class=\\"lang-\\">CREATE LIBRARY fuzzywuzzy LANGUAGE plpythonu FROM 's3://your-redshift-bucket/lib/fuzzywuzzy.zip' CREDENTIALS 'aws_iam_role=arn:xxxxxxxx:role/your-lambda-service-role';\\n</code></pre>\\n<p>对于 Redshift Python 内置依赖包清单及安装自定义包的详细过程,我们可参考附录“已安装依赖包清单及安装包过程” [1]。</p>\n<h4><a id=\\"22__102\\"></a><strong>2.2 调试</strong></h4>\\n<p>调试时,我们可通过 logging/logger 把日志打印到 svl_udf_log 里,查看自定义日志信息。查看示例如下:</p>\n<pre><code class=\\"lang-\\">select * from svl_udf_log order by created desc;\\n</code></pre>\\n<h4><a id=\\"23__112\\"></a><strong>2.3 注意事项</strong></h4>\\n<p>(1)Redshift Python 目前使用定制的 python 2.7,所有的依赖包也是基于此版本,有些包的 function 可能在此版本下并不能很好地支持,如遇到此类情况可以考虑使用 Lambda UDF 或其它形式的代码组合处理。</p>\n<p>(2)定制的 python 2.7 版本与本地部署的环境有差异,部分函数即使在本地部署的 python 2.7 测试通过,仍需在 Redshift Python 下测试验证。</p>\n<p>(3)涉及到 UTF-8 编码(如中文处理),最好在 python 头加入如下标识,避免一些中文处理的异常:</p>\n<pre><code class=\\"lang-\\"># -*- coding: utf-8 -*-\\n</code></pre>\\n<p>(4)使用 python UDF,有一些限制条件,比如:a. 用户安装的依赖包大小不可超过 100 MB;b. 不支持 SUPER 和 HLLSKETCH 数据类型等。详细情况请参考 “UDF Constraints”[2]</p>\n<p>(5)python 的数据类型一般没有长度限制,但数据库接收的返回值的数据类型是有长度限制的,过长的返回内容会引起报错。</p>\n<h4><a id=\\"Lambda_UDF__130\\"></a><strong>三、Lambda UDF 的实现</strong></h4>\\n<p>Lambda UDF 是通过 Redshift 外部服务 Amazon Lambda 实现 UDF 功能,然后通过 CREATE EXTERNAL FUNCTION 关联到对应的 Lambda 函数。</p>\n<p>Lambda UDF 在入参以及出参方面,与 Python UDF 相比有明显的不同,区别如下表所示:</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/dc47ca9b2477458892e7a3aa77db26a0_%5DI77%29L5GN7M%40LLD%28I%5D%60%406GC.png\\" alt=\\"I77L5GN7MLLDI`6GC.png\\" /></p>\n<h4><a id=\\"1__140\\"></a><strong>1. 实现方式</strong></h4>\\n<p><strong>(1)创建函数示例</strong></p>\\n<h5><a id=\\"_146\\"></a><strong>方式一</strong></h5>\\n<p>我们直接把上述的 Python UDF 转化成 Lambda UDF,代码示例如下:</p>\n<pre><code class=\\"lang-\\">import json\\n\\ndef get_avg(in_param_1, in_param_2):\\n avg_result = 0\\n error_msg = ''\\n try:\\n avg_result = str((in_param_1 + in_param_2 * 0.5) / 2)\\n except Exception as e:\\n error_msg = str(e)\\n return avg_result, error_msg\\n\\n\\ndef lambda_handler(event, context):\\n error_msg = ''\\n result = list()\\n for x in event['arguments']:\\n avg_result, error_msg = get_avg(x[0], x[1])\\n result.append(avg_result)\\n\\n if (error_msg is None) | (error_msg == ''):\\n ret_json = json.dumps({"results": result, "success": True})\\n else:\\n ret_json = json.dumps({"success": False, "error_msg": error_msg})\\n return ret_json\\n\\n</code></pre>\\n<h5><a id=\\"_180\\"></a><strong>方式二</strong></h5>\\n<p>以下代码示例通过 pandas 进行矢量化数据处理,从而有效地提高处理性能。</p>\n<pre><code class=\\"lang-\\">import json\\nimport numpy as np\\nimport pandas as pd\\n\\ndef get_avg(list_args):\\n avg_result = list()\\n error_msg = ''\\n try:\\n df = pd.DataFrame(list_args, columns = ['in_param_1', 'in_param_2'], dtype=np.float64)\\n avg_result = (df['in_param_1'] + df['in_param_2'] * 0.5) / 2\\n except Exception as e:\\n error_msg = str(e)\\n return avg_result.tolist(), error_msg\\n\\n\\ndef lambda_handler(event, context):\\n error_msg = ''\\navg_result, error_msg = get_avg(event['arguments'])\\navg_result = avg_result.astype(str)\\n\\n if (error_msg is None) | (error_msg == ''):\\n ret_json = json.dumps({"results": avg_result, "success": True})\\n else:\\n ret_json = json.dumps({"success": False, "error_msg": error_msg})\\n return ret_json\\n</code></pre>\\n<p><strong>(2)关联函数示例</strong></p>\\n<pre><code class=\\"lang-\\">CREATE OR REPLACE EXTERNAL FUNCTION ef_get_avg(NUMERIC, NUMERIC) RETURNS VARCHAR IMMUTABLE\\nLAMBDA 'ef_get_avg' IAM_ROLE 'arn:xxxxxxxx:role/your-lambda-service-role';\\n</code></pre>\\n<p>这里假设你的 IAM Role 已配置好相应的权限</p>\n<p><strong>(3)SQL 调用验证</strong></p>\\n<pre><code class=\\"lang-\\">select ef_get_avg(10,18)\\n</code></pre>\\n<p><strong>(4)返回结果</strong></p>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/7fad20aed5f74653b8dd2316d5568b02_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"2__233\\"></a><strong>2. 环境配置</strong></h4>\\n<h4><a id=\\"21__236\\"></a><strong>2.1 安装依赖包</strong></h4>\\n<p>在亚马逊云科技海外某些区域如 us-east-1, ap-northeast-1 等,可以直接选用 Layers DataWrangler,里面已经包含了很多常用的数据处理依赖包(如 pandas, pyarrow, boto3 等),具体可参考 “Data Wrangler Github”[3]。</p>\n<p>其它没有内置 DataWrangler 的区域(如中国区),如果也想使用此依赖包,可以自行创建对应依赖包并在压缩后加载到 custom layer,详细步骤可见 “Creating and sharing Lambda Layers” [4]。</p>\n<h4><a id=\\"22__244\\"></a><strong>2.2 调试</strong></h4>\\n<p>自定义调试或报错信息,可以放入返回结果的 error_msg 中查看返回错误信息。</p>\n<p>在 Lambda 调试时,可通过 Configure test event 进行单元测试,示例如下:</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/bcf55cf42c8a4c00a238fcccea181b9a_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"23__254\\"></a><strong>2.3 注意事项</strong></h4>\\n<p>(1)Lambda python runtime 基于 python 3,默认整个处理都是基于 UTF-8,无需如 Python UDF 使用 # -<em>- coding: UTF-8 -</em>-。</p>\\n<p>(2)输入参数从 Redshift 传递到 Lambda 时,使用 Json 格式的 event,从 Lambda 返回 Redshift 亦如此,详细的 Json 格式可参考 “Creating a Lambda UDF” [5]。</p>\n<p>(3)以下语句可查看已创建的 UDF 清单:</p>\n<pre><code class=\\"lang-\\">select * from pg_proc_info where prokind='f' and proname like 'ef%'; -- ef\\n</code></pre>\\n<p>在这里代表以 ef 开头的 lambda UDF(即 External Function)</p>\n<h4><a id=\\"_UDF__270\\"></a><strong>四、三种 UDF 的比较</strong></h4>\\n<p>以上三种 Redshift UDF 实现,各有其优劣势及其适合的场景,在这里对它们进行简单的对比:</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/39ddacf1569f4258936f4f5eb04bf6cf_75f4534a673e843da4c4822131e3fa8.png\\" alt=\\"75f4534a673e843da4c4822131e3fa8.png\\" /></p>\n<h4><a id=\\"_278\\"></a><strong>结论</strong></h4>\\n<p>通过本文,你可以了解三种 Redshift UDF 的不同实现方法及其适合的场景。上述的示例代码可以帮助客户快速实现 Redshift UDF 交付,支持各种复杂数据分析场景。</p>\n<p>如你有其它的问题、建议或经验,欢迎留言给我们。</p>\n<h4><a id=\\"_286\\"></a><strong>参考</strong></h4>\\n<p>[1]已安装依赖包清单及安装包过程 – <a href=\\"https://docs.aws.amazon.com/redshift/latest/dg/udf-python-language-support.html\\" target=\\"_blank\\">https://docs.aws.amazon.com/redshift/latest/dg/udf-python-language-support.html</a></p>\\n<p>[2] UDF Constraints of scalar Python UDF – <a href=\\"https://docs.aws.amazon.com/redshift/latest/dg/udf-constraints.html\\" target=\\"_blank\\">https://docs.aws.amazon.com/redshift/latest/dg/udf-constraints.html</a></p>\\n<p>[3] Data Wrangler Github – <a href=\\"https://github.com/awslabs/aws-data-wrangler\\" target=\\"_blank\\">https://github.com/awslabs/aws-data-wrangler</a></p>\\n<p>[4] Creating and sharing Lambda Layers – <a href=\\"https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html\\" target=\\"_blank\\">https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html</a></p>\\n<p>[5] Creating a Lambda UDF – <a href=\\"https://docs.aws.amazon.com/redshift/latest/dg/udf-creating-a-lambda-sql-udf.html\\" target=\\"_blank\\">https://docs.aws.amazon.com/redshift/latest/dg/udf-creating-a-lambda-sql-udf.html</a></p>\\n<h4><a id=\\"_300\\"></a><strong>本篇作者</strong></h4>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/26b04771ba854ab6a547df45a0c53893_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_306\\"></a><strong>孔庆强</strong></h4>\\n<p>亚马逊云科技专业服务团队的大数据顾问,十多年从事数据湖仓及数据分析,为客户提供数据建模、数据治理及整体专业数据解决方案。在个人爱好方面,喜爱健身、音乐、旅行。</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/ad906daecdf240e69cec4191c71bd51d_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_314\\"></a><strong>赵鑫</strong></h4>\\n<p>亚马逊云科技专业服务团队数据架构师,专注于生命科学、自动驾驶领域的数据架构与数据分析</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/c91e60aceeb54f21b7a9f982c1ddcbb0_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_322\\"></a><strong>李烨炜</strong></h4>\\n<p>亚马逊云科技专业服务团队大数据咨询顾问。专注于企业级客户云上数据架构与数据平台设计等相关咨询服务。</p>\n"}