概述
继续跟中华石杉老师学习ES,第50篇
课程地址: https://www.roncoo.com/view/55
思考
聚合分析的内部原理是什么?当我们使用比如aggs,term,avg 、max等执行一个聚合操作的时候,内部原理是怎样的呢?用了什么样的数据结构去执行聚合?是不是用的倒排索引?
知识点
ES搜索靠倒排索引。 排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values。
ES在建立索引的时候,
- 一方面会建立倒排索引,以供搜索用;
- 一方面会建立正排索引,也就是doc values,以供排序,聚合,过滤等操作使用。
doc values是被保存在磁盘上的,此时如果内存足够,os会自动将其缓存在内存中,性能还是会很高,若内存不足,os会将其写入磁盘。
举例说明
举一个 搜索+聚合 的例子 来理解下 倒排索引和正排索引。
GET /test_index/test_type/_search { "query": { "match": { "search_field": "test" } }, "aggs": { "group_by_agg_field": { "terms": { "field": "agg_field" } } } }
那上面的DSL举个例子
假设索引中有3个doc
doc1: hello world test1, test2 doc2: hello test doc3: world test
那ES建立的倒排索引如下:
hello ---> doc1,doc2 world ---> doc1,doc3 test1 ---> doc1 test2 ---> doc1 test ---> doc2,doc3
我们的DSL中的查询
"query": { "match": { "search_field": "test" } }
查询 “test” ,那么直接从倒排索引中查到对应的结果为doc2,doc3 ,那么搜索就是 doc2,doc3 。
纯用倒排索引来实现的弊端
先回归下,最简单的aggs操作
请求DSL中, "field": "color"
,按照某个字段划分bucket操作,
返回结果是 该field对应的value ,每个value对应一个bucket .
那我们上面的例子中的 aggs呢 ? 假设也是 倒排索引的方式来查找,我们来分析下
agg_field
假设如下N多个doc:
... ... ... ...N多doc doc2: agg_field_value_1 doc3: agg_field_value_2
那建立的倒排索引 如下
... ... ... ... ...N多值 agg_field_value_1 doc2 agg_field_value_2 doc3
doc2, doc3, search result --> 实际上,要搜索到doc2的agg_field的值是多少,doc3的agg_field的值是多少
拿到doc2和doc3的agg_field的值之后,就可以根据值进行分组,实现terms bucket操作
doc2的agg_field的值是多少,这个时候,如果你手上只有一个倒排索引,你该怎么办???你要扫描整个倒排索引,去一个一个的搜,拿到每个值,比如说agg_field_value_1 ,看一下,它是不是doc2的值,拿到agg_field_value_2,看一下,是不是doc2的值,直到在倒排索引中找到doc2的agg_field的值。
如果用纯倒排索引去实现聚合,现实不现实啊???性能是很低下的。。。搜索,search,搜倒排索引,搜那个term,就结束了。。。聚合,搜索出了1万个doc,每个doc都要在倒排索引中搜索出它的那个聚合field的值。
倒排索引的话,必须遍历完整个倒排索引才可以。。。。
因为可能你要聚合的那个field的值,是分词的,比如说hello world my name --> 一个doc的聚合field的值可能在倒排索引中对应多个value
所以说,当你在倒排索引中找到一个值,发现它是属于某个doc的时候,还不能停,必须遍历完整个倒排索引,才能说确保找到了每个doc对应的所有terms,然后进行分组聚合
倒排索引+正排索引(doc value)的原理和优势
正排索引 如下:
1万个doc --> 搜 -> 可能跟搜索到15000次,就搜索完了,就找到了1万个doc的聚合field的所有值了,然后就可以执行分组聚合操作了
石杉老师说的最后一句话 ,我没明白, 为啥不用把正排索引都搜索完呢? 有明白的同仁 指导下 拜托了。