在建立索引的时候,一方面会建立倒排索引,以供搜索用;
一方面会建立正排索引,也就是 doc value
,以供排序,聚合,过滤等操作使用。
doc value
是被保存在磁盘上的。此时如果内存足够,os 会自动将其缓存在内存中。
doc1: {"field_1": "value1", "field_2": "value1"}
doc2: {"field_1": "value2", "field_2": "value2"}
-
搜索请求发送到某一个
coordinate node
,构建一个priority queue
,长度以paging
操作from
和size
为准,默认是 10 -
coordinate node
将请求转发到所有shard
,每个shard
本地搜索,并构建一个本地的priority queue
-
各个
shard
将自己的priority queue
返回给coordinate node
,并构建一个全局的priority queue
-
这个过程就是
query phase
由于 document
到达 coordinate node
还需要进行排序、分页、聚合等操作,所以部分数据可能是不需要的。为了减少网络传输的开销,priority quere
中只包含了 doc id
在 coordinate node
构建完 priority queue
之后,就发送 mget
请求去所有 shard
上获取对应的 document
各个 shard
将 document
返回给 coordinate node
后,coordinate node
将合并后的 document
结果返回给 client
客户端
假设有 5 个
shard
,每个shard
返回的priority queue
都是根据某个field
排序后的结果,现在我们需要获取排序后前四个document
。首先每个
shard
会返回内部排序后的前四个document
,例如
6 3 2 1
7 5 3 2
3 2 1 0
9 4 2 1
4 3 2 1
然后将
doc id
返回给coordinate node
处理
coordinate node
会获取每个priority queue
首位的document
然后根据field
对priority queue
进行排序,得到
9 4 2 1
7 5 3 2
6 3 2 1
4 3 2 1
3 2 1 0
那么就可以排除近一半的数据,前四的结果只可能存在于这半边
9 4 2 1
7 5 3
6 3
4
此时使用
mget
获取这些数据,然后进行排序即可获得结果
两个 document
排序,field
值相同
- 在不同的
shard
上,可能排序不同 - 每次请求打到不同的
replica shard
上,这样可能就会导致看到搜索结果不一样
解决方案:使用 preference
他可以决定哪些 shard
会被用来执行搜索操作
通过将 preference
设置为一个字符串,比如说 user_id
,让每个 user
每次搜索的时候,都使用同一个 repliace shard
来执行,就不会发生 bouncing results
了。
document
文档路由默认是 _id
路由,如果需要根据其他 field
来确定 document
归属于哪个 shard
的话,可以设置routing=field
scroll
滚动搜索 es 内部支持的一种按批搜索模式,目的是解决大量数据查询带来的性能问题。
使用 scroll
搜索,es 会保存一个当前的快照,之后只会基于该旧快照提供数据搜索。
这个时期的数据变更,对用户是透明的。
scroll
和 paging
的区别是,scroll
是在服务内部完成滚动搜索获取大量数据,而 paging
只是为了获取当前页的数据。
scroll
同样会有分布式排序问题,推荐采用基于 _doc
进行排序的方式,性能较高。
假如 os cache 中的数据丢失
-
os disk 会同步从上一次 commit point 开始的所有 segment file 到磁盘上。
-
translog 会存储上一次 flush 开始的所有数据变更记录。
此时重启数据,首先会将 translog 文件中的变更记录进行回放,再重新将 segment 刷入 os cache 中,等待下一次 commit point 的发生。