AWS DynamoDB - 随机选择记录/项目?

问题描述 投票:0回答:7

有什么想法如何从 DynamoDB 表中随机选择项目/记录吗?我不认为 API 中对此有任何规定。

我考虑过维护一个 NumericId|MyOtherKey (“NumericIdTable”)表,然后生成一个 0 到我拥有的记录总数之间的随机数,然后从 NumericIdTable 获取该项目,但从长远来看它不会起作用.

欢迎想法/想法。

random amazon-web-services record amazon-dynamodb
7个回答
37
投票

我想出的一种从 DynamoDB 表中随机选择项目的方法:

  1. 在表中所有可能的 RangeKey 上生成随机 RangeKey
  2. 使用此 RangeKey 和 RangeKeyCondition GreaterThan 且限制为 1 查询表

例如,如果您使用 UUID 作为 RangeKey 的标识符,您可以获得如下随机项目

RandomRangeKey = new UUID
RandomItem = Query( "HashKeyValue": "KeyOfRandomItems",
                    "RangeKeyCondition": { "AttributeValueList":
                                "RandomRangeKey",
                                "ComparisonOperator":"GT"}, 
                    "Limit": 1 )

这样你就得到一个随机物品并且只消耗1个读取容量。

通过生成比表中使用的最小 UUID 更小的 UUID,有可能会错过随机变量的第一个查询。这个机会会随着表的扩大而缩小,您可以使用同一个随机键上的 SmallerThan 比较轻松地发送另一个请求,从而确保随机项目的命中。


如果您的 Tabledesign 不允许可随机化的 RangeKeys,您可以按照您的方法创建一个单独的 RandomItem 表并将 ID 存储在可随机化的 RangeKey 下。可能的表结构是

*RandomItemTable
   TableName - HashKey
   UUID - Rangekey
   ItemId

请记住,对于这种方法,您需要管理原始表和随机化表之间的冗余。


35
投票

如果您使用 GUID 作为表的哈希键,您可以执行以下操作:

var client = new AmazonDynamoDBClient();

var lastKeyEvaluated = new Dictionary<string, AttributeValue>() 
{ 
    { "YOUR_HASH_KEY", new AttributeValue(Guid.NewGuid().ToString()) } 
};

var request = new ScanRequest()
{
    TableName = YOUR_TABLE_NAME,
    ExclusiveStartKey = lastKeyEvaluated,
    Limit = 1
};
var response = client.Scan(request);

这每次都会给你一个随机记录,因为它会生成一个随机 GUID 作为最后的 KeyEvaluated。


4
投票

天真的方法是 1)使用describe table调用来获取该表中的N(总行数) 2)选择1到N之间的随机数i 3)扫描。停下来,直到你看到我行

我正在考虑更好的方法来做到这一点。当我有好的答案时我会更新。


0
投票

一种简单有效的方法:

  1. 检索表中的所有项目。由于 DynamoDB 限制只能获取 1MB 数据,因此在此操作中使用
    ProjectionExpression
    只检索您的主分区键。
  2. 从上面的结果中,您将得到项目的总数。现在,只需生成一个介于 0 和项目计数之间的随机数。我们称这个随机数为
  3. n
  4. 从 1 中的结果中,取出第
  5. n 项,这将是该随机项的主分区键值。
  6. 使用您刚刚计算的随机项的主分区键值执行另一个 DynamoDB 查询,以获取所有必要的列值。

0
投票
我也遇到了同样的问题,并按照nenTi的建议类似的方式解决了它,但有一些保留。正如评论中所述,该方法仅在具有相同分区键的一组项目上随机选择范围键时才有效 - 因此将其与表的键一起使用会干扰分区键尽可能分布的最佳实践。

我通过添加一个 GSI(全局二级索引)来解决这个问题,它的哈希键代表一大类可供选择的项目(该类别不需要分布!)和一个具有随机值的排序键。

查询此 GSI 会产生高效的随机结果(约 90KB 数据库中的每个请求 0.5 RCU,仅扫描单个项目)。

我在下面使用的查询:

response = table.query( Limit=1, IndexName="my_index", KeyConditionExpression=Key("type").eq("Q") & Key(random_property).gt(Decimal(str(Random().random()))), ReturnConsumedCapacity='TOTAL' )
    

0
投票
根据 nenTi 的回答,我想扩展这个想法,因为它有一个小缺陷。

如果从随机 id 中选择下一个最大的记录,如果两个 id 非常接近,会发生什么情况?还是说距离很远呢?这将影响选择 id 的概率。事实上,如果 id 之间的距离不是同质的,那么我们在 id 上就会有非同质的概率。

要解决此问题,您可以选择 50 条记录而不是 1 条。请求后,从这 50 条记录中随机选择一条。这将平均 50 条记录之间的距离,这应该会导致 id 之间的概率更加均匀。

然后,如果我们接近最大的 id,请说 n

< 50 from the top, the probability will also tend to be higher as you will be selecting between less than 50 records (only n).

只需查询最小的 50-n 条记录并将它们添加到 ids 中以供选择。


-1
投票
对于某些用例,我会推荐下一种方法:

  1. 创建一个扫描所有dynamodb表的脚本并将“pk”和“sk”保存到单独的文件中。

  2. 将 lambda 层中的所有“pk”和“sk”对保存为本地依赖项(如果使用nodejs,请搜索“package.json 中的本地依赖项”)。

  3. 在 lambda 中导入本地依赖并选择一个随机项。

  4. 定期运行脚本以刷新本地依赖项中的“pk”和“sk”集。

如果您没有非常大的 dynamodb 表并且不需要经常包含新的“pk”和“sk”,我认为这种方法就足够好了。

© www.soinside.com 2019 - 2024. All rights reserved.