要在DynamoDB中执行地理位置查询,AWS(https://aws.amazon.com/blogs/mobile/geo-library-for-amazon-dynamodb-part-1-table-structure/)中有库。但是要按距离对地理查询的结果进行排序,必须读取整个数据集,对吗?如果地理查询产生大量结果,那么如果按距离排序,就无法分页(在后端,而不是对用户)吗?
答案 0 :(得分:0)
您是正确的。要按到某个任意位置的距离对所有数据点进行排序,必须从DynamoDB表中读取 all 数据。
在DynamoDB中,您只能使用已存储在DynamoDB表中并且用作表或其索引之一的排序键的预先计算的值对结果进行排序。如果需要按与固定位置的距离排序,则可以使用DynamoDB进行此操作。
可能的解决方法(有限制)
这仍然涉及对内存中的数据点进行排序,但是通过产生不完整的结果(通过限制结果的最大范围),使问题变得更容易。
要执行此操作,您需要P点的Geohash(从中测量所有其他点的距离)。假设它是A234311。然后,您需要选择合适的结果范围。让我们对此加一些数字以使其具体化。 (我完全把这些数字弄成数字,因为实际数字与理解这些概念无关。)
A - represents a 6400km by 6400km area
2 - represents a 3200km by 3200km area within A
3 - represents a 1600km by 1600km area within A2
4 - represents a 800km by 800km area within A23
3 - represents a 400km by 400km area within A234
1 - represents a 200km by 200km area within A2343
1 - represents a 100km by 100km area within A23431
从图形上看,它可能像这样:
View of A View of A23
|----------|-----------| |----------|-----------|
| | A21 | A22 | | | |
| A1 |-----|-----| | A231 | A232 |
| | A23 | A24 | | | |
|----------|-----------| |----------|-----------|
| | | | |A2341|A2342|
| A3 | A4 | | A233 |-----|-----|
| | | | |A2343|A2344|
|----------|-----------| |----------|-----------| ... and so on.
在这种情况下,我们的点P在A224132中。另外,假设我们要获得400km之内的排序点。 A2343是400 km x 400 km,因此我们需要从A2343及其所有8-connected邻居(A2341,A2342,A2344,A2334,A2332,A4112,A4121,A4122)加载结果。然后,当我们仅将这些内容加载到内存中后,您便可以计算距离,对其进行排序,并丢弃所有超过400公里的结果。
(只要用户/客户端知道400公里以外的数据可能是不完整的,您就可以保留距离超过400公里的结果。)
DynamoDB Geo库使用的哈希方法与Z-Order Curve非常相似-熟悉该方法以及AWS的Part 1和Part 2可能会有所帮助有关DynamoDB中多方面查询的Z顺序索引的数据库博客。
答案 1 :(得分:0)
不完全是。查询位置时,您可以通过固定查询值(分区键值)和排序键进行查询,因此您可以限制查询数据结果并应用一些过滤。
在设计 DynamoDB Geo Hash 邻近定位器服务时,我一直在绞尽脑汁。对于此示例,customer_A 想要查找其区域内的所有服务提供商_X。所有客户和提供商都有一个“g8”密钥,用于存储他们精确的 geoHash 位置(最多 8 个级别)。
完成此搜索的公认方法是从主表生成一个二级索引,使用不太准确的 geoHash 'g4',这为主查询键提供了更广泛的区域。我正在为单个表设计应用键重载和复合键结构。这个设计的目标是在一次查询中返回所有需要的数据,二级索引可以通过设计复制数据(存储便宜但cpu和带宽不便宜)
GSI1PK GSI1SK providerId Projected keys and attributes
---------------------------------------------
g4_9q5c provider pr_providerId1 name rating
g4_9q5c provider pr_providerId2 name rating
g4_9q5h provider pr_providerId3 name rating
场景 1:customer_A.g8_9q5cfmtk 所以你发出一个查询,其中 GSI1PK=g4_9q5c 并返回两个提供者的列表,而不是我想要的三个。
但是使用 geoHash.neighbor() 将返回 8 个周围的邻居,如 9q5h(参见下面的参考)。这很好,因为 9q5h 中有一个提供程序,但这意味着我必须运行九个查询,一个在中心,八个在邻居,或者运行 1-N,直到获得我需要的最少结果。
但是查询第二个方向,NW,SW,E??这将需要另一个级别的暗示哪个邻居有更多结果,而无需先知道,除非您对加权结果运行预查询。但是,您冒着只返回有利邻居的风险,因为以前不受欢迎的邻居可能会有新的供应商。您可以将一些 ML 和随机查询应用到邻居中以检查当前计数。
在采用上述方法之前,我尝试过这种设计。
GSI1PK GSI1SK providerId Projected keys and attributes
---------------------------------------------
loc g8_9q5cfmtk pr_provider1
loc g8_9q5cfjgq pr_provider2
loc g8_9q5fe954 pr_provider3
场景 2:customer_A.g8_9q5cfmtk 因此,您发出一个查询,其中 GSI1PK=loc 和 GSI1SK 位于 g8_9q5ca 和 g8_9q5fz 之间,并且返回了三个提供商的列表,但大量数据被提取并丢弃。
关于上面的哈希/大小表,我建议使用这个 https://www.movable-type.co.uk/scripts/geohash.html Geohash 长度 单元格宽度 单元格高度 1 ≤ 5,000km × 5,000km 2 ≤ 1,250km × 625km 3 ≤ 156km × 156km 4 ≤ 39.1km × 19.5km 5 ≤ 4.89km × 4.89km ...