我有一个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,...的随机数。
当“单词”包含表中相对常见的单词时,此代码可以按预期工作,但是当“单词”包含数据库中不太常见的单词时,此代码将花费太多时间来运行。在某些情况下,扫描将无限期地运行。我也尝试使用查询而不是扫描,但是用它来改进代码没有运气。
您对如何优化上述代码有何建议?
答案 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属性。