“文档值是在索引时构建的,而不是在搜索时构建的”,那么如果使用 doc_values 会构建什么?
有两种类型的工作负载,我们需要在数据之上的列视图:排序和聚合。而在当前版本的 Elasticsearch 中有两种情况:
- 该字段仅被索引。在这种情况下,如果您开始对给定字段进行排序/聚合,则数据将在搜索时延迟不反转并放入缓存中,以便您可以访问给定文档 ID 的值。这意味着倒排索引,例如
foo -> 0, 1
bar -> 1
将转换为以下数据结构
0 -> foo
1 -> foo, bar
- 该字段启用了文档值。在这种情况下,数据将在索引时以列格式存储。您在搜索时需要做的所有事情都是加载一些关于您的字段及其编码方式的微小元数据。然后将直接从磁盘读取数据(依赖文件系统缓存来提高性能)。
“doc 值是预先构建的,并且初始化速度要快得多”,为什么它要快得多?
我提到的这个非反转过程实际上是 CPU 和 I/O 密集型的。结果被放入缓存中,但第一次访问仍然很慢,这将损害在大型合并后立即运行的所有查询的延迟。您可以通过急切加载 fielddata 来解决此问题,但即使它会使响应时间更好,它也会将问题转移到其他地方,并且对索引的更改将需要更长的时间才能变得可见,因为 elasticsearch 将等待在新点之前加载字段数据索引上的实时视图可供搜索。
另一方面,使用 doc 值,您只需要从磁盘读取一些微小的元数据即可。
“但没有使用堆内存”,所以使用页面缓存?
确切地!文档值需要很少的堆内存,主要是关于字段字段的元数据以及事物在磁盘上的编码方式。其余部分直接从磁盘读取,并依赖文件系统缓存来提高性能。
有人可以向我解释一下 doc_values 是如何实现的,我应该什么时候使用?我定期用 jstat 检查我的堆使用情况,我可以看到我仍然有足够的空间可以使用。
这有点复杂,因为有不同的情况......例如:
- 取决于字段的类型(数字与字符串)
- 字段是单值还是多值
- 场的基数
- 数据的一些模式......例如,我们在编码数字字段时检查公约数,以便在所有值共享公约数的情况下进行更有效的压缩。如果您以秒或天精度编码时间戳,通常会发生这种情况,因为所有值都是 1000 的倍数。
但在实践中,重要的是要知道它基本上是一个非常大的 mmap 文件,按顺序读取,因此即使是基于磁盘的,它仍然对您的 I/O 系统很友好。
如果您对此感兴趣,可以阅读更多相关信息
关于何时应该使用文档值,我认为您应该在计划排序或聚合的所有字段上启用文档值。在下一个 elasticsearch 主要版本中,关于默认启用 doc 值的讨论正在进行中。