Elasticsearch 入门到精通-Elasticsearch查询原理Query-Fetch分析

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版本,实际上只能够索引文本类型的数据,表面上被定义为数值类型的字段,在暗地里都被转换成了字符串,编排成了倒排索引。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值