Amazon Location Service 的 Amazon Aurora PostgreSQL 用户定义函数 - Amazon Location Service

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Amazon Location Service 的 Amazon Aurora PostgreSQL 用户定义函数

您可以使用 Amazon Location Service 处理存储在数据库表中的坐标和地址,以清理和丰富您的地理空间数据。

例如:

  • 您可以使用地理编码将地址转换为坐标,以便对存储在数据库表中的地址进行规范化并填补数据中的空白。

  • 您可以对地址进行地理编码以获取其位置,并将坐标与数据库空间函数(例如显示指定区域中的行的函数)一起使用。

  • 您可以使用丰富的数据来生成自动报告,例如生成说明给定区域内所有设备的自动报告,或者生成自动机器学习报告,说明发送位置更新时故障率较高的区域。

本教程介绍如何使用 Amazon Location Service 格式化和丰富存储在 Amazon Aurora PostgreSQL 数据库表中的地址。

  • Amazon Aurora PostgreSQL——一种完全托管的关系数据库引擎,与 MySQL 和 PostgreSQL 兼容,其输出的吞吐量是 MySQL 的五倍,是 PostgreSQL 的三倍,而无需更改您大部分现有应用程序。有关更多信息,请参阅 Amazon Aurora 用户指南中的什么是 Amazon Aurora?

重要

本教程中生成的应用程序使用存储地理编码结果的地点索引。有关存储地理编码结果的适用费用的信息,请参阅 Amazon Location Service 定价

示例代码可在上的 Amazon Location Service 示例存储库中找到 GitHub,其中包含一个AWS CloudFormation模板

概述

该架构涉及以下集成:

  • 此解决方案使用 Amazon Location 地点索引资源来支持使用操作 SearchPlaceIndexForText 进行地理编码查询。

  • 当 IAM policy 允许 AWS Lambda 调用 Amazon Location 地理编码操作 SearchPlaceIndexForText 时,AWS Lambda 使用 Python Lambda 对地址进行地理编码。

  • 授予 Amazon Aurora PostgreSQL 使用 SQL 用户定义函数调用地理编码 Lambda 函数的权限。

先决条件

在开始之前,您需要满足以下先决条件:

快速入门

除了完成本教程中的步骤外,您还可以启动快速堆栈来部署支持 Amazon Location 操作 SearchPlaceIndexForText 的 AWS Lambda 函数。这会自动将您的 AWS 账户配置为允许 Amazon Aurora 调用 AWS Lambda。

配置 AWS 账户后,您需要:

创建地点索引资源

首先创建一个支持地理编码查询的地点索引资源。

  1. 打开 Amazon Location Service 控制台:https://console.aws.amazon.com/location/

  2. 在左侧导航窗格中,选择地点索引

  3. 填写以下选框:

    • 名称——输入地点索引资源的名称。例如,AuroraPlaceIndex。最多 100 个字符。有效条目包括:字母数字字符、连字符、句号和下划线。

    • 描述——输入可选描述。例如,Amazon Aurora 的地点索引

  4. 数据提供程序下,选择要与您的位置索引资源配合使用的可用数据提供程序。如果您没有偏好,我们建议您从 Esri 开始。

  5. 数据存储选项下,指定是,将存储结果。这表示您打算将地理编码结果保存在数据库中。

  6. (可选)在 Tags (标签) 下,输入标签 Key (键)Value (值)。这会为您的新地点索引资源添加标签。有关更多信息,请参阅标记资源

  7. 选择创建地点索引

创建用于地理编码的 AWS Lambda 函数

要在 Amazon Aurora PostgreSQL 和 Amazon Location Service 之间建立连接,您需要一个 AWS Lambda 函数来处理来自数据库引擎的请求。此函数转换 Lambda 用户定义的函数事件并调用 Amazon Location 操作 SearchPlaceIndexForText

您可以使用 AWS Lambda 控制台、AWS Command Line Interface 或 AWS Lambda API 创建函数。

使用控制台创建 Lambda 用户定义的函数

  1. 通过 https://console.aws.amazon.com/lambda/ 打开 AWS Lambda 控制台。

  2. 从左侧导航窗格中,选择函数

  3. 选择创建函数,并确保选择从头开始创作

  4. 填写以下选框:

    • 函数名称——输入您的函数的唯一名称。有效条目包括字母数字字符、连字符和下划线,不带空格。例如,AuroraGeocoder

    • 运行时系统——选择 Python 3.8

  5. 选择创建函数

  6. 选择 代码 选项卡以打开编辑器。

  7. lambda_function.py 中使用以下内容覆盖占位符代码:

    from os import environ import boto3 from botocore.config import Config # load the place index name from the environment, falling back to a default PLACE_INDEX_NAME = environ.get("PLACE_INDEX_NAME", "AuroraPlaceIndex") location = boto3.client("location", config=Config(user_agent="Amazon Aurora PostgreSQL")) """ This Lambda function receives a payload from Amazon Aurora and translates it to an Amazon Location `SearchPlaceIndex` call and returns the results as-is, to be post-processed by a PL/pgSQL function. """ def lambda_handler(event, context): kwargs = {} if event.get("biasPosition") is not None: kwargs["BiasPosition"] = event["biasPosition"] if event.get("filterBBox") is not None: kwargs["FilterBBox"] = event["filterBBox"] if event.get("filterCountries") is not None: kwargs["FilterCountries"] = event["filterCountries"] if event.get("maxResults") is not None: kwargs["MaxResults"] = event["maxResults"] return location.search_place_index_for_text( IndexName=PLACE_INDEX_NAME, Text=event["text"], **kwargs)["Results"]
  8. 如果您将地点索引命名为以外的其他名称 AuroraPlaceIndex,请创建一个名为的环境变量PLACE_INDEX_NAME以将资源名称分配给:

    • 选择配置选项卡中,选择环境变量

    • 选择编辑,然后选择添加环境变量

    • 对于,输入 PLACE_INDEX_NAME

    • 对于:输入您的地点索引资源的名称。

  9. 选择部署以保存您更新的函数。

  10. 测试下拉菜单中,选择配置测试事件

  11. 选择 Create new test event(新建测试事件)。

  12. 输入以下测试事件:

    { "text": "Baker Beach", "biasPosition": [-122.483, 37.790], "filterCountries": ["USA"] }
  13. 选择测试来测试 Lambda 函数。

  14. 选择配置选项卡。

  15. 常规配置下:选择权限

  16. 执行角色下:选择超链接角色名称以授予 Amazon Location Service 对您的 Lambda 函数的权限。

  17. 权限选项卡中,选择添加权限下拉菜单,然后选择创建内联策略

  18. 选择 JSON 选项卡。

  19. 添加以下 IAM policy:

    • 以下策略授予向地点索引资源发送SearchPlaceIndexForText数据的权限AuroraPlaceIndex

      { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "geo:SearchPlaceIndexForText", "Resource": "arn:aws:geo:<Region>:<AccountId>:place-index/AuroraPlaceIndex" } ] }
  20. 选择查看策略

  21. 输入策略名称。例如,AuroraPlaceIndexReadOnly

  22. 选择创建策略

授予 Amazon Aurora PostgreSQL 对访问 AWS Lambda 的权限

必须先授予访问权限,然后 Amazon Aurora PostgreSQL 才能调用 AWS Lambda 函数。

如果您的 Amazon Aurora PostgreSQL 集群不可公开访问,则需要先为 AWS Lambda 创建一个 VPC 端点,这样 Amazon Aurora 才能调用您的 Lambda 函数。

为 AWS Lambda 创建 VPC 端点

注意

只有在 Amazon Aurora PostgreSQL 集群不可公开访问时,才需要执行此步骤。

  1. 打开 Amazon Virtual Private Cloud Console

  2. 在左侧导航窗格中,选择终端节点

  3. 选择创建端点

  4. 服务名称筛选器中,输入“lambda”,然后选择 com.amazonaws.<region>.lambda

  5. 选择包含您的 Aurora 集群的 VPC。

  6. 对于每个可用区,选择一个子网。

  7. 安全组筛选器中,输入“默认”或您的 Aurora 集群所属的安全组的名称,然后选择安全组。

  8. 选择创建端点

创建 IAM policy 以授予调用您的 AWS Lambda 函数的权限

  1. 打开 IAM 控制台

  2. 在左侧导航窗格中,展开访问管理,然后选择策略

  3. 选择创建策略

  4. JSON 选项卡上,输入以下策略:

    • 以下是提供 Amazon Aurora PostgreSQL 权限以调用 AuroraGeocoder AWS Lambda 函数的 IAM policy 示例。

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": [ "arn:aws:lambda:<Region>:<AccountId>:function:AuroraGeocoder" ] } ] }
  5. 选择下一步:标签,以添加可选标签。

  6. 选择下一步:审核

  7. 查看您的策略并输入该策略的以下详细信息:

    • 名称——使用字母数字和 '+=、.@-_'字符。最多 128 个字符。例如,AuroraGeocoderInvoke

    • 描述——输入可选描述。使用字母数字和 '+=、.@-_' 字符。最多 1000 个字符。

  8. 选择创建策略。记下此策略的 ARN,您使用该 ARN 将策略附加到 IAM 角色。

创建一个 IAM 角色来授予对 Amazon Relational Database Service (Amazon RDS) 的权限

通过创建 IAM 角色,Amazon Aurora PostgreSQL 可以代表您代入该角色来访问 Lambda 函数。有关更多信息,请参阅《IAM 用户指南》中的创建向 IAM 用户委派权限的角色

以下示例是一个创建名为的角色的AWS CLI命令 AuroraGeocoderInvokeRole

aws iam create-role --role-name rds-lambda-role --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }'

将您的 IAM policy 附加到 IAM 角色

在拥有 IAM 角色时,附加您创建的 IAM policy。

以下示例是将策略附加AuroraGeocoderInvoke到角色的AWS CLI命令AuroraGeocoderInvokeRole

aws iam attach-role-policy --policy-arn AuroraGeocoderInvoke --role-name AuroraGeocoderInvokeRole

将该 IAM 角色添加到 Amazon Aurora 数据库集群中

以下示例是向名为的Amazon Aurora PostgreSQL数据库集群添加 IAM 角色的AWS CLI命令MyAuroraCluster

aws rds add-role-to-db-cluster \ --db-cluster-identifier MyAuroraCluster \ --feature-name Lambda \ --role-arn AuroraGeocoderInvokeRole \ --region your-region

调用 AWS Lambda 函数

授予 Amazon Aurora PostgreSQL 调用地理编码 Lambda 函数的权限后,您可以创建 Amazon Aurora PostgreSQL 用户定义的函数来调用地理编码 AWS Lambda 函数。有关更多信息,请参阅 Amazon Aurora 用户指南中的从 Amazon Aurora PostgreSQL 数据库集群调用 AWS Lambda 函数

安装所需的 PostgreSQL 扩展

要安装所需的 PostgreSQL 扩展 aws_lambda 和扩展 aws _commons,请参阅 Amazon Aurora 用户指南中的 Lambda 函数使用概述

CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE;

安装所需的 PostGIS 扩展

PostGIS 是一个 PostgreSQL 扩展,用于存储和管理空间信息。有关更多信息,请参阅 Amazon Relational Database Service 用户指南中的使用 PostGIS 扩展

CREATE EXTENSION IF NOT EXISTS postgis;

创建用于调用 Lambda 函数的 SQL 用户定义函数

在 SQL 编辑器中,创建一个新的用户定义函数f_SearchPlaceIndexForText来调用该函数 AuroraGeocoder

CREATE OR REPLACE FUNCTION f_SearchPlaceIndexForText( text text, bias_position geometry(Point, 4326) DEFAULT NULL, filter_bbox box2d DEFAULT NULL, filter_countries text[] DEFAULT NULL, max_results int DEFAULT 1 ) RETURNS TABLE ( label text, address_number text, street text, municipality text, postal_code text, sub_region text, region text, country text, geom geometry(Point, 4326) ) LANGUAGE plpgsql IMMUTABLE AS $function$ begin RETURN QUERY WITH results AS ( SELECT json_array_elements(payload) rsp FROM aws_lambda.invoke( aws_commons.create_lambda_function_arn('AuroraGeocoder'), json_build_object( 'text', text, 'biasPosition', CASE WHEN bias_position IS NOT NULL THEN array_to_json(ARRAY[ST_X(bias_position), ST_Y(bias_position)]) END, 'filterBBox', CASE WHEN filter_bbox IS NOT NULL THEN array_to_json(ARRAY[ST_XMin(filter_bbox), ST_YMin(filter_bbox), ST_XMax(filter_bbox), ST_YMax(filter_bbox)]) END, 'filterCountries', filter_countries, 'maxResults', max_results ) ) ) SELECT rsp->'Place'->>'Label' AS label, rsp->'Place'->>'AddressNumber' AS address_number, rsp->'Place'->>'Street' AS street, rsp->'Place'->>'Municipality' AS municipality, rsp->'Place'->>'PostalCode' AS postal_code, rsp->'Place'->>'SubRegion' AS sub_region, rsp->'Place'->>'Region' AS region, rsp->'Place'->>'Country' AS country, ST_GeomFromGeoJSON( json_build_object( 'type', 'Point', 'coordinates', rsp->'Place'->'Geometry'->'Point' ) ) geom FROM results; end; $function$;

调用 SQL 函数从 Aurora 进行地理编码

运行 SQL 语句会调用 Lambda 函数 AuroraGeocoder,该函数从数据库的数据库表中获取地址记录,并使用位置索Amazon Aurora PostgreSQL引资源对其进行地理编码。

注意

Amazon Aurora PostgreSQL 每次调用 SQL 用户定义函数时都会调用 Lambda 函数。

如果您要对 50 行进行地理编码,请 Amazon Aurora PostgreSQL 调用 Lambda 函数 50 次。每行调用一次。

以下 f_SearchPlaceIndexForText SQL 函数通过 L AuroraGeocoderambda 函数向亚马逊位置的 SearchPlaceIndexForText API 发出请求。该函数返回一 geom 列 PostGIS 几何图形,该列 ST_AsText(geom) 会转换为文本。

SELECT *, ST_AsText(geom) FROM f_SearchPlaceIndexForText('Vancouver, BC');

默认情况下,返回值将包含一行。要请求更多行,直到 MaxResults 限制,请运行以下 SQL 语句,同时提供 BiasPosition 并限制结果在加拿大。

SELECT * FROM f_SearchPlaceIndexForText('Mount Pleasant', ST_MakePoint(-123.113, 49.260), null, '{"CAN"}', 5);

要使用边界框筛选结果,请将 Box2D 作为 filter_bbox 传递:

  • FilterBBox——通过返回边界框内的位置来筛选结果。此参数为可选参数。

SELECT * FROM f_SearchPlaceIndexForText('Mount Pleasant', null, 'BOX(-139.06 48.30, -114.03 60.00)'::box2d, '{"CAN"}', 5);

有关 PostGIS 类型和函数的更多信息,请参阅 PostGIS 参考

丰富包含地址数据的数据库

您可以构造一个格式化的地址,同时使用 Amazon Location 操作 SearchPlaceIndexForText 进行规范化和地理编码,给定一个数据库表,其中包含以下数据,分为以下几列:

  • id

  • address

  • city

  • state

  • zip

WITH source_data AS ( SELECT id, address || ', ' || city || ', ' || state || ', ' || zip AS formatted_address FROM addresses ), geocoded_data AS ( SELECT *, (f_SearchPlaceIndexForText(formatted_address)).* FROM source_data ) SELECT id, formatted_address, label normalized_address, ST_Y(geom) latitude, ST_X(geom) longitude FROM geocoded_data -- limit the number of rows that will be geocoded; remove this to geocode the entire table LIMIT 1;

以下示例对此数据表行进行了说明:

id | formatted_address | normalized_address | latitude | longitude ----+--------------------------------+--------------------------------------------+------------------+------------------- 42 | 123 Anytown Ave N, Seattle, WA | 123 Anytown Ave N, Seattle, WA, 12345, USA | 47.6223000127926 | -122.336745971039 (1 row)

更新数据库表并填充列

以下示例更新表并用 SearchPlaceIndexForText 查询结果填充列:

WITH source_data AS ( -- select rows that have not been geocoded and created a formatted address for each SELECT id, address || ', ' || city || ', ' || state || ', ' || zip AS formatted_address FROM addresses WHERE label IS NULL -- limit the number of rows that will be geocoded; remove this to geocode the entire table LIMIT 1 ), geocoded_data AS ( -- geocode each row and keep it linked to the source's ID SELECT id, (f_SearchPlaceIndexForText(formatted_address)).* FROM source_data ) UPDATE addresses -- populate columns SET normalized_address = geocoded_data.label, latitude = ST_Y(geocoded_data.geom), longitude = ST_X(geocoded_data.geom) FROM geocoded_data -- ensure that rows match WHERE addresses.id = geocoded_data.id;

后续步骤

示例代码可在上的 Amazon Location Service 示例存储库中找到 GitHub,其中包含一个AWS CloudFormation模板