【问题标题】:Encode PartitionKey into Document Id?将 PartitionKey 编码为文档 ID?
【发布时间】:2018-03-27 15:08:06
【问题描述】:

我已将我的一个 Cosmos DB 的分区键设置为 /partition

例如:我们有一个包含订阅者列表的Chat 文档,然后我们有一个包含文本、对作者的引用和一些其他属性的ChatMessages。两个文档都有一个 partition 属性,其中包含“聊天”类型和聊天 ID。

聊天示例:

{
"id" : "955f3eca-d28d-4f83-976a-f5ff26d0cf2c",
"name" : "SO questions",
"isChat" : true,
"partition" : "chat_955f3eca-d28d-4f83-976a-f5ff26d0cf2c",
"subscribers" : [
    ...
]
}

然后我们有这样的消息文档:

{
"id" : "4d1c7b8c-bf89-47e0-83e1-a8cf0d71ce5a",
"authorId" : "some guid",
"isMessage" : true,
"partition" : "chat_955f3eca-d28d-4f83-976a-f5ff26d0cf2c",
"text" : "What should I do?"
}

现在返回特定聊天的所有消息非常方便,我只需要使用属性isMessage = true查询分区chat_955f3eca-d28d-4f83-976a-f5ff26d0cf2c的所有文档。一切都好...

但如果我现在想通过 id 查询我的数据库以获取特定消息,我通常只知道 id,但不知道分区,因此必须运行 slow crosspartition 查询。这让我想到了一个问题,如果我不应该将 partitionKey 添加到消息 id 中,这样我就可以在查询 db 时拆分 id 以便更快地查找。我看到文档的 _rid 属性看起来像是 db 的 id 和集合的 id 的组合,然后是文档特定的 id。我的意思是(简化):

Chat.Id = "abc"
Chat.Partition = "chat_abc"  //[type]_[chatId]
Message.Id = "chat_abc|123" //[Chat.Partition]|[Message.Id]
Message.Partition = chat_abc //[Chat.Partition]

假设我现在想通过id 获取Message 文档,我只需将id 拆分为| 符号,然后使用id 的第一部分查询文档为分区和完整的id作为key。

这有意义吗?有没有更好的方法来做到这一点?我是否应该始终传递文档的partitionKey,而不仅仅是id?我应该只使用_rid 属性吗?

非常感谢任何经验!

更新

我找到了以下答案here

一些应用程序将分区键编码为 ID 的一部分,例如 分区键是客户 ID,ID = "customer_id.order_id", 这样您就可以从 ID 值中提取分区键。

我已经通过电子邮件进一步询问了 cosmos 团队这是否是推荐的模式,并发布了答案,以防万一。

【问题讨论】:

    标签: azure-cosmosdb database-partitioning


    【解决方案1】:

    是的,您从 id 中提取分区键的建议(通过前缀/分隔符之类的约定)是有道理的。这在具有单个密钥并希望重构它以使用来自不同存储系统的 Cosmos DB 的应用程序中很常见。

    如果您是从头开始构建应用程序,则应考虑通过 API/应用程序连接复合键(分区键 + 项目键(“id”))。

    【讨论】:

      【解决方案2】:

      首先,如果您知道您的数据(和索引)大小)将保持在 10gb 的限制内,并且您的 RU/sec 限制没问题,那么固定的无分区集合将绕过这个问题。可能 OP 在知情的情况下做出了需要分区的决定,但出于泛化目的,这是一个重要的考虑因素。如果可能,亲吻 ;)

      如果分区是必须的,那么除非您知道分区键,否则您无法避免 crosspartition 拆分及其开销。

      恕我直言,将重复的分区键合并到 id 字段的 OP 建议是一个相当丑陋的解决方案,因为:

      1. 名称id 表示它是唯一键,分区键不是它的一部分,也不是该键及其唯一性所必需的。任何在上游使用此密钥的人都会承担更长密钥的强制超额成本,无法使用更简单的Guid 类型等。
      2. 如果您的分区键更改将来会变得一团糟。
      3. 合并的id 的内部结构如果没有文档就不会直观 - 它的部分没有命名,即使它们看起来有一个模式,新开发者也不会在没有找到外部的情况下确定文档以可靠地了解正在发生的事情。
      4. 您的数据模型不需要这种语义级别的重复,这将是为了您的应用程序查询舒适,因此此类黑客应该属于您的应用程序代码,而不是数据模型。如果可能,应避免此类泄漏问题。
      5. 文档内的数据重复会不必要地增加文档大小、带宽等(可能会或可能不会显着,具体取决于规模和使用情况)。有时需要进行文档内复制,但恕我直言,在这种情况下不一定。

      更好的设计是确保分区键始终存在于逻辑上下文中并且可以传递给查找。如果您没有它可用,那么也许您应该重构您的应用程序代码(而不是数据设计)以在需要的地方显式传递 chatIdid。那就是没有将它们合并成一些不透明的字符串格式。

      此外,我没有看到使用 _rid 的好方法,就好像我没记错一样,它不包含对分区或分区键的任何内部引用。

      免责声明:我对内部 CosmosDB 索引设计或分区集合上的 _rid 逻辑没有任何访问权限或深入了解。我可能误解了它的工作原理。

      【讨论】:

      • 感谢您对此问题的意见。我同意你的一些想法,但在这种情况下,请依赖 Cosmos DB 工程团队成员的专业知识。
      • np。这是投资回报率/风险的问题。重构选择可能更简洁,但对于现有应用程序来说显然成本更高。
      猜你喜欢
      • 2011-10-21
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      • 2014-06-22
      • 1970-01-01
      相关资源
      最近更新 更多