es的查询dsl有很多种类型,比如match query,term query, filter, 关于elasticsearch query 各种dsl可以参考:elastic search query dsl查询语法总结
这篇文章不详细展开具体的区别,仅对完整的流程做一个分析
查询分为两个阶段:query阶段和fetch阶段
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进行查询的
这里有一个norms的概念,以及节省存储空间的一个细节
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值了。
参考:elasticsearch中mapping定义中norms字段的疑问?
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中的数据,取出当前要获取的那一页的数据了。
这就是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 方法, 搜索精度比较高。
搜索的慢查询日志
可以针对query phase和fetch phase单独设置慢查询的阈值