查询具有给定范围内的主键和匹配给定值的辅助键的所有项目

时间:2019-05-12 19:47:01

标签: amazon-web-services boto3 dynamodb-queries

我有一个dynamoDB表,用于存储句子。每个句子都有一个称为“ id”(类型为int)的主键,以及该句子中每个单词的其他辅助键。

例如,条目“ hello world”将具有一些整数作为id,并且条目“ hello” = 1和“ world” = 1。我需要查询具有给定范围内的id且包含给定单词列表中的单词(words = [word1,word2,word3,word4,word5])的所有句子。到目前为止,我的查询是:

while items == []:
      response = lyric_table.scan(
                          FilterExpression=(Key(words[0]).eq(1) | 
                                            Key(words[1]).eq(1) | 
                                            Key(words[2]).eq(1) | 
                                            Key(words[3]).eq(1)| 
                                            Key(words[4]).eq(1)) & 
                                            filt,
                          ExclusiveStartKey={'id': r},)
      items = response['Items']

其中

filt = Key('id').between(r1, r2) | Key('id').between(r3, r4) ...

虽然我不确定是否有必要,但我还在while循环的每次迭代中都将ExclusiveStartKey选择为选自r1,r3,...的随机数。

当“单词”包含表中相对常见的单词时,此代码可以按预期工作,但是当“单词”包含数据库中不太常见的单词时,此代码将花费太多时间来运行。在某些情况下,扫描将无限期地运行。我也尝试使用查询而不是扫描,但是用它来改进代码没有运气。

您对如何优化上述代码有何建议?

1 个答案:

答案 0 :(得分:0)

在Dynamodb中有效执行范围运算的唯一方法是,如果属性是表或索引上的排序键(或辅助键)。如果是分区键(或主键),则Dynamodb对其进行哈希处理以随机分布。这是设计使然,以允许读/写可伸缩性。对分区键进行范围操作将涉及表扫描,因此效率不高。

如果我正确理解了您的问题,则您的数据如下所示:

Id Word SomeValue 101 Hello 1 101 World 2

如果您知道ID的完整范围(例如1-1000),则一种解决方案是对这些ID进行存储分区,请使用存储分区键作为分区键,并使用ID作为排序键:

BucketId Id 1 .. 1 .. 100 101 100 101 100 121 … 200 300 : 1000

然后对于(101,320)范围,您可以使用适当的过滤器表达式对ID 100、200和300进行3个查询。这肯定比表扫描更有效率。至于单词,不确定您的特定用例是什么,但是如果每个id的数量受限制,则可以将它们存储为单个map或set属性。