本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
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 GitHub
主题
概览
该架构涉及以下集成:
-
此解决方案使用 Amazon Location 地点索引资源来支持使用该操作进行地理编码查询
SearchPlaceIndexForText
。 -
AWS Lambda当 IAM 策略授予允许调用 Amazon 位置地理编码操作的权限时,使用 Python LambdaAWS Lambda 对地址进行地理编码
SearchPlaceIndexForText
。 -
授Amazon Aurora PostgreSQL予使用 SQL 用户定义函数调用地理编码 Lambda 函数的权限。
先决条件
在开始之前,您需要以下前提条件:
-
一个Amazon Aurora PostgreSQL集群。有关创建 Amazon Aurora 数据库集群的更多信息,请参阅 Amazon Aurora 用户指南。
注意 如果您的 Amazon Aurora 集群未公开使用,您还必须配置 Amazon Aurora 来AWS Lambda连接到您AWS账户的 VPC。有关更多信息,请参阅授予Amazon Aurora PostgreSQL访问权限AWS Lambda:
-
用于连接到Amazon Aurora PostgreSQL集群的 SQL 开发者工具。
快速启动
除了完成本教程中的步骤外,您还可以启动快速堆栈来部署支持 Amazon Location 操作的AWS Lambda函数SearchPlaceIndexForText
。这会自动将您的AWS账户配置为允许 Amazon Aurora 拨打电话AWS Lambda。
配置AWS账户后,您需要:
-
向Amazon Aurora a 添加 Lambda 功能。请参阅中的将 IAM 角色添加到 Amazon Aurora 数据库集群中授予Amazon Aurora PostgreSQL访问权限AWS Lambda。
-
将用户定义函数加载到您的数据库中。请参阅调用 AWS Lambda 函数。
创建地点索引资源
首先创建一个支持地理编码查询的地点索引资源。
-
打开亚马逊Location Service 控制台,网址为 https://console.aws.amazon.com/location/
。 -
在左侧导航窗格中,选择 P lace 索引。
-
填写以下方段:
-
名称 — 输入地点索引资源的名称。例如,
AuroraPlaceIndex
。最多 100 个字符。有效条目包括字母数字字符、连字符、句点和下划线。 -
描述-输入可选描述。例如,
Amazon Aurora 的地址索引
。
-
-
在 “数据提供者” 下,选择可用数据提供者
以用于您的地点索引资源。如果您没有偏好,我们建议从 Esri
开始。 -
在 “数据存储选项” 下,指定 “是,将存储结果”。这表明您打算将地理编码结果保存在数据库中。
-
(可选)在 Tags (标签) 下,输入标签 Key (键) 和 Value (值)。这会为您的新地点索引资源添加一个标签。有关更多信息,请参阅标记资源。
-
选择创建地点索引。
创建用于地理编码的AWS Lambda函数
要在Amazon Aurora PostgreSQL和亚马逊Location Service 之间创建连接,您需要一个AWS Lambda函数来处理来自数据库引擎的请求。此函数转换 Lambda 用户定义的函数事件并调用 Amazon Location 操作SearchPlaceIndexForText
。
您可以使用AWS Lambda控制台AWS Command Line Interface、或AWS Lambda API 创建函数。
使用控制台创建 Lambda 用户定义的函数
-
打开 AWS Lambda 控制台,地址:https://console.aws.amazon.com/lambda/
。 -
从左侧导航中,选择 Function (函数)。
-
选择 “创建函数”,并确保选择 “从头开始创作”。
-
填写以下方段:
-
函数名称 — 为函数输入唯一名称。有效条目包括字母数字字符、连字符和下划线,不含空格。例如,
AuroraGeocoder
。 -
运行时 — 选择
Python 3.8
。
-
-
选择 Create function (创建函数)。
-
选择 “代码” 选项卡以打开编辑器。
-
用以下内容覆盖中的
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"]
-
如果您将地点索引命名为其他名称
AuroraPlaceIndex
,请创建一个名为的环境变量PLACE_INDEX_NAME
以将资源名称分配给:-
从 “配置” 选项卡中,选择 “环境变量”。
-
选择 “编辑”,然后选择 “添加环境变量”。
-
对于密钥:输入
PLACE_INDEX_NAME
。 -
对于值:输入您的地点索引资源的名称。
-
-
选择 Deploy 保存更新的函数。
-
从 Test 下拉菜单中,选择配置测试事件。
-
选择 Create new test event(新建测试事件)。
-
输入以下测试事件:
{ "text": "Baker Beach", "biasPosition": [-122.483, 37.790], "filterCountries": ["USA"] }
-
选择 Test 以测试 Lambda 函数。
-
选择 Configuration 选项卡。
-
在 “常规配置” 下:选择 “权限”。
-
在执行角色下:选择超链接角色名称以向您的 Lambda 函数授予亚马逊Location Service 权限。
-
在 “权限” 选项卡下:选择 “添加权限” 下拉列表,然后选择 “创建内联策略”。
-
请选择 JSON 选项卡。
-
添加以下 IAM policy:
-
以下策略授予向地点索引资源发送
SearchPlaceIndexForText
的权限AuroraPlaceIndex
。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "geo:SearchPlaceIndexForText", "Resource": "arn:aws:geo:<Region>:<AccountId>:place-index/
AuroraPlaceIndex
" } ] }
-
-
选择Review policy(查看策略)。
-
输入策略名称。例如,
AuroraPlaceIndexReadOnly
。 -
选择 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集群不可供公开访问时,才需要此步骤。
-
在左侧导航中,选择 Endpoin cti on (
-
选择 Create endpoint(创建端点)。
-
在服务名称筛选器中,输入 “lambda”,然后选择
com.amazonaws.<region>.lambda
。 -
选择包含您的 Aurora 集群的 VPC。
-
为每个可用区选择一个子网。
-
在安全组筛选器中,输入 “默认” 或您的 Aurora 集群所属安全组的名称,然后选择安全组。
-
选择 Create endpoint(创建端点)。
创建 IAM 策略以授予调用AWS Lambda函数的权限
-
打开 IAM 控制台
。 -
在左侧导航栏中,展开 “访问管理”,选择 “策略”。
-
选择 Create policy(创建策略)。
-
在 JSON 选项卡上,输入以下策略:
-
以下是授予调用该
AuroraGeocoder
AWS Lambda函数Amazon Aurora PostgreSQL权限的 IAM 策略的示例。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": [ "arn:aws:lambda:<Region>:<AccountId>:function:
AuroraGeocoder
" ] } ] } -
-
选择 “下一步:标签” 以添加可选标记。
-
选择 Next: Review(下一步: 审核)。
-
查看您的政策并输入该政策的以下详细信息:
-
名称 — 使用字母数字和 '+=, .@-_' 字符。最多 128 个字符。例如,
AuroraGeocoderInvoke
。 -
描述-输入可选描述。使用字母数字和 '+=, .@-_' 字符。最多 1000 个字符。
-
-
选择 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-nameAuroraGeocoderInvokeRole
将该 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-arnAuroraGeocoderInvokeRole
\ --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 AuroraGeocoder
ambda 函数向亚马逊位置的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 传递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;
后续步骤
示例代码可在的亚马逊Location GitHub