【问题标题】:AWS DynamoDB - Pick a record/item randomly?AWS DynamoDB - 随机选择记录/项目?
【发布时间】:2012-05-26 20:07:44
【问题描述】:

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

我考虑过维护一个 NumericId|MyOtherKey ("NumericIdTable") 表,然后生成一个介于 0 和我拥有的记录总数之间的随机数,然后从 NumericIdTable 获取该项目,但它不会长期工作-运行。

欢迎提出想法/想法。

【问题讨论】:

    标签: random amazon-web-services record amazon-dynamodb


    【解决方案1】:

    我想出的一种从 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 不允许可随机化的 RangeKey,您可以按照您的方法创建一个单独的 RandomItem 表并将 ID 存储在可随机化的 RangeKey 下。一个可能的表结构是

    *RandomItemTable
       TableName - HashKey
       UUID - Rangekey
       ItemId
    

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

    【讨论】:

    • 感谢 nenTi - 我会看看如何实现它。我必须承认我没有考虑在 UUID 上使用 GT 比较运算符 - 好主意 :)
    • DynamoDB 查询需要指定哈希键。如果您想获得特定哈希键的随机行,上述答案将起作用。如果您想获得一个“全局”随机项,那么它将无法工作:(
    • 我不确定这是否是因为它已经过时了,但我可以摸索到RangeKey == SortKeyHashKey == PartitionKey。不幸的是,您不能在 `PartitionKey 上使用>/GT,并且需要专门有一个排序键...
    • 现在是 2019 年。有没有更好的解决方案?
    【解决方案2】:

    如果您使用 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 作为 lastKeyEvaluated。

    【讨论】:

    • 因此,通过将限制设置为 1,您将只能获得一项。但是如何将 ExclusiveStartKey 设置为尚不存在的随机 UUID 为您提供另一个随机行?生成的 UUID 不是必须已经存在于表中吗?而且由于它的独特性,这永远不会发生
    • UUID 不需要存在于表中。对于给定的密钥,DynamoDB 知道它“应该”存在于何处(如果存在)。当您选择一个随机项目时,DynamoDB 从该位置开始,移动到下一个项目,然后将其返回。这类似于在街上随便找一所房子:选择一个门牌号,去那个门牌号应该在的地方,然后沿着街道往上走,直到找到真正的房子。
    • 另外,YOUR_HASH_KEY 的值可以概括为选择 2048 个随机位,将其视为字符串,并以此为起点。请参阅stackoverflow.com/questions/5351277 了解如何在 Java 中执行此操作。
    • 我对此表示怀疑,但您确实可以为分区键使用随机值。如果你有一个排序键,你还需要提供一个值,否则你会收到一个关于它与模式不匹配的错误:stackoverflow.com/questions/39989567/…
    • 想必如果没有返回任何物品,您应该执行后续查询以获取第一个物品。如果您不这样做,并且您有一个仅包含 1 个项目的集合,并且该项目恰好具有非常低的 UUID,那么您的方法可能会在返回单个项目之前进行大量请求。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      一种简单有效的方法:

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

      【讨论】:

      • 这个问题: 1. 如果您的数据(甚至只是密钥)大于 1MB 怎么办?那么,您不是在整个数据上随机选择,除非您可以保证 dynamo 每次返回的项目都是真正随机的。 2. 如果您仅扫描键的大小接近 1MB,那么每次您需要随机行时,这都是一项巨大的操作。
      【解决方案5】:

      我会为某些用例推荐下一种方法:

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

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

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

      4. 定期运行脚本以获取本地依赖项中一组令人耳目一新的“pk”和“sk”。

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

      【讨论】:

        猜你喜欢
        • 2020-12-01
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-04
        • 1970-01-01
        • 2020-08-31
        • 2011-09-05
        相关资源
        最近更新 更多