当前位置: 首页 > 知识库问答 >
问题:

将Azure Cosmos DB中存储的实体上的“扩展”元数据存储为JSON文档

戚侯林
2023-03-14

我们正在.NET中构建一个REST API,部署到Azure应用程序服务/Azure API应用程序。通过该API,客户端可以创建“产品”并查询“产品”。产品实体有一组通用的字段,所有客户在创建产品时都必须提供这些字段,如下面的字段(示例)

{
"id": "cbf3f7aa-4743-4198-b307-260f703c42c1"
"name": "Product One"
"description": "The number one product"
}

我们目前将这些产品作为自包含文档存储在Azure Cosmos DB中。

问题一:分区。该集合不会存储大量的文档,我们谈论的最多是大约2 500 000个文档,每个文档在1 - 5 kb之间(估计)。我们目前已经选择了id字段(这是我们的系统生成的id,而不是内部的Cosmos DB文档id)作为分区键,这意味着2 500 000个逻辑分区,每个分区一个文档。这些文档将用于一些低延迟的工作负载,但是这些工作负载将通过id(分区键)进行查询。客户端也将通过例如名称进行查询,然后我们有一个扇出查询,但是这些查询将不会是延迟关键的。在门户中,您不能再创建单个分区集合,但是您可以通过SDK或固定的分区键值来创建。如果我们将所有这些文档放在一个分区中(这里我们讨论的是远低于10 GB的数据),我们将永远不会得到任何扇出查询,而是更多地依赖于一个逻辑分区中的索引。所以问题是:即使我们没有海量的数据,像我们目前所做的那样进行分区仍然是明智的吗?

问题 2:扩展元数据。我们将面对想要在基本公共字段之外编写客户端/应用程序/客户特定元数据的客户。最好的方法是什么?

下面是我的一些头脑Storm。

一个选项是允许API中的客户端在创建产品时添加一种类型的嵌套“extendedMetadata”字段和键值对。Cosmos DB是模式不可知的,所以理论上这应该很好。一些产品可以没有扩展元数据,而其他产品可以有很多扩展元数据。对于客户端,我们可以promise基本的公共字段,但对于扩展的元数据字段,我们不能promise字段数量、命名等方面的任何内容。文档大小将随之变化。如前所述,这些产品仍将用于按“id”(分区键)进行查询的延迟关键工作负载扩展元数据永远不会用于任何延迟关键工作负载。性能/吞吐量对文档大小的影响有多大,一般如何?对于延迟关键的读取场景,查询优化器将直接转到正确的分区,然后使用索引快速检索感兴趣的文档字段。或者,整个文档总是独立于要查询的字段进行加载和处理吗?

{
"id": "cbf3f7aa-4743-4198-b307-260f703c42c1"
"name": "Product One"
"description": "The number one product"
"extendedMetadta" : {
    "prop1": "prop1",
    "prop2": "prop2", 
    "propN": "propN"
}
}

扩展元数据仅在某些情况下用于从同一API检索。我们可以这样做:

  • api.org.com/products/{id}--将始终返回具有基本公共字段的乘积
  • api.org.com/products/{id}/扩展--将返回完整文档(基本扩展元数据)

一种选择可能是进行某种拆分。如果 API 中的客户端创建了一个包含扩展元数据的产品,那么如果 extendedMetadata 包含数据,我们可以实现一些拆分文档的逻辑。我想分裂可以通过多种方式完成,在下面进行头脑Storm。我猜拆分文档的主要目的(这需要在写入操作上做更多的工作)是为了获得更好的吞吐量,以防文档大小在这里发挥重要作用(在大多数情况下,客户端可以使用基本的公共字段)。

    < li >一个仅包含基本公共字段的基本文档和一个包含基本公共字段的扩展文档(具有相同的id)扩展元数据(基本公共字段的副本)我们可以添加“类型”字段,以区分基本文档和扩展文档。如果客户要求扩展,我们将只查询“扩展”类型的文档。 < li >一个仅包含基本公共字段的基本文档是对一个仅包含扩展元数据的扩展文档的引用。这意味着当客户请求具有扩展元数据的产品时,读取操作需要读取两个文档。 < li >考虑将其拆分为不同的集合,一个集合保存基本文档,吞吐量专用于低延迟读取场景,另一个集合保存扩展元数据。

抱歉发了这么长的帖子。希望这是可以理解的,期待您的反馈!

共有1个答案

闻人博
2023-03-14

答案一:

如果您可以保证文档总大小永远不会超过10GB,那么创建固定集合是出于2个原因的方法。首先,不需要跨分区查询。我并不是说没有分区就会快如闪电,但是因为你只与一个简单的物理分区进行交互,所以它比在每个物理分区中查找数据要快。

(但是请记住,每当人们认为他们可以保证某些东西的最大尺寸时,它通常不会成功。

/id 分区策略只有在始终提供 id 时才有效。这称为读取。如果需要按任何其他属性进行搜索,则表示您正在执行查询。这是html" target="_blank">系统不会做得那么好的地方。

理想情况下,您应该以一种永远不会将跨分区查询作为日常工作负载的一部分的方式设计您的Cosmos DB集合。出于报告原因,也许千载难逢。

答案二:

Cosmos DB是一个无NoSQL模式的数据库是有原因的。头脑Storm中的第二种方法适用于传统的RDBMS数据库,但我们这里没有。您可以简单地使用第一种方法,或者将所有属性都放在一个属性下,或者将它们放在顶层。

请记住,您可以将响应映射到您想要的任何对象,因此您只需要2个DTO。一个瘦版本和一个扩展版本,并根据endpoint映射到不同的版本。

希望这有帮助。

 类似资料:
  • 我一直在android studio上开发一个Java应用程序,我想提取我存储在google数据存储中的几个实体。实体存储为列表 我只需要每个属性的“值”。 有没有办法将响应转换回带有json的数据存储实体? 编辑:我的代码片段

  • 问题内容: 我认为这是一个n00b要做的事情。因此,我从未做到过。然后,我看到FriendFeed做到了这一点,实际上使他们的数据库扩展性更好,并减少了延迟。我很好奇我是否应该这样做。而且,如果是这样,正确的方法是什么? 基本上,什么地方是学习如何将MySQL中的所有内容存储为CouchDB类数据库的好地方?将所有内容存储为JSON似乎会变得更加轻松快捷(无需构建,延迟更短)。 此外,是否容易编辑

  • 问题内容: 有人可以告诉我,在以下情况下如何进行? 接收文件(MS文件,ODS,PDF) 通过Apache Tika提取公元核心元数据+通过jackrabbit-content-extractors提取内容 使用Jackrabbit将文档(内容)及其元数据存储到存储库中 ? 检索文档+元数据 我对第3点和第4点感兴趣… 详细信息:该应用程序正在以交互方式处理文档(一些分析-语言检测,单词计数等。+

  • 我正试图让我的头绕过DDD,但我卡住了。这就是我如何设置我的项目: 然后,我继续实现UserRepository,这里我遇到了另一个问题:UserRepository接口需要域用户模型,当我试图在DAL中实现接口时,我需要使用域用户模型来实现它,这导致DAO是为域模型而不是DAL模型创建的,这没有任何意义。唯一能修正的就是在域层中引用DAL,这是错误的。 有人能解释一下我在DDD中遗漏了什么吗?

  • 我正在处理一个用例。要求是我需要创建订单。订单有一些客户参数。订单可以多次修改。最初,我想在以太坊中实现它。因此,我考虑从UI中捕获客户详细信息,并将其存储在智能合约中。然而,问题是一旦部署了合同,我就不能更改它,因为它是不可变的。这个缺点使我无法使用以太坊。考虑到Corda,我可以将客户数据存储为单个记录,并对其进行修改,以便将修改存储在我们可以查询的分类帐中吗。例如,我想存储客户ID、客户名称

  • 我想用Spring Boot数据JPA配置我的应用程序,并调用存储过程。然而,在搜索web之后,我发现这种方法必须使用某种“实体表”。 例如,这可以从这里和这里的解释中看出。 但是,我不明白为什么需要将存储过程元数据定义绑定到一个实体上?如果我没有这样的实体表怎么办?没有别的办法了吗?