正排索引(doc values)
搜索的时候,要依靠倒排索引;排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values。
在建立索引的时候,一方面会建立倒排索引,以供搜索用;一方面会建立正排索引,也就是doc values,以供排序,聚合,过滤等操作使用
doc values是被保存在磁盘上的,此时如果内存足够,os会自动将其缓存在内存中,性能还是会很高;如果内存不足够,os会将其写入磁盘上。
我们了解到倒排索引对搜索是非常高效的,但是在排序或聚合操作方面,倒排索引就显得力不从心,例如我们举个实际案例,假设我们有两个文档:
I have a friend who loves smile
love me, I love you
为了建立倒排索引,我们先按最简单的用空格把每个单词分开,可以得到如下结果:
" * " 表示该列文档中有这个词条,为空表示没有该词条
如果我们要搜索love you,我们只需要查找包含每个词条的文档:
搜索是非常高效的,倒排索引根据词条来排序,我们首先在词条列表中打到love,然后扫描所有的列,可以快速看到doc2包含这个关键词。
但聚合操作呢?我们需要找到doc2里所有唯一的词条,用倒排索引来完成,代价就非常高了,需要迭代索引的每个词条,看一下有没有doc2,有就把这个词条收录起来,没有就检查下一个词条,直到整个倒排索引全部搜索完成。很慢而且难以扩展,并且 会随着数据量的增加而增加。
聚合查询肯定不能用倒排索引了,那就用正排索引,建立的数据结构将变成这样:
这样的数据结构,我们要搜索doc2包含多少个词条就非常容易了。
倒排索引+正排索引结合的优势
如果聚合查询里有带过滤条件或检索条件,先由倒排索引完成搜索,确定文档范围,再由正排索引提取field,最后做聚合计算。这样才是最高效的。
倒排:
doc1: hello world you and me
doc2: hi, world, how are you
word doc1 doc2
hello *
world * *
you * *
and *
me *
hi *
how *
are *
正排:
sort by age
doc1: { "name": "jack", "age": 27 }
doc2: { "name": "tom", "age": 30 }
document name age
doc1 jack 27
doc2 tom 30
禁用正排索引
正排索引默认对所有字段启用,除了analyzed text。也就是说所有的数字、地理坐标、日期和不分析(not_analyzed)字符类型都会默认开启。针对某些字段,可以不存正排索引,减少磁盘空间占用(生产不建议使用,毕竟无法预知需求的变化),示例如下:
PUT /my_index
{
"mappings": {
"dynamic":"strict",
"properties": {
"gender": {
"type": "keyword",
"doc_values": false
}
}
}
}