Analysis is the process of converting text, like the body of any email, into tokens or terms which are added to the inverted index for searching. Analysis is performed by an analyzer which can be either a built-in analyzer or a custom analyzer defined per index.
Analysis分析是指将文本(如邮件正文)转换成token或term的过程,token或term会被添加到倒排索引中用于搜索。分析是通过每个索引中定义的内置分析器Analyzer或用户自定义分析器实现。
一、ElasticSearch概要
1.1 什么是ElasticSearch
ElasticSearch基于全文搜索引擎库Lucene开发,提供了一套RESTful风格的API接口,天生支持分布式特性,易于扩展,不论是结构化还是非结构化数据,都可以提供近实时的搜索和分析功能。
1.2 核心概念
1.2.1 对比MySQL数据库
1.2.2 文档——Document
文档是索引中的基本单元,文档中采用JSON格式存储。一个文档包含多个Field字段,每个字段都有一个名称和值(键值对),Mapping映射中负责定义Field的类型及索引方式。文档类似于数据库表中的一条记录,记录中包含多个字段,ES文档中包含多个索引字段Field。
1.2.3 索引——Index
索引是具有相似特征的文档集合,创建索引时,ES要求索引名称必须为英文小写。索引作为动词,表示创建索引这个操作,作为名词时,表示索引。ES中的索引可以类比成数据库中的库,每一个数据库都会有不同的表,表中会定义Schema,而ES索引中可以包含不同的Type(ES6.X后只支持单个Type,ES7.X后将不支持Type),Type中会定义Mapping映射,用于指定不同字段的类型。
1.2.4 类型——Type
Type即Mapping Type,类似于数据库中的schema,在ES6.X之前版本支持多个Type,但是不利于维护,数据稀疏问题严重,6.X开始只支持单个Type。
1.2.5 集群——Cluster
集群由一个或者多个ES节点组成,整个集群负责存储数据、提供索引和搜索数据的功能。同一个网络中,具有相同cluster.name的节点会自动加入集群,因此不同环境的cluster.name需要进行区分,防止加入错误的集群。
测试环境ES集群,集群名称f6-search-local,包含了s1和s2两个节点。索引内的数据被拆分为5份,即5个分片Shard,每个分片有一个备份数据——副本Replica。
集群是否正常运行可以通过健康状态反映,通过GET /_cat/health?v查看status,包括green、yellow、red三种状态。
green
:每个索引的primary shard和replica shard都是active状态的;yellow
:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态;red
:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了;1.2.6 节点——Node
每一个ES实例都是集群中的一个节点,节点名称默认是一串随机的UUID字符串,集群中通过node.name唯一标识一个节点,可以在elasticsearch.yml配置节点的名称。节点具体地负责索引数据的创建和存储,处理前端搜索请求。
根据节点的不同职责,可以划分为以下几种类型:
1.2.7 主分片——Shards
单个节点,当存储大量文档时,很容易超过单机限制。为了解决这个问题,ElasticSearch采用分片来切割索引中的数据,在创建索引时可以指定分片数,默认为5分片。每个分片都是一个功能完备的Lucene索引,ES中的索引是一个逻辑索引。分片机制为ES提供了扩展性,多个分片提供了并行处理请求的能力,能有效提高系统吞吐量。
1.2.8 副本分片——Replicas
副本机制通过冗余分片数据(主分片和副本分片不允许分配在一个节点上),保证系统中某个节点宕机时,系统的高可用。同时,增加的副本分片,能够有效提高查询的性能和吞吐量。创建索引时,默认副本分片数为1。
1.2.9 近实时——Near Realtime
NRT即Near Realtime,ES是一个近实时的搜索平台,从索引一个文档到文档能够被搜索出来,有短暂延迟,通常为1s。
1.3.0 集群、节点、主分片和副本分片的关系
集群(Cluster)、节点(Node)、主分片(Primary Shard)和副本分片(Replica Shard)的关系如上图,上图集群由四个节点node1、node2、node3和node4组成,每一个节点中,分配了不同数量的分片,绿色节点为主分片(Primary Shard),白色节点为副本分片(Replica Shard)。 索引(Index)由一个或多个主分片组成,每个主分片负责存储部分索引数据。副本分片是主分片的拷贝,用于保证系统高可用,提升系统吞吐量。索引查询时,可以通过所有分片(包括主分片和副本分片)进行,而索引创建、删除、更新时,只能通过主分片进行,然后再同步到副本分片。为了保证高可用,主分片和副本分片不允许存储在同一个节点上,当主分片所在节点宕机时,副本分片会被提升为主分片,处理索引的写操作。
二、Mapping
2.1 什么是Mapping
Mapping映射用于定义索引中的Document,以及其中包含了哪些字段Field,这些字段是如何被索引(Index)和存储的(Stored)。
每个索引中包含一个Mapping Type,它决定了文档是如何索引的。Mapping Type中包含了两种类型的字段,一种是元字段,一种是用户自定义字段。元字段(Meta Fields)用于描述文档自身的信息,包括_index, _type, _id(这三个属性唯一指向一条文档)和_source(存储文档原始数据,用于数据查询和更新)。
已经存在的字段类型不允许进行修改,因为改变现有字段数据类型,意味着已有数据全部要失效。通常,都是重新创建一个索引,然后reindex数据,或者增加新的字段替代原有字段。新版本中,允许给字段设置别名来进行更新查询操作,字段类型更新时,可以添加新的字段,然后修改mapping中的别名类型,指向新添加的字段。
通常,一个mapping定义如下:
2.2 Mapping参数
dynamic参数——控制mapping动态添加字段。
type参数——定义字段类型,包含了以下数据类型,其中text类型也被称为全文本类型,会进行分词处理,然后再建立倒排索引。keyword、long、integer等类型都是精确类型,查询时会精确匹配。
index参数——决定字段是否索引,默认为true,text类型字段使用倒排索引存储,数值和地理类型使用BKD Tree存储。
doc_values参数——用于字段排序和聚合操作,默认为true,不支持text字段。
fields参数——同一个字段使用不同的方式进行索引,从而满足不同的使用场景。例如要对customCode字段进行排序,但是因为搜索时需要支持模糊查询,已经进行了ngram分词处理,直接对分词结果进行排序,毫无意义。这时可以通过fileds可以定义一个keyword类型,对原字段内容进行排序。
三、Analysis分析
3.1 什么是Analysis
Analysis分析过程是通过分析器Analyzer实现的,分析器Analyzer负责将文本解析成term,进而存储到倒排索引中。搜索时会采用同样的分析器,对原始的搜索文本进行分析,然后匹配到相应的文档。ES中提供了内置的分析器,也提供了自定义分析器的方式,可以对现有分析器中的功能进行组合。 分析器analyzer包好了三个模块:
3.2 常用Analyzer分析器及效果
3.2.1 Standard分析器
standard分析器是ES的默认分析器,根据字符边界(英文根据空格,汉字根据单字)拆分,对于类似英语的语言效果较好,对汉语分词效果比较差,测试效果如下:
3.2.2 IK分析器
IK分词器是一款著名的中文分词器,用户可以配置词库来达到很好的分词效果,ES的IK插件提供了
ik_smart
和ik_max_word
分析器,同时也提供了ik_smart
和ik_max_word
的分词器Tokenizer,用户可以引用,然后自定义自己的Analyzer分析器。ik_smart分析器效果:
ik_max_word分析器效果:
3.2.3 pinyin分析器
pinyin分析器插件提供了
pinyin
分析器、pinyin
分词器以及一个语汇单元过滤器token-filterpinyin
。pinyin分析器效果如下:
3.2.4 自定义分析器
实际使用中,对于分词的场景多种多样,有的需要使用拼音分词品牌,有的需要使用ik中文分词匹配,有的字段需要实现类似于like的模糊搜索,所以我们需要自定义分析器来满足各种场景。 如下的语句中,定义了三个自定义分析器:
四、常用API
4.1 index api
添加文档到索引,PUT操作为创建文档,默认操作类似于put-if-absent,不存在时则创建,存在时则更新(文档覆盖更新):
如果想实现只创建文档,存在了不覆盖更新,可以使用op_type=create参数进行控制,已存在文档则会报错。
上面的示例中,我们都指定了index、type和id,其实ES也可以实现自动生成ID的操作(使用POST请求),但是实际中会使用业务ID:
4.2 delete api
删除操作比较简单,使用DELETE请求,指定好index、type和id即可(文档删除后不会立刻被清除,ES会在合适的时机执行段合并操作,合并之后才会真正删除文档:
4.3 update api
使用index api可以更新文档,但是是覆盖更新,实际使用场景中,需要更新用户传入的更新字段,其他字段保持不变,这个时候就需要使用update api。 第一种方式是脚本更新,更新之前文档中的用户字段(painless脚本功能强大,可以实现一些动态功能,但是注意性能消耗,不推荐使用):
第二种方式是使用局部更新:
但是有时候想要实现upsert操作——存在则更新部分字段,不存在则插入,则需要添加doc_as_upsert参数:
4.4 get api
get api用于根据index、type、id查询某个文档,使用较少:
4.5 bulk api
bulk api支持批量执行多个操作,每个操作包含两行,格式如下,第一行声明操作类型,指定对应的元数据,第二行传入请求体,delete操作没有请求体,格式如下:
action代表操作类型,包含以下几种:
create
:新增操作,和PUT twitter/_doc/1?op_type=create或PUT twitter/_doc/1/_create作用相同,强制创建,不会更新,存在文档则会报错;delete
:删除操作;index
:和普通的PUT操作相同,不存在则新增,存在则全量替换;update
:局部更新操作;bulk操作中,任意一个操作失败,是不会影响其他的操作的,但是在返回结果里,会告诉你异常日志。
4.6 search api
search api的结构通常如下,是一个match查询语句,既可以匹配全文搜索,也可以匹配精确查询,取决于字段的定义是text还是其他精确字段:
查询语句的含义很容易理解,匹配name字段,匹配的关键词是机油。 查询时会根据字段定义的分析器,进行分词,然后匹配ES倒排索引中的数据,计算文档匹配度,返回结果默认根据匹配程度排序。
复合查询语句:
复合语句查询使用bool语句,可以包含must、must_not、should等子语句,minimum_should_match用于控制should语句中最小需要满足条件的个数。
multi_match查询:
multi_match一次可以匹配多个字段,type属性有六个取值,其中best_fields、most_fields、cross_fields比较常用。
term查询单个值;terms查询多个值
range查询
聚合查询
按字段进行排序【支持多字段排序】