[Elasticsearch] 分布式搜索

分布式搜索

本文翻译自Elasticsearch官方指南的Distributed Search Execution一章。

在继续之前,我们将绕一段路来谈谈在分布式环境中,搜索是怎样运行的。和在分布式文档存储(Distributed Document Store)中讨论的基本CRUD操作相比,这个过程会更加复杂一些。

一个CRUD操作会处理一个文档,该文档有唯一的_index,_type和路由值(Routing Value,它默认情况下就是文档的_id)组合。这意味着我们可以知道该文档被保存在集群中的哪个分片(Shard)上。

然而,搜索的运行模型会复杂的多,由于我们无法知道哪些文档会匹配 - 匹配的文档能够在集群中的不论什么分片上。因此搜索请求须要訪问索引中的每一个分片来得知它们是否有匹配的文档。

可是,找到全部匹配的文档仅仅完毕了一半的工作。从多个分片中得到的结果须要被合并和排序以得到一个完整的结果,然后search API才可以将结果返回。正由于如此,搜索由两个阶段组成(Two-phase Process) - 查询和获取(Query then Fetch)。

查询阶段(Query Phase)

在查询的初始阶段,查询会被广播(Broadcast)给索引中的每一个分片拷贝(Shard Copy,它能够是主分片或者是副本分片)。然后每一个分片会在本地运行该搜索,匹配的文档会被保存到一个优先队列(Priority Queue)中。

优先队列

优先队列实际上是一个用来保存前N个匹配(Top-N Matching)的文档的有序列表。优先队列的大小取决于分页參数:fromsize。比方,以下的搜索请求会建立一个大小为100的优先队列用于保存匹配的文档:

GET /_search
{
    "from": 90,
    "size": 10
}

查询阶段的步骤例如以下图所看到的:

  1. client发送一个搜索请求到节点3,节点3随即会创建一个大小为from + size的空的优先队列。
  2. 节点3将搜索请求转发到索引中每一个分片的主分片(Primary Shard)或副本分片(Replica Shard)。然后每一个分片会在本地运行该查询,然后将结果保存到本地的一个大小相同为from
    + size
    的优先队列中。
  3. 每一个分片返回优先队列中文档的IDs和它们的排序值到协调节点(Coordinating Node),也就是节点3。然后节点3负责将全部的结果合并到本地的优先队列中,这个优先队列就是全局的查询结果。

当一个搜索请求被发往一个节点时,该节点就变成了协调节点(Coordinating Node)。它须要向其它关联分片所在的节点广播搜索请求,然后合并来自它们的中间结果来得到终于可以发送给client的全局结果。

第一步是将请求广播给索引中全部分片拷贝(能够是主分片,也能够是副本分片)所在的节点。和获取文档的GET请求一样,搜索请求也能够被主分片或者它关联的随意一个副本分片处理。这就是当添加副本分片(加入很多其它的硬件)能够添加搜索吞吐量的原由。协调节点会通过循环(Round-robin)的方式向全部的分片拷贝发送请求来分布负载。

每一个分片会在本地运行查询,然后建立一个大小为from + size的优先队列来保存其结果。换言之,在本地就行满足全局的搜索请求(译注:由于本地的优先队列大小和协调节点上的优先队列大小是一致的)。它会返回一个轻量级的结果列表给协调节点
- 仅包括文档的IDs和在排序过程中须要的相关值,比方_score

协调节点会将从其它节点返回的结果合并来得到一个全局的优先队列。到这里,查询阶段就结束了。

多索引搜索(Multi-index Search)

一个索引可以含有一个或者多个主分片,因此针对一个索引的搜索请求须要对来自多个分片的搜索结果进行合并。一个针对多个或者全部索引的搜索请求也以同样的方式工作 - 仅仅是很多其它的分片会參与到这个过程中。

获取阶段(Fetch Phase)

查询阶段可以辨识出哪些文档可以匹配搜索请求,可是我们还须要获取文档本身。这就是获取阶段完毕的工作。此阶段例如以下图所看到的:

  1. 协调节点(Coordinating Node)会首先辨识出哪些文档须要被获取,然后发出一个multi GET请求到相关的分片。
  2. 每一个分片会读取相关文档并依据要求对它们进行润色(Enrich),最后将它们返回给协调节点。
  3. 一旦全部的文档都被获取了,协调节点会将结果返回给client。

协调节点首先决定究竟哪些文档是真的须要被获取的。比方,假设在查询中指定了{ "from": 90, "size": 10 },那么头90条结果都会被丢弃(Discarded),仅仅有剩下的10条结果所代表的文档须要被获取。这些文档可能来自一个或者多个分片。

协调节点会为每一个含有目标文档的分片构造一个multi GET请求,然后将该请求发送给在查询阶段中參与过的分片拷贝。

分片会载入文档的正文部分 - 即_source字段 - 假设被要求的话,还会对结果进行润色,比方元数据和搜索片段高亮(Search
Snippet Highlighting)
。一旦协调节点获取到了全部的结果,它就会将它们组装成一个响应并返回给client。

深度分页(Deep Pagination)

查询并获取(Query then Fetch)的过程支持通过传入的fromsize參数来完毕分页功能。可是该功能存在限制。不要忘了每一个分片都会在本地保存一个大小为from
+ size
的优先队列,该优先队列中的全部内容都须要被返回给协调节点。然后协调节点须要对number_of_shards * (from + size)份文档进行排序来保证最后可以得到正确的size份文档。

依据文档的大小,分片的数量以及你正在使用的硬件,对10000到50000个结果进行分页(1000到5000页)是能够非常好地完毕的。可是当from值大的一定程度,排序就会变成非常消耗CPU,内存和带宽等资源的行为。由于如此,我们强烈地建议你不要使用深度分页。

实践中,深度分页返回的页数实际上是不切实际的。用户往往会在浏览了2到3页后就会改动他们的搜索条件。罪魁祸首往往都是网络爬虫这样的无休止地页面进行抓取的程序,它们会让你的server不堪重负。

假设你确实须要从集群中获取大量的文档,那么你能够使用禁用了排序功能的scan搜索类型来高效地完毕该任务。我们会在稍后的Scan和Scroll一节中进行讨论。

搜索选项(Search Options)

有一些搜索字符串參数可以影响搜索过程:

preference

该參数可以让你控制哪些分片或者节点会用来处理搜索请求。它可以接受:_primary_primary_first_local_only_node:xyz_prefer_node:xyz以及_shards:2,3这种值。这些值的含义在搜索preference的文档中有详解。

可是,最经常使用的值是某些随意的字符串,用来避免结果跳跃问题(Bouncing Result Problem)。

结果跳跃(Bouncing Results)

比方当你使用一个timestamp字段对结果进行排序,有两份文档拥有同样的timestamp。由于搜索请求是以一种循环(Round-robin)的方式被可用的分片拷贝进行处理的,因此这两份文档的返回顺序可能由于处理的分片不一样而不同,比方主分片处理的顺序和副本分片处理的顺序就可能不一样。

这就是结果跳跃问题:每次用户刷新页面都会发现结果的顺序不一样。

这个问题能够通过总是为相同用户指定相同的分片来避免:将preference參数设置为一个随意的字符串,比方用户的会话ID(Session
ID)。

timeout

默认情况下,协调节点会等待全部分片的响应。假设一个节点有麻烦了,那么会让全部搜索请求的响应速度变慢。

timeout參数告诉协调节点它在放弃前要等待多长时间。假设放弃了,它会直接返回当前已经有的结果。返回一部分结果至少比什么都不返回要强。

在搜索请求的响应中,实用来表明搜索是否发生了超时的字段,同一时候也有多少分片成功响应的字段:

...
    "timed_out":     true,
    "_shards": {
       "total":      5,
       "successful": 4,
       "failed":     1
    },
...

routing

在分布式文档存储(Distributed Document Store)一章中的路由文档到分片(Routing a document to a shard)一小节中,我们已经解释了自己定义的routing參数能够在索引时被提供,来确保全部相关的文档,比方属于同一用户的文档,都会被保存在一个分片上。在搜索时,相比搜索索引中的全部分片,你能够指定一个或者多个routing值来限制搜索的范围到特定的分片上:

GET /_search?routing=user_1,user2

该技术在设计很大型的搜索系统实用处,在Designing for scale中我们会具体介绍。

search_type

除了query_then_fetch是默认的搜索类型外,还有其它的搜索类型能够满足特定的目的,比方:

GET /_search?search_type=count

count

count搜索类型仅仅有查询阶段。当你不须要搜索结果的时候能够使用它,它仅仅会返回匹配的文档数量或者聚合(Aggregation)结果。

query_and_fetch

query_and_fetch搜索类型会将查询阶段和获取阶段合并成一个阶段。当搜索请求的目标仅仅有一个分片时被使用,比方指定了routing值时,是一种内部的优化措施。虽然你能够选择使用该搜索类型,可是这样做差点儿是没实用处的。

dfs_query_then_fetch和dfs_query_and_fetch

dfs搜索类型有一个查询前阶段(Pre-query phase)用来从相关分片中获取到词条频度(Term Frequencies)来计算群安居的词条频度。我们会在相关性错了(Relevance
is broken)
一节中进行讨论。

scan

scan搜索类型会和scroll API一起使用来高效的获取大量的结果。它通过禁用排序来完毕。在下一小节中会进行讨论。

scan和scroll

scan搜索类型以及scroll API会被一同使用来从ES中高效地获取大量的文档,而不会有深度分页(Deep
Pagination)中存在的问题。

scroll

一个滚动(Scroll)搜索可以让我们指定一个初始搜索(Initial Search),然后继续从ES中获取批量的结果,直到全部的结果都被获取。这有点像传统数据库中的游标(Cursor)。

一个滚动搜索会生成一个实时快照(Snapshot) - 它不会发如今初始搜索后,索引发生的不论什么变化。它通过将老的数据文件保存起来来完毕这一点,因此它可以保存一个在它開始时索引的视图(View)。

scan

在深度分页中最耗费资源的部分是对全局结果进行排序,可是假设我们禁用了排序功能的话,就能够高速地返回全部文档了。我们能够使用scan搜索类型来完毕。它告诉ES不要运行排序,仅仅是让每一个还有结果能够返回的分片返回下一批结果。



为了使用scan和scroll,我们将搜索类型设置为scan,同一时候传入一个scroll參数来告诉ES,scroll会开放多长时间:

GET /old_index/_search?search_type=scan&scroll=1m
{
    "query": { "match_all": {}},
    "size":  1000
}

以上请求会让scroll开放一分钟。

此请求的响应不会含有不论什么的结果,可是它会含有一个_scroll_id,它是一个通过Base64编码的字符串。如今能够通过将_scroll_id发送到_search/scroll来获取第一批结果:

GET /_search/scroll?scroll=1m
c2Nhbjs1OzExODpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExOTpRNV9aY1VyUVM4U0
NMd2pjWlJ3YWlBOzExNjpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExNzpRNV9aY1Vy
UVM4U0NMd2pjWlJ3YWlBOzEyMDpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzE7dG90YW
xfaGl0czoxOw==

该请求会让scroll继续开放1分钟。_scroll_id可以通过请求的正文部分,URL或者查询參数传入。

注意我们重新指定了?scroll=1m。scroll的过期时间在每次运行scroll请求后都会被刷新,因此它仅仅须要给我们足够的时间来处理当前这一批结果,而不是匹配的全部文档。

这个scroll请求的响应包括了第一批结果。虽然我们指定了size为1000,我们实际上可以获取很多其它的文档。size会被每一个分片使用,因此每批最多可以获取到size
* number_of_primary_shards
份文档。

NOTE

scroll请求还会返回一个新的_scroll_id。每次我们运行下一个scroll请求时,都须要传入上一个scroll请求返回的_scroll_id

当没有结果被返回是,我们就处理完了全部匹配的文档。

TIP

一些ES官方提供的client提供了scan和scroll的工具用来封装这个功能。

时间: 2024-11-06 12:25:11

[Elasticsearch] 分布式搜索的相关文章

elasticsearch分布式搜索配置文件详解

Elasticsearch是一个开源的分布式实时搜索与分析引擎,支持云服务.它是基于Apache Lucene搜索引擎的类库创建的,提供了全文搜索能力.多语言支持.专门的查询语言.支持地理位置服务.基于上下文的搜索建议.自动完成以及搜索片段(snippet)的能力.Elasticsearch支持RESTful的API,可以使用JSON通过HTTP调用它的各种功能,包括搜索.分析与监控.下面是讲述了elasticsearch分布式搜索配置文件各类参数的具体含义. elasticsearch的con

Elasticsearch分布式搜索

ElasticSearch之介绍 一 Elasticsearch产生背景 1.1 大规模数据如何检索 如:当系统数据量上了10亿.100亿条的时候,我们在做系统架构的时候通常会从以下角度去考虑问题:1)用什么数据库好?(mysql.oracle.mongodb.hbase…)2)如何解决单点故障:(lvs.F5.A10.Zookeep.MQ)3)如何保证数据安全性:(热备.冷备.异地多活)4)如何解决检索难题:(数据库代理中间件:mysql-proxy.Cobar.MaxScale等;)5)如何

[转]分布式搜索elasticsearch几个概念解析

Document 在Elasticsearch世界(或者Lucene世界中),Document是主要的实体,文档这个单词有特殊的含义.它指的是在Elasticsearch中被存储到唯一ID下的由最高级或者根对象 (root object )序列化而来的JSON.Elasticsearch的documents最终被存储为Lucene documents. 文档元数据 一个文档不只包含了数据.它还包含了元数据(metadata) —— 关于文档的信息.有三个元数据元素是必须存在的,它们是: 名字 说

ElasticSearch(8)-分布式搜索

分布式搜索的执行方式 在继续之前,我们将绕道讲一下搜索是如何在分布式环境中执行的. 它比我们之前讲的基础的增删改查(create-read-update-delete ,CRUD)请求要复杂一些. 注意: 本章的信息只是出于兴趣阅读,使用Elasticsearch并不需要理解和记住这里的所有细节. 阅读这一章只是增加对系统如何工作的了解,并让你知道这些信息以备以后参考,所以别淹没在细节里. 一个CRUD操作只处理一个单独的文档.文档的唯一性由_index, _type和routing-value

分布式搜索elasticsearch 基本概念

ElasticSearch官网:http://www.elasticsearch.org/ 先上一张elasticsearch的整体框架图: ElasticSearch是基于Lucene开发的分布式搜索框架,包括例如以下特性: 分布式索引.搜索 索引自己主动分片.负载均衡 自己主动发现机器.组建集群 支持Restful 风格接口 配置简单等. 下图是ElasticSearch的第三方插件管理工具.通过它能够非常清晰的看到它索引分布的情况:哪块分布在那里,占用空间多少都能够看到.而且能够管理索引.

分布式搜索elasticsearch几个概念解析

介绍下es的几个概念: cluster代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的.es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的. shards代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上.构成分布式搜索.分片的数量只能在索引创建前指定,

ELK介绍及搭建 Elasticsearch 分布式集群

笔记内容:ELK介绍及搭建 Elasticsearch 分布式集群笔记日期:2018-03-02 27.1 ELK介绍 27.2 ELK安装准备工作 27.3 安装es 27.4 配置es 27.5 curl查看es集群情况 ELK介绍 需求背景: 业务发展越来越庞大,服务器越来越多 各种访问日志.应用日志.错误日志量越来越多,导致运维人员无法很好的去管理日志 开发人员排查问题,需要到服务器上查日志,不方便 运营人员需要一些数据,需要我们运维到服务器上分析日志 为什么要用到ELK: 一般我们需要

Elasticsearch7-分布式及分布式搜索机制

分布式特性 Elasticsearch的分布式带来的好处: 存储的水平扩容 提供系统的可用性,部分节点停止服务,整个集群不受影响 Elasticsearch的分布式架构 不同集群通过不同集群名称区分,默认"elasticsearch" 通过配置文件修改,或者在命令行中-E cluster.name="ops-es"进行设定 节点 节点是一个Elasticsearch实例: 本质上就是一个JAVA进程 一台机器上可以运行多个Elasticsearch进程,但是生产环境

lucene之排序、设置权重、优化、分布式搜索(转)

lucene之排序.设置权重.优化.分布式搜索(转) 1. 基本应用 using System;using System.Collections.Generic;using System.Text;using Lucene.Net;using Lucene.Net.Analysis;using Lucene.Net.Analysis.Standard;using Lucene.Net.Documents;using Lucene.Net.Index;using Lucene.Net.QueryP