D 的个人博客

全职做开源,自由职业者

  menu

全文搜索之 Elasticsearch

概述

Elasticsearch (ES)是一个基于 Lucene 的开源搜索引擎,它不但稳定、可靠、快速,而且也具有良好的水平扩展能力,是专门为分布式环境设计的。

特性

  • 安装方便:没有其他依赖,下载后安装非常方便;只用修改几个参数就可以搭建起来一个集群
  • JSON:输入/输出格式为 JSON,意味着不需要定义 Schema,快捷方便
  • RESTful:基本所有操作(索引、查询、甚至是配置)都可以通过 HTTP 接口进行
  • 分布式:节点对外表现对等(每个节点都可以用来做入口);加入节点自动均衡
  • 多租户:可根据不同的用途分索引;可以同时操作多个索引

集群

其中一个节点就是一个 ES 进程,多个节点组成一个集群。一般每个节点都运行在不同的操作系统上,配置好集群相关参数后 ES 会自动组成集群(节点发现方式也可以配置)。集群内部通过 ES 的选主算法选出主节点(目前版本 1.2 存在脑裂问题),而集群外部则是可以通过任何节点进行操作,无主从节点之分(对外表现对等/去中心化,有利于客户端编程,例如故障重连)。

索引

“索引”有两个意思:

  • 作为动词,它指的是把一个文档“保存”到 ES 中的过程,索引一个文档后,我们就可以使用 ES 搜索到这个文档
  • 作为名词,它是指保存文档的地方,相当于一个数据库概念中的“库”

为了方便理解,我们可以将 ES 中的一些概念对应到我们熟悉的关系型数据库上:

    ES         索引         类型         文档    
    DB         库          表     行

分片

ES 是一个分布式系统,我们一开始就应该以集群的方式来使用它。它保存索引时会选择适合的“分片”(Primary Shard),把索引保存到其中(我们可以把分片理解为一块物理存储区域)。分片的分法是固定的,而且是安装时候就必须要决定好的(默认是 5),后面就不能改变了。

既然有主分片,那肯定是有“从”分片的,在 ES 里称之为“副本分片”(Replica Shard)。副本分片主要有两个作用:

  • 高可用:某分片节点挂了的话可走其他副本分片节点,节点恢复后上面的分片数据可通过其他节点恢复
  • 负载均衡:ES 会自动根据负载情况控制搜索路由,副本分片可以将负载均摊

一个示例

来个示例总结一下上面的内容(结合下面的图一起看):

  • 3 个 ES 节点(es-58/59/60)组成一个集群
  • 搭建集群时使用默认的主分片数 5,shard0~shard4
  • 该集群内有加入两个索引 index1、index2
  • 这两个索引中分别“索引”(保存)了两个文档
  • index1 索引中这个文档被 ES 自动保存到了分片 2 中,主分片在 es-58 节点,副本分片在 es-59 节点
  • index2 索引中这个文档被 ES 自动保存到了分片 2 中,主分片在 es-59 节点,副本分片在 es-58 节点

shards

(该图是使用 ES 的 RESTful 接口获取的,后面会介绍常用接口)

多租户

ES 的多租户简单的说就是通过多索引机制同时提供给多种业务使用,每种业务使用一个索引(关于多租户的详细定义与用途,可以参考这里)。前面我们提到过可以把索引理解为关系型数据库里的库,那多索引可以理解为一个数据库系统建立多个库给不同的业务使用。

在实际使用时,我们可以通过每个租户一个索引的方式将他们的数据进行隔离,并且每个索引是可以单独配置参数的(可对特定租户进行调优),这在典型的多租户场景下非常有用:例如我们的一个多租户应用需要提供搜索支持,这时可以通过 ES 根据租户建立索引,这样每个租户就可以在自己的索引下搜索相关内容了。

RESTful

这个特性非常方便,最关键的是 ES 的 HTTP 接口不只是可以进行业务操作(索引/搜索),还可以进行配置,甚至是关闭 ES 集群。下面我们介绍几个很常用的接口:

  •  /_cat/nodes?v:查集群状态
  • /_cat/shards?v:查看分片状态
  • /${index}/${type}/_search:搜索

v 是 verbose 的意思,这样可以更可读(有表头,有对齐),_cat 是监测相关的 APIs,/_cat?help 来获取所有接口。${index} 和 ${type} 分别是具体的某一索引某一类型,是分层次的。我们也可以直接在所有索引所有类型上进行搜索:/_search。

官方术语表

最后,来份官方的术语表翻译,巩固一下理解:

analysis 分析

分析是将文本(text)转化为查询词(term)的过程。使用不同的分析器,这三种短语:FOO BAR,Foo-Bar,foo,bar 都有可能被分解成查询词 foo 与 bar。这些查询词实际上将被存储在索引中。一次对 FoO:bAR 的全文查询(不是查询词查询)可能会被分析为为查询词 foo,bar,可以匹配上保存在索引中的查询词。这就是分析处理过程(包含了索引与搜索),它使得 es 可以进行全文查询。

cluster 集群

一个或多个拥有同一个集群名称的节点组成了一个集群。每个集群都会自动选出一个主节点,如果该主节点故障,则集群会自动选出新的主节点来替换故障节点。

document 文档

一个文档就是一个保存在 es 中的 JSON 文本,可以把它理解为关系型数据库表中的一行。每个文档都是保存在索引中的,拥有一种类型和 id。一个文档是一个 JSON 对象(一些语言中的 hash / hashmap / associative array)包含了 0 或多个字段(键值对)。原始的 JSON 文本在索引后将被保存在 _source 字段里,搜索完成后返回值中默认是包含该字段的。

id

Id 是用于标识文档的,一个文档的索引/类型/id 必须是唯一的。文档 id 是自动生成的(如果不指定)。

field 字段

一个文档包含了若干字段,或称之为键值对。字段的值可以是简单(标量)值(例如字符串、整型、日期),也可以是嵌套结构,例如数组或对象。一个字段类似于关系型数据库表中的一列。每个字段的映射都有一个字段类型(不要和文档类型搞混了),它描述了这个字段可以保存的值类型,例如整型、字符串、对象。映射还可以让我们定义一个字段的值如何进行分析。

index 索引

一个索引类似关系型数据库中的一个数据库,它可以映射为多种类型。一个索引就是逻辑上的一个命名空间,对应到 1 或多个主分片上,可以拥有 0 个或多个副本分片。

mapping 映射

一个映射类似于关系型数据库中的模式定义。每个索引都存在一个映射,它定义了该索引中的每一种类型,以及索引相关的配置。映射可以显示定义,或者在文档被索引时自动创建。

node 节点

一个节点是集群中的一个 es 运行实例。测试时,多个节点可以同时启在同一个服务器上,生产环境一般是一个服务器上一个节点。节点启动时将使用单播(或者是组播)来发现和自己配置的集群名称相同的集群,并尝试加入到该集群中。

primary shard 主分片

每个文档都会被保存在一个主分片上。当我们索引一个文档时,它将在一个主分片上进行索引,然后才放到该主分片的各副本分片上。默认情况下,一个索引有 5 个主分片。我们可以指定更少或更多的主分片来伸缩索引可处理的文档数。需要注意的是,一旦索引创建,就不能修改主分片个数。

replica shard 副本分片

每个主分片可以拥有 0 个或多个副本分片。一个副本分片是主分片的一份拷贝,这样做有两个主要原因:

  1. 故障转移:当主分片失效时,一个副本分片会被提升为主分片
  2. 提高性能:获取与搜索请求可以被主分片或副本分片处理。默认情况下,每个主分片都有一个副本分片,副本分片的数量可以动态调整。在同一个节点上,副本分片和其主分片不会同时运行

routing 路由

当我们索引一个文档时,它将被保存在一个主分片上,分片的选择是通过路由值哈希得到的。默认情况下,路由值来自于文档 id,如果该文档指定来了父文档,则路由值来自于父文档 id(这是为了确保子文档和父文档被保存在相同的分片上)。该值可以在索引时指定,也可以通过映射路由字段来指定。

shard 分片

一个分片就是一个 Lucene 实例,它是 es 管理的底层“工作单元”。一个索引是逻辑上的一个命名空间,指向主分片和副本分片。索引的主分片和副本分片数量必须明确指定好,在应用代码使用时只需要处理和索引的交互,不会涉及到和分片的交互。Elasticsearch 会在集群中的所有节点上设置好分片,但节点失效或加入新节点时会自动将移动节点分片。

source field 源字段

默认情况下,在获取和搜索请求返回值中的 _source 字段保存了源 JSON 文本,这使得我们可以直接在返回结果中访问源数据,而不需要根据 id 再发一次检索请求。注意:索引的 JSON 字符串将完整返回,无论是否是一个合法的 JSON。该字段的内容也不会描述数据如何被索引。

term 查询词

一个查询词是一个被 es 索引的确切值。查询词 foo,Foo,FOO 是不同的。查询词可以使用查询词查询接口进行获取。

text 文本

文本(或称之为全文)是普通的、非结构化的文本,例如本段话。默认情况下,文本将被分析为查询词,查询词将被保存在索引中。为能够进行全文搜索,文本字段在索引时将被分析为查询词,查询关键字在搜索时也将被分析为查询词,通过对比查询词是否相同而完成全文搜索。

type 类型

一种类型类似于关系型数据库中的一张表。每种类型都有若干字段,可以用于指定给该类型文档。映射定义了该文档中的每个字段如何进行分析。

参考