Elasticsearch 查询分为两个阶段:查询的过程大体上分为查询(query)和取回(fetch)两个阶段。这个节点的任务是广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。
简单说就是先根据条件在所有分片(所有分片)上查询满足条件的id,汇总到coordinate node上进行汇总排序,然后根据选出的id到各node上获取数据。
一、Query阶段
1、客户端发送请求到任意一个coordinate node(节点默认就为coordinate node)构建一个priority queue,长度以paging操作from和size为准,默认为10
2、coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡
3、每个shard本地搜索,并构建一个本地的priority queue 接收到请求的每个shard,也会构建一个from + size大小的本地priority queue。
这里面是如何进行_score计算的,其根据这个本地shard的tf-idf情况,进行相关度评分
这是多shard下可能评分发生评分不准的原因
如何调用底层lucene进行查询的
lucene在内部会通过doc id来唯一标识一个document,这个doc id是integer类型,范围在0到索引中含有的document数量之间。这些doc id是用来在lucene内部的api之间进行通信的,比如说,对一个term用一个match query来进行搜索,就会产生一个doc id集合,然后这些doc id会用来获取对应的norm值,以用来计算每个doc的相关度分数。
而根据doc id查找norm的过程,是通过每个document的每个field保留一个字节来进行的一个算法,这个过程叫做norm查找,norm就是每个document的每个field保留的一个字节。对于每个doc id对应的那个norm值,可以通过读取es一个内置索引(doc_id的索引)中的一个字节来获取。这个过程是性能很高的,而且可以帮助lucene快速的定位到每个document的norm值,但是同时这样的话document本身就不需要存储这一个字节的norm值了。
4、各个shard将自己的priority queue返回给coordinate node。coordinate node将所有shard的from + size大小的priority queue,进行merge。merge成一个from + size大小的priority queue,全局排序后的queue,放到自己的queue中。此时,coordinate queue,就可以将自己priority queue中的数据,取出当前要获取的那一页的数据了。此时,coordinate queue,就可以将自己priority queue中的数据,取出当前要获取的那一页的数据了。
这就是es deep page效率低的原因
二、Fetch阶段
1、coordinate node获取query phase结果后,获取到的是一堆doc id等信息。就会发送mget api去各个shard上批量一次性获取自己需要的数据
2、各个shard将document返回给coordinate node
3、coordinate node将合并后的document结果返回给client客户端
4、特殊情况:document如果还在建立索引过程中,可能只有primary shard有,任何一个replica shard都没有,此时可能会导致无法读取到document,但是document完成索引建立之后,primary shard和replica shard就都有了
三、search_type
搜索相关参数有一个search_type参数
default:query_then_fetch,就是请求分为两次,如上面介绍的。
另外一种type:dfs_query_then_fetch,可以提升relevance sort精准度
DFS 其实就是在进行真正的查询之前, 先把各个分片的词频率和文档频率收集一下, 然后进行词搜索的时候, 各分片依据全局的词频率和文档频率进行搜索和排名。 显然如果使用 DFS_QUERY_THEN_FETCH 这种查询方式, 效率比较低,因为一个搜索, 可能要请求 3 次。 但使用 DFS 方法, 搜索精度比较高。
四、相关性计算
在搜索过程中对文档进行排序,需要对每一个文档进行打分,判别文档与搜索条件的相关程度。在旧版本的ES中默认采用TF/IDF(term frequency/inverse document frequency)算法对文档进行打分。
五、数值类型对搜索效率的影响
ES5.x之前用到的Lucene版本,实际上只能够索引文本类型的数据,表面上被定义为数值类型的字段,在暗地里都被转换成了字符串,编排成了倒排索引。