一、前言
(知识搬运工
走近 ElasticSearch (一)——基本概念与架构设计
走近 ElasticSearch (二)——Document概念、倒排索引原理与分词
走近 ElasticSearch (三)——Mapping设计与Search API 介绍
二、Document 介绍
1. Document 数据类型
Json Object,由字段(Field)组成,常见数据类型如下:
- 字符串: text, keyword
- 数值型: long, integer, shot, byte, double, float,haf_float, scaled_float
- 布尔: boolean
- 日期: date
- 二进制: binary
- 范围类型: integer_range, float_range, long_range, double_range, date_range, ip_range
- 还有其他数据类型:
- 嵌套类型: nested
- 对象类型: object
- 数组类型: Array
- 地理类型: geo_point, geo_shape
- 自动补全类型: completion
- 多字段特性:multi-fields
2. Document 创建
每个文档有唯一的 id 标示。两种方式:自行指定;es自动生成
以es自动生成索引为例:
文档元数据解释:
- _index: 文档所在的索引名
- _type: 文档所在的类型名
- _id: 文档唯一id
- _uid: 组合 id, 由 _type 和 _id 组成(6.x _type 不再起作用, 同_id一样)
- _source: 文档的原始 Json 数据,可以从这里获取每个字段的内容
- _all: 整合所有字段内容到该字段,默认禁用
注意:创建文档时,如果索引不存在,es 会自动创建对应的 index 和 type。建议在创建索引时,定义 mapping。
使用 POST _bulk
一次创建多个文档,从而减少网络传输开销,提升写入速率
3. Document 查询
指定要查询的文档id
搜索索引文档,用到_search
:
三、倒排索引与分词
1. 倒排索引
1.1 概念
倒排索引是搜索引擎到核心,主要包括两部分:
- 单词词典(Term Dictionary)
- 记录所有文档的单词,一般都比较大
- 记录单词到倒排列表的关联信息(文档ID)
- 倒排列表(Posting List):
- 记录了单词对应的文档集合,由倒排索引项(Posting)组成
单词词典的实现一般是 B+ Tree:
倒排索引项(Posting)主要包含如下信息:
- 文档Id,用于获取原始信息
- 单词频率(TF, Term Frequency),记录该单词在该文档中的出现次数,用于后续相关性算法
- 位置(Position),记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query)
- 偏移(Offset),记录单词在文档的开始和结束位置,用于做高亮显示
1.2 索引的位置与粒度
倒排索引的位置:
Cluster->Node->Shard->segment->Index
为了优化搜索,segment不仅只提供了倒排,还提供了document values field cache 解决:排序、聚合等问题
对于索引的构建粒度,是按照字段来构建的,即:每个字段会有自己的倒排索引,类似下图:
1.3 ES集群中操作索引过程
ES引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,建立起 分词 (Term)—> 文档(Document) 映射关系。
然后这些倒排索引会存放在段(segment)中,段的写入会落盘,缓存buffer会实时更新。
具体的操作可分为写操作、读操作、更新操作:
- 写操作: 写操作必须在primary shard完全成功后才能拷贝至其对应的replicas上,默认情况下主分片。等待所有备份完成索引后才返回客户端。
1、客户端向Node1 发送索引文档请求
2、Node1 根据文档ID(_id字段)计算出该文档应该属于shard0,然后请求路由到Node3的P0分片上
3、Node3在P0上执行了请求。如果请求成功,则将请求并行的路由至Node1,Node2的R0上。当所有的Replicas报告成功后,Node3向请求的Node(Node1)发送成功报告,Node1再报告至Client。
当客户端收到执行成功后,操作已经在Primary shard和所有的replica shards上执行成功了 - 读操作: 一个文档可以在primary shard和所有的replica shard上读取
1.客户端发送Get请求到NODE1。
2.NODE1根据文档ID(_id字段)计算出该文档应该属于shard0,且shard 0的所有拷贝存在于所有3个节点上。这次,它将请求路由至NODE2。
3.NODE2将文档返回给NODE1,NODE1将文档返回给客户端。 对于读请求,请求节点(NODE1)将在每次请求到来时都选择一个不同的replica shard来达到负载均衡。使用轮询策略轮询所有的replica shards。 - 更新操作,结合了以上的两个操作:读、写
1.客户端发送更新操作请求至NODE1
2.NODE1将请求路由至NODE3,Primary shard所在的位置
3.NODE3从P0读取文档,改变source字段的JSON内容,然后试图重新对修改后的数据在P0做索引。如果此时这个文档已经被其他的进程修改了,那么它将重新执行3步骤,这个过程如果超过了retryon_conflict设置的次数,就放弃。
4.如果NODE3成功更新了文档,它将并行的将新版本的文档同步到NODE1和NODE2的replica shards重新建立索引。一旦所有的replica shards报告成功,NODE3向被请求的节点(NODE1)返回成功,然后NODE1向客户端返回成功。
2. 分词
分词是指将文本转换成一系列单词(term or token)的过程,也可以叫做文本分析,在 es 里面成为 Analysis,如下图所示:
2.1 分词器组成
分词器是 es 中专门处理分词的组建,英文为 Analyzer,它的组成如下:
- Character Filters:针对原始文本进行处理,比如去除 html 特殊标记符
- Tokenizer:将原始文本按照一定规则切分为单词
- Token Filters:针对 tokenizer 处理的单词再加工,比如转小写,删除或新增等处理
分词器调用顺序:
2.2 调参:测试我们配置的分词器
es 提供了一个测试分词的 api 接口,方便验证分词效果,endpoint 是 _analyze。
对此我们可以使用三种方式进行测试:
- 直接指定 analyzer 进行测试,接口如下:
- 直接指定索引中的字段进行测试,接口如下:
- 自定义分词器进行测试,接口如下:
2.3 分词器种类
es自带如下的分词器:Standard、Simple、Whitespace、Stop、Keyword(不分词,直接将输入作为一个单词输出)、Pattern、Language
常用中文分词器:
- ik(下载地址)
- 可自定义词库,支持热更新分词词典
- jieba(下载地址)
- 支持繁体分词、自定义词典、并行分词等。python 中最流行的分词系统,支持分词和词性标注
基于自然语言处理的分词系统
- 支持繁体分词、自定义词典、并行分词等。python 中最流行的分词系统,支持分词和词性标注
- Hanlp:由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生成环境中的应用
- THULAC:清华大学自然语言处理实验室推出的一套中文词法分析工具包,具有中文分词和词性标注功能
2.4 分词器使用说明
分词会在如下两个时机使用:
- 创建或更新文档时(Index Time),会对相应的文档进行分词处理
- 查询时(Search Time),会对查询语句进行分词
对于创建或更新索引:我们可以通过配置 Index Mapping 中每个字段的 analyzer 属性实现指定分词器(默认 standar 分词器);
对于查询时分词,通过 index mapping 设置 search_analyzer 实现