按距离对查询进行排序需要读取整个数据集吗?

时间:2019-02-08 21:16:13

标签: amazon-web-services amazon-dynamodb

要在DynamoDB中执行地理位置查询,AWS(https://aws.amazon.com/blogs/mobile/geo-library-for-amazon-dynamodb-part-1-table-structure/)中有库。但是要按距离对地理查询的结果进行排序,必须读取整个数据集,对吗?如果地理查询产生大量结果,那么如果按距离排序,就无法分页(在后端,而不是对用户)吗?

2 个答案:

答案 0 :(得分:0)

您是正确的。要按到某个任意位置的距离对所有数据点进行排序,必须从DynamoDB表中读取 all 数据。

在DynamoDB中,您只能使用已存储在DynamoDB表中并且用作表或其索引之一的排序键的预先计算的值对结果进行排序。如果需要按与固定位置的距离排序,则可以使用DynamoDB进行此操作。


可能的解决方法(有限制)

  • TLDR; ,如果您只能对距任意点X公里以内的项目进行分类,就不是一个坏问题。

这仍然涉及对内存中的数据点进行排序,但是通过产生不完整的结果(通过限制结果的最大范围),使问题变得更容易。

要执行此操作,您需要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 1Part 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 之间,并且返回了三个提供商的列表,但大量数据被提取并丢弃。

为了实现上面的查询,X和Y之间的排序条件是由组成的。 9q5c.neighbors().sorted() = 9q59, 9q5c, 9q5d, 9q5e, 9q5f, 9q5g, 9qh1, 9qh4, 9qh5。所以我们可以只使用 X=9q59 和 Y=9qh5 但是有超过 50 个(我真的没有在 50 之后计算)在函数之间的这种 UTF 中匹配象限。

关于上面的哈希/大小表,我建议使用这个 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 ...