elasticsearch查询原理query-fetch分析

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单独设置慢查询的阈值

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Elasticsearch 中使用深度分页功能需要注意以下几点: 1. 尽量避免使用深度分页功能,因为它会增加网络和计算开销,可能导致性能问题。 2. 深度分页功能是通过设置 from 和 size 参数来实现的。from 参数表示从哪个位置开始查询,size 参数表示每页返回的文档数量。 3. Elasticsearch 默认最多只能返回 10000 条记录,如果需要查询更多的记录,需要设置 index.max_result_window 参数。但是设置太大会占用过多的内存,影响性能。 下面是一个 Java 实现 Elasticsearch 分页查询的示例代码: ``` import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.Client; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; public class ESQuery { private Client client; public ESQuery(Client client) { this.client = client; } public void search(String index, String type, int from, int size) { SearchResponse response = client.prepareSearch(index) .setTypes(type) .setQuery(QueryBuilders.matchAllQuery()) .addSort(SortBuilders.fieldSort("_id").order(SortOrder.DESC)) .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setFrom(from) .setSize(size) .execute() .actionGet(); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); } } } ``` 调用示例: ``` ESQuery esQuery = new ESQuery(client); esQuery.search("my_index", "my_type", 0, 10); // 查询第一页,每页10条记录 esQuery.search("my_index", "my_type", 10, 10); // 查询第二页,每页10条记录,从第11条记录开始 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值