建立索引和查询
索引和查询文档是该系列中的第二个最佳实践文档。 它向您显示以下最佳实践:
- 如何理解将数据发射到视图中或不发射数据之间的不同结果。
- 为什么您决不能依赖 IBM Cloudant 查询功能而不创建显式索引。
- 为什么必须使用 IBM Cloudant Search (或 IBM Cloudant 查询文本类型的索引) 来限制字段数。
- 如何管理设计文档。
- 为什么分区查询更快,更便宜。
- 如何将主索引用作免费搜索索引。
有关更多信息,请参阅 数据建模 或 实践中的IBM Cloudant。
本文档中的内容最初由 Stefan Kruger 在 2019 年 11 月 21 日作为 最佳和最差实践 博客帖子编写。
了解在将数据发送到视图或不将数据发送到视图中的权衡
由于视图引用的文档始终通过使用 include_docs=true
提供,因此可以执行类似于以下示例的操作,以允许在 indexed_field
上进行查找:
emit(doc.indexed_field, null);
此示例具有以下优点和缺点:
- 索引是紧凑型的。 此索引大小很好,因为索引大小会增加存储成本。
- 指数稳健。 由于索引不存储文档,因此您可以访问任何字段,而无需预先考虑要在索引中存储的内容。
- 缺点是使文档返回比将数据发射到索引本身的替代方法成本更高。 首先,数据库必须在索引中查找请求的密钥,然后读取关联的文档。 此外,如果您正在读取整个文档,但只需要一个字段,那么您将使数据库读取和传输您不需要的数据。
此示例还表示此处存在潜在的竞争状态。 该文档可能会在索引与文档读取之间进行更改或删除 (尽管在实践中不太可能)。
将数据发送到索引 (关系代数项中的所谓 "投影") 意味着您可以对所需的文档的精确子集进行微调。 换句话说,你不需要发出整个文档。 发出仅表示应用程序中所需数据的值,该应用程序是具有最少详细信息的向下分割对象,例如:
emit(doc.indexed_field, {name: doc.name, dob: doc.dob});
如果您改变了对要发出哪些字段的想法,那么需要重建索引。
IBM Cloudant 查询的 JSON 索引在引擎盖下以这种方式使用视图。 IBM Cloudant 查询可以方便地替换某些类型的视图查询,但并非全部。 请花点时间了解何时使用其中一个或另一个。
- IBM Cloudant 查询 文档
- IBM Cloudant 使用 视图的指南
- 使用 include_docs 的性能影响
从不依赖于 IBM Cloudant 查询的无索引的缺省行为
依赖 IBM Cloudant 查询功能而不创建显式索引很有吸引力。 这种做法在性能方面成本很高,因为每次查找都是数据库的完整扫描,而不是索引查找。 如果您的数据很小,那么此全扫描查找无关紧要,但随着数据集的增长,性能将成为您以及整个集群的问题。 我们很可能很快就会限制这一设施。 IBM Cloudant 仪表板提供了一种以简单方式创建索引的方法。
创建索引并创建 IBM Cloudant 使用这些索引的查询需要一些标记。 要确定特定查询正在使用的索引,请将 POST 发送到数据库的 _explain
端点,并将该查询作为数据。
有关更多信息,请参阅 IBM Cloudant 查询文档。
在 IBM Cloudant 搜索 (或 IBM Cloudant 查询文本类型的索引) 中,限制字段数
IBM Cloudant 搜索和 IBM Cloudant 类型为 text
(这两个类型都是 Apache Lucene 下的) 的查询索引为您提供了将任意数量的字段建立索引的方法。 在某些示例中,这种类型的索引被故意滥用,或者大部分是错误的。 规划索引以仅包含实际查询所需的字段。 索引占用空间,如果已建立索引的字段数较大,那么重建索引的成本可能很高。
我们还需要解决您将哪些字段存储在 IBM Cloudant Search 中的问题。 在查询中检索存储的字段而不执行 include_docs=true
,因此权衡类似于 了解发射数据或不进入视图的权衡 部分。 有关更多信息,请参阅 IBM Cloudant
搜索 文档。
设计文档管理需要一些标志
随着数据集的增长以及视图数量的增加,您迟早要思考如何跨设计文档组织视图。 可以使用单个设计文档来构成所谓的 view group
: 一组视图,这些视图由一些对于用例有意义的度量组成。 如果视图是静态的,那么这将使视图查询 URL 在语义上与相关查询相似。 它在索引时的性能也更高,因为索引会装入文档一次,并从中生成多个索引。
设计文档本身通过使用与任何其他文档相同的读/写端点进行读/写。 通过这些端点,您可以在应用程序中创建,检查,修改和删除设计文档。 但是,即使对设计文档的微小更改也会对您的数据库产生重大影响。 更新设计文档时,其中的 所有 视图将变为不可用,直到建立索引完成为止。 这种滞后在生产上会有问题。 为了避免这种情况,您必须执行疯狂的设计文档交换舞 (请参阅 couchmigrate
)。
在大多数情况下,此过程可能不是您想要处理的内容。 随着您的开始,最有可能更方便的是拥有一个按设计的单视图文档策略。
另外,在不明显的情况下,视图是代码。 视图必须遵循您在其他应用程序代码的源代码版本管理方面使用的相同流程。 如何实现这一标准可能并不是立竿见影的。 您可以增加 JavaScript 片段的版本号。 然后,您可以将代码剪切并粘贴到 IBM Cloudant 仪表板中,以在发生更改时进行部署。 是的,我们都时不时地诉诸这种做法。
有更好的方法来执行此操作,我们有理由使用围绕 couchapp
概念的一些工具。 couchapp
是一个自包含的 CouchDB Web 应用程序,现在没有太多用途。 存在几个 couchapp
工具,可以使 couchapp
的部署
(包括其视图) 变得更容易,这一点至关重要。
使用 couchapp
工具意味着您可以根据需要自动部署视图,即使不使用 couchapp
概念本身也是如此。
分区查询更快,更便宜
是的,分区查询更快,更便宜。 选择创建 分区数据库 (相对于未分区数据库) 意味着 IBM Cloudant 使用 分区键 来决定每个文档驻留的分片。 具有相同 分区键 的文档位于同一数据库片段上。 针对 _all_docs
, MapReduce 视图, IBM Cloudant 查询 _find
查询和 IBM Cloudant 搜索操作的请求可以定向到单个分区,而不必在
"scatter and gather" 模式中查询所有分片, 全局查询就是这种情况。
这些 分区查询 仅执行数据库的一个片段。 这种做法使其执行速度比全局查询更快。 出于计费目的,它们被分类为 "读取" 请求,而不是更昂贵的 "查询" 请求,这将为您提供来自同一 IBM Cloudant 套餐的更多可用容量。
并非所有数据设计都适合分区设计,但如果您的数据可以塑造成 <partition key>:<document key>
模式,那么您的应用程序可以从性能和成本方面受益。
将主索引视为免费搜索索引
缺省 IBM Cloudant 文档 _id
是一个 32 个字符的字符串,用于编码 128 位随机数据。 _id
属性用于构造数据库的主索引, IBM Cloudant 用于在用户提供 startkey/endkey
对时按 _id
或键范围检索文档。 我们可以利用此事实将数据打包到 _id
字段中,并将其用作可查询值范围的 "免费"
索引。
请参阅以下列表中的一些示例:
- 使用可时间排序的文档标识,以便将文档排序为粗略的日期和时间顺序。 此排序使您能够轻松地检索最近添加到数据库中的内容。 有关更多信息,请参阅 Time-sortable -IDs。
- 将可搜索数据打包到
_id
字段中,例如,<customerid>~<date>~<orderid>
可用于通过customer
,customer/date
或customer/date/orderid
检索数据。 - 在分区数据库中, 分区键 的明智选择允许将整个数据库缩进到已知分区键的少数文档中。 确保分区模式解决了最常见的用例。
- 在分区数据库中,密钥的两个部分必须包含用户提供的数据 (不存在自动生成的
_ids
) ,因此最好以最佳方式使用该数据。 例如,在 IoT 应用程序中,<sensorid>:<time-sortable-id>
允许按传感器和时间对数据进行排序,而不使用辅助索引。 使用 time-boxed databases 实现此模式以获取最佳结果。