本文将从数据存储和搜索的角度简单分析Elasticsearch的搜索运行机制,主要涉及搜索API、搜索机制、存在问题和解决方案。

4.1 Search API

Search API允许用户执行一个搜索查询并返回匹配查询的搜索命中结果。

Elasticsearch查询主要有两种方式:URI SearchRequest Body Search

  • URI Search:通过URI参数实现搜索,特点是操作简便,仅包含部分查询语法,常用参数如下:

    q:指定查询语句,使用Query String Syntax

    df:默认字段,不指定时,会对所有字段进行查询

    sort:排序

    profile:用于查看查询是如何被执行的

  • Request Body Search:完备的查询语法Query DSL,所以还是建议使用Request Body Search。

4.2 深入了解Search运行机制

建议先参考上篇Elasticsearch核心技术(四):索引原理分析,其中主要介绍了ES的分布式存储架构和原理。

4.2.1 Query-then-Fetch运行机制

Elasticsearch的分布式搜索的运行机制称为Query-then-Fetch。具体分为Query和Fetch两个阶段:

Query阶段

用户发出搜索请求到达ES节点。节点收到请求后,会以协调节点(Coordinating Node)的身份,在6个主副分片中随机选择3个分片,发送查询请求。

被选中的节点,进行排序(根据score值进行排序)。然后每个分片都返回 From+size 个排序后的文档id和排序值给协调节点。 注意这里返回的是文档id。

Fetch阶段

Coordinating节点将Query阶段从每个分片获取的排序的文档id列表重新进行排序,选取 From 到 From+size 个文档的id。

multi get请求的方式,到相应的分片获取详细的文档数据。

4.2.2 为什么需要两阶段才能完成搜索

因为Elasticsearch在查询的时候不知道文档位于哪个分片,因此索引的所有分片都要参与搜索,然后协调节点将结果合并,在根据文档ID获取文档内容。例如现在有5个分片,需要查询匹配度Top10的数据,那么每个分片都要查询出当前分片的Top10的数据,协调节点将5×10个结果再次进行排序,返回Top10的结果给客户端。

4.2.3 Query-then-Fetch存在问题和解决方案

Query-then-Fetch存在问题分为两方面,一个是性能问题,一个是相关性算分问题。

  • 性能问题

性能问题主要表现为深度分页的问题。Elasticsearch数据是分片存储的,数据分布在多台机器上。有这样一个场景,如何获取前1000个文档?当获取从990-1000的文档时候,会在每个分片上面都先获取1000个文档,然后再由协调节点聚合所有分片的结果在排序选取前1000个文档。

这个过程有什么问题吗?当然是有的,页数越深,处理文档越多,占用内存越多,耗时越长。所以要尽量避免深度分页。当然,ES官方也注意了这个问题,所以通过index.max_result_window限定最多到10000条数据。当然我们也可以根据业务需要修改这个参数,这也解释了:为什么Google搜索结果只有相关度最高的17页结果,百度只有76页的结果,原因之一是受限于Elasticsearch深度分页的性能问题。



  • 相关性算分问题

    另外一个问题是相关性算分不准确问题。每个分片都基于自己分片上面的数据进行相关度计算。这会导致打分偏离的情况,特别是数据量很少的时候。相关性算分在分片之间是相互独立。当文档总数很少的情况下,如果主分片大于1,如果主分片数越多,相关性算分会越不准。

  • 如何解决算分不准的问题?

  1. 当数据量不大的时候,将主分片数设置为1;当数据量足够大的时候,只要保证文档均匀分布在各个分片上面,结果一般不会出现偏差
  2. 使用DFS Query Then Fetch

    在搜索的URL中指定参数 _search?search_type=dfs_query_then_fetch ;这样就可以保证每个分片把各个分片的词频和文档频率进行搜集,然后进行一次相关性算分。但是这样会耗费更多的CPU和内存资源,执行性能较低。
  • 如何避免深度分页的问题?

使用Search_After

ES提供实时的下一页文档获取功能,这个功能只能下一页,不能上一页;

不能指定页数,不能使用from参数;

  • 三种分页方式对比:
类型 场景
From/Size 需要实时获取顶部的部分文档,且需要自由翻页
Scroll 需要全部文档,如导出所有数据的功能
Search_After 需要全部文档,不需要自由翻页

4.3 总结

经济基础决定上层建筑,ES的分片存储决定了搜索机制。其实存储和搜索不能分割开来看,只存储不可搜索,这个存储是没有意义的;只搜索没有存储(数据源)是空中楼阁。

Elasticsearch核心技术(五):搜索API和搜索运行机制的更多相关文章

  1. ElasticSearch(十五) _search api 分页搜索及deep paging性能问题

    1.分页搜索 语法: size,from GET /_search?size=10 GET /_search?size=10&from=0 GET /_search?size=10&f ...

  2. 五:理解控件的运行机制(例:基于Control命名空间的简单控件)

    一:先用最简短的话说点理论的1.asp.net中所有的标准控件都可以重写 2.和控件相关的命名空间有 System.Web.UI.Control是所有控件的基类只提供简单的呈现逻辑,不支持样式表 Sy ...

  3. elasticsearch系列四:搜索详解(搜索API、Query DSL)

    一.搜索API 1. 搜索API 端点地址 从索引tweet里面搜索字段user为kimchy的记录 GET /twitter/_search?q=user:kimchy 从索引tweet,user里 ...

  4. Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery)

    Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery) 体验 冒号搜索 1. 获取谷歌搜索api 谷歌搜索api教程 2. 后台调用 程序入口 main.go // ...

  5. ES系列五、ES6.3常用api之搜索类api

    1.搜索api 1.1.routing:路由 执行搜索时,它将广播到所有索引/索引分片(副本之间的循环).可以通过提供routing参数来控制将搜索哪些分片.例如,在索引book时,路由值可以是nam ...

  6. ElasticSearch查询 第一篇:搜索API

    <ElasticSearch查询>目录导航: ElasticSearch查询 第一篇:搜索API ElasticSearch查询 第二篇:文档更新 ElasticSearch查询 第三篇: ...

  7. SpringBoot:elasticSearch 7.2.0 Java High Level REST Client 搜索 API

    Springboot整合最新版elasticSearch参考之前的文章:SpingBoot:整合ElasticSearch 7.2.0 Search API SearchRequest用于与搜索文档, ...

  8. Elasticsearch java api 基本搜索部分详解

    文档是结合几个博客整理出来的,内容大部分为转载内容.在使用过程中,对一些疑问点进行了整理与解析. Elasticsearch java api 基本搜索部分详解 ElasticSearch 常用的查询 ...

  9. ElasticSearch High Level REST API【5】使用模板搜索

    ElasticSearch Rest高级API 提供了多种搜索方式,除了前面讲到的search查询,ElasticSearch 还提供了通过模板搜索查询.我个人比较喜欢这种方式. 我们可以通过脚本预选 ...

随机推荐

  1. Freeswitch 安装爬坑记录1

    2 Freeswitch的安装 2.1 准备工作 服务器安装CentOS 因为是内部环境,可以关闭一些防火墙设置,保证不会因为网络限制而不能连接 关闭防火墙 查看防火墙 systemctl statu ...

  2. oracle 根据ids转names

     WITH t AS (SELECT '1,2,3,4' a, 1 b    FROM Dual  UNION ALL  SELECT '1,2,3' a, 2 b FROM Dual),p AS ( ...

  3. 【Linux】【Basis】块存储,文件存储,对象存储

    1. 块存储: 定义:这种接口通常以QEMU Driver或者Kernel Module的方式存在,这种接口需要实现Linux的Block Device的接口或者QEMU提供的Block Driver ...

  4. mysql explain using filesort

    创建表,字段tid上无索引(mysql 5.7) CREATE TABLE `test` ( `tid` int(11) DEFAULT NULL, `tname` varchar(12) DEFAU ...

  5. What happens when more restrictive access is given to a derived class method in C++?

    We have discussed a similar topic in Java here. Unlike Java, C++ allows to give more restrictive acc ...

  6. MySQL(1):SQLyog

    数据库(DataBase,简称DB) 一. 基本数据库操作命令 flush privileges 刷新数据库 show databases 显示所有数据库 use dbname 打开某个数据库 sho ...

  7. navicat突然连接不上远程linux服务器上的mysql

    我linux服务器上的mysql是docker安装的,突然有一天我的navicat连接不上服务器上的mysql,于是开始了下面一系列的修复 1.首先登录服务器上mysql,看是否能正常登录,我发现不能 ...

  8. 最小化安装centos ubuntu基础命令

    # yum install vim iotop bc gcc gcc-c++ glibc glibc-devel pcre \ pcre-devel openssl openssl-devel zip ...

  9. List如何一边遍历,一边删除?

    1.新手常犯的错误 可能很多新手(包括当年的我,哈哈)第一时间想到的写法是下面这样的: public static void main(String[] args) { List<String& ...

  10. 【Java多线程】线程池-ThreadPoolExecutor

    ThreadPoolExecutor提供了四个构造方法: 我们以最后一个构造方法(参数最多的那个),对其参数进行解释: public ThreadPoolExecutor(int corePoolSi ...