Amazon Aurora PostgreSQLAmazon Location Service 用户定义函数 - Amazon Location Service

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

Amazon Aurora PostgreSQLAmazon Location Service 用户定义函数

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

例如:

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

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

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

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

  • Amazon Aurora PostgreSQL— 完全托管式关系数据库引擎,与 MySQL 兼容,将 MySQL 的吞吐量增加 5 倍,而无需对大多数现有应用程序进行更改。有关更多信息,请参阅什么是 Amazon Aurora? Amazon Aurora 用户指南中。

重要

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

示例代码可在的亚马逊Location GitHubService 示例存储库中找到,其中包含一个AWS CloudFormation模板

概览

该架构涉及以下集成:

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

  • AWS Lambda当 IAM 策略授予允许调用 Amazon 位置地理编码操作的权限时,使用 Python LambdaAWS Lambda 对地址进行地理编码SearchPlaceIndexForText

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

先决条件

在开始之前,您需要以下前提条件:

快速启动

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

配置AWS账户后,您需要:

创建地点索引资源

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

  1. 打开亚马逊Location Service 控制台,网址为 https://console.aws.amazon.com/location/

  2. 在左侧导航窗格中,选择 P lace 索引

  3. 填写以下方段:

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

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

  4. 在 “数据提供者” 下,选择可用数据提供者以用于您的地点索引资源。如果您没有偏好,我们建议从 Esri 开始。

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

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

  7. 选择创建地点索引

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

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

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

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

  1. 打开 AWS Lambda 控制台,地址:https://console.aws.amazon.com/lambda/

  2. 从左侧导航中,选择 Function (函数)。

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

  4. 填写以下方段:

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

    • 运行时 — 选择 Python 3.8

  5. 选择 Create function (创建函数)

  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. 选择 Deploy 保存更新的函数。

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

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

  12. 输入以下测试事件:

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

  14. 选择 Configuration 选项卡。

  15. 在 “常规配置” 下:选择 “权限”。

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

  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. 选择Review policy(查看策略)

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

  22. 选择 Create policy(创建策略)

授予Amazon Aurora PostgreSQL访问权限AWS Lambda

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

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

为创建 VPC 终端节点AWS Lambda

注意

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

  1. 打开 Amazon Virtual Private Cloud Console

  2. 在左侧导航中,选择 Endpoin cti on (

  3. 选择 Create endpoint(创建端点)。

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

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

  6. 为每个可用区选择一个子网。

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

  8. 选择 Create endpoint(创建端点)。

创建 IAM 策略以授予调用AWS Lambda函数的权限

  1. 打开 IAM 控制台

  2. 在左侧导航栏中,展开 “访问管理”,选择 “策略”。

  3. 选择 Create policy(创建策略)

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

    • 以下是授予调用该AuroraGeocoderAWS Lambda函数Amazon Aurora PostgreSQL权限的 IAM 策略的示例。

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

  6. 选择 Next: Review(下一步: 审核)

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

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

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

  8. 选择 Create policy(创建策略)。请注意此策略的 ARN,您使用该 ARN 将策略附加到 IAM 角色。

创建 IAM 角色以授予AAmazon Relational Database Service e(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 策略。

以下示例是将策略附加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 扩展

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

CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE;

安装所需的 PostGIS 扩展

PostGIS 是一个 PostgreSQL 扩展,用于存储和管理空间信息。有关更多信息,请参阅Amazon Relational Database 用户指南》中的使用 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$;

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

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

注意

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

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

以下f_SearchPlaceIndexForText SQL 函数通过 L AuroraGeocoderambda 函数向亚马逊位置的SearchPlaceIndexForText API 发出请求。该函数返回一个 PostGIS 几何图形的geom列,该列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);

要使用边界框筛选结果,请将 a 传递Box2Dfilter_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;

后续步骤

示例代码可在的亚马逊Location GitHubService 示例存储库中找到,其中包含一个AWS CloudFormation模板