Elasticsearch 入门
1. 安装与准备
安装 es 就是按部就班:
- 查看插件:
./elasticsearch-plugin list
- 安装插件:
./elasticsearch-plugin install xxx
- 部署:
./elasticsearch
- 多节点部署:
1 | ./elasticsearch -E node.name=node1 -E cluster.name=geektime -E path.data=node1_data -d |
- 删除部署的节点:
1 | ps -ef | grep elasticsearch | awk '{print $2}' | xargs kill -9 |
安装一下 Kibana ,端口是 5601 :
- 查看插件
./kibana-plugin list
- 安装插件
./kibana-plugin install xxx
当然也能用 docker 装。
1 | version: '2.2' |
一个 cerebro 0.9.1、一个 kibana 7.7.0、两个 es 7.7.0。
接着是 Logstash ,尝试将 movielens 数据集写入 es ,使用指令:./logstash -f logstash.conf
执行。
需要提前准备数据集。不再继续打印输信息了,就算结束了。logstash 会监听文件,如有变化,会继续更新。
2. 基本概念
ES 是面向文档的,文档被保存成 JSON 格式,每一个文档都有一个 Unique ID。
每一个文档都有『元数据』,
_index
文档索引名,_type
文档所属的类型名,_id
唯一 ID,_source
原始 JSON,_all
整合所有内容(已经废除),_version
文档版本信息,_score
相关性打分。
索引 Index 是文档的容器,表示一类文档的集合。
- Index 提现了逻辑空间的概念。每个索引都有自己的 Mapping ,用于定义包含文档的字段与类型。
- Shard 是物理空间的概念。索引中的数据分散在 Shard 中。
- Mapping 定义字段类型,Setting 定义不同的数据分布。
索引在 es 中也可以给表示动词:索引(动)文档到 es 的索引(名)中。
动词『索引』指保存的意思。
在 7.0 前,一个 Index 可以设置多个 Type ,但是 7.0 开始一个索引只能设置一个 Type _doc
。
与 RDBMS 相比,es 中与之对应的概念:
RDBMS | Elasticsearch |
---|---|
Table | Index(Type) |
Row | Document |
Column | Filed |
Schema | Mapping |
SQL | DSL |
- es 偏向于相关性的全文检索;
- RDBMS 事务性更强。
节点与分片是重要的概念:
- es 不同的集群通过名字来划分,默认为『elasticsearch』。通过
-E cluster.name=xxx
来设置集群名字,一个集群有一个或多个节点。 - 节点是一个 es 的实例,本质上是一个进程,生产环境推荐一台机器一个实例(节点),每个节点都有名字通过
-E node.name=xxx
来设置,每个节点启动后会有一个 UID,保存在 data 目录下。 - 每个节点启动默认是一个『Master-eligible』节点,可以通过设置
node.master: false
禁止,只有 Master 节点可以修改集群的状态信息。- Data Node 是可以保存数据的节点,负责保存分片数据;
- Coordinating Node 负责接收 Client 的请求,将请求分发到合适的节点上,最终将结果聚集返回(每个节点默认都有 Coordinating Node 的职责);
- Hot Node 是配置比较高的节点(一般而言),而 Warm Node 则保存比较旧的数据(一般配置较低);
- Machine Learning Node 负责机器学习的 Job ,用来异常检测;
- Tribe Node 逐渐淘汰,改用 Cross Cluster Search 用于连接不同的集群,将这些集群当做一个集群。
开发环境一个节点可以承担多个角色,生产环境则应该设置单一角色。
1 | master eligible |
- Primary Shard,主分片,解决水平扩展的问题,将数据分布到集群内所有节点上。
- 一个分片是一个 Lucene 实例。
- 主分片数在索引创建时指定,后续不能更改,除非 Reindex。
- Replica Shard,副本,用于解决数据高可用的问题,分片是主分片的拷贝。
- 副本分片可以动态调整。
- 增加副本数,可以在一定程度上提高服务的可用性。
- 主分片如果过小,导致无法增加节点实现水平扩展,同时单个节点数据量过大,数据查询耗时。
- 主分片如果过大,默认是 1 ,将影响搜索结果的相关性打分,同时单个节点上分片过多,会资源浪费,同时影响性能。
集群有健康状况 GET _cluster/health
,Green 都正常,Yellow 主正常部分副本不正常,Red 主不正常。
3. CRUD 与批量操作
Http Method + Index Name + Type + Doc Id。
- Type 约定用
_doc
; - Create 如果 Id 存在,会失败;
- Index 如果 Id 不存在,创建新的文档,否则删除现有文档,再创建新的文档,版本会增加;
- Update 如果文档存在,更新只会对相应字段做增量操作;
3.1 Create
- 通过
post /users/_doc
系统自动生成 Doc Id; - 使用
put user/_create/1
或put users/_doc/1?op_type=create
显式指定 Id ,如果 Id 存在,则失败;- 先执行了自动生成,再执行手动指定的时候,会成功,但是第二次执行会失败(因为自动生成的 Id 是随机的,不会在这里发生冲突)
3.2 Get
- 找到则返回 200
get users/_doc/1
;_version
表示文档经过多少次改动;
- 找不到则 404
3.3 Index
如果文档不存在,就创建新的文档;否则现有文档被删除,再创建新的文档,版本增加。
- 使用
put user/_doc/1
进行操作;
3.4 Update
不会删除原有的文档,而是实现真正的数据更新。
- 使用
post users/_update/1
进行操作; - 在执行时必须指明
doc
;
3.5 Bulk API
- 在一次 API 调用中,对不同的索引进行操作,支持:Index Create Update Delete。
- 单条操作失败不会影响其他结果;最终结果包含每一条操作。
- 以
post _bulk
开始,其中指定各种 Index 。
3.6 批量读取 mget
- 批量操作,用 Id 获得详情,减少网络连接所产生的开销,提高性能。
- 以
get _mget
开始,可以在 URI 中指定 Index,也可以在请求体中说明 Index。
3.7 批量查询 msearch
- 以
post _msearch
开始,API 更加丰富,根据条件进行查询。
429 集群繁忙。
4. 倒排索引
目录是正排索引 Id -> 内容,书的结尾的索引页是倒排索引 内容 -> Id。
倒排索引包括两个部分:
- 单词词典 Term Dictionary,记录所有文档的单词,记录单词到倒排索引的关系,可以用 B+ 树或哈希拉链,满足高性能的插入与查询。
- 倒排列表 Posting List,记录单词对应的文档结合,由倒排索引项组成。倒排索引项包括:
- 文档 Id
- 词频 TF
- 位置,用于语句搜索
- 偏移,单词开始到结束的位置,高亮显示
5. Analyzer 分词
Analysis 文本分析可以把全文文本转化成一系列单词,也就是分词。Analysis 是通过 Analyzer 实现的。
Analyzer 分词器由三个部分组成:Character Filters 针对原始文本进行处理、Tokenizer 根据一定规则进行字符串切分、Token Filters 将切分结果进行二次加工。
- Standard Analyzer - 是默认分词器,按词进行切分,小写处理。
- Simple Analyzer – 按照非字母切分(符号、数字被过滤),小写处理
- Stop Analyzer – 小写处理,停用词过滤(the,a,is)
- Whitespace Analyzer – 按照空格切分,不转小写
- Keyword Analyzer – 不分词,直接将输入当作输出
- Patter Analyzer – 正则表达式,默认 \W+ (非字符分隔)
- Language – 提供了30多种常见语言的分词器
- ICU Analyzer - 中文分词,提供 Unicode 支持,Character Filters 是 Normalization,Tokenizer 是 ICU Tokenizer,Token Filters 是 Normalization + Folding + Collation + Transform。
get /_analyze
指定 Analyzer 进行分词,post xxx/_analyze
指定索引字段进行分词,post /_analyzer
自定义分词器进行分词。
6. Search API 概览
- URI Search
- 在 URL 中使用查询参数。
- 使用 get 方法,在 URL 中使用
q
指定查询字符串,字符串是k:v
形式的键值对。
- Request Body Search
- 使用 es 提供的,基于 JSON 格式的更加完备的 DSL 。
- 使用 get 或 post 方法,在请求体中使用 DSL 。
/_search
查询集群上所有的索引。/index1/_search
查询 index1 索引上的内容。/index1,index2/_search
查询 index1 和 index2 索引上的内容。/index*/_search
匹配 index 开头的索引上的内容。
响应结果中:
- took 花费时间。
- total 符合条件的文档总数。
- hits 结果集,默认前 10 个文档。
另外一个重点在于 score :
- 搜索结果会根据 score 进行排名。
- Precision 查准率 = True Positive / 全部返回的结果
- Recall 查全率 = True Positive / 所有应该返回的结果
- 使用 es 的查询和相关参数可以改善搜索的 Precision 和 Recall 。
7. URI Search 详解
q
查询语句,使用 Query String Syntax。df
默认字段,不指定时,返回所有字段的查询。sort
排序。from
和size
用于分页。- 请求体里的
Profile
查看查询是如何被执行的。 - 指定字段查询
q=title:2012
,范查询则是q=2012
。 - Term vs Phrase
- Beautiful Mind 等效于 Beautiful OR Mind
title:(Beautiful AND Mind)
。 - “Beautiful Mind” 等效于 Beautiful AND Mind,同时要求顺序一致
title="Beautiful Mind"
。
- Beautiful Mind 等效于 Beautiful OR Mind
- 布尔操作
AND
$$
OR
||
NOT
!
- 分组操作
+
或%2B
必须要。-
一定不要。title:(Beautiful %2BMind)
这种情况下 Mind 不需要有,Beautiful 可以没有。
- 范围查询
[]
闭区间,{}
开区间。year:{2018 TO 2019]
year:[* TO 2019]
- 数学符号
year:>2010
year:(>2010 %% <=2018)
year:(+>2010 +<=2018)
- 当然也能有通配符、正则.
- 模糊与近似查询
title:beautifl~1
可以找到拼写完整的 befautiful。title:"lord rings"~2
可以找到 lord of the rings。
8. Request Body 与 Query DSL
- 推荐用 Request Body Search,有些操作这能在这里用。
- 请求体的
query
中"match_all":{}
查询所有文档。 - 请求体的
from
从 0 开始,默认返回 10 个结果。 - 请求体的
sort
可以进行排序,比如"sort":[{"order_date":"desc"}]
。最好是数字和日期。 - 请求体的
_source
可以进行过滤,比如"_source":["order_date","category.keyword"]
。 - URI 中的参数
ignore_unavailable=true
可以忽略访问不存在的索引导致的报错。 - 请求体中使用
script_fields
表示脚本字段,比如如下例子:
1 | GET kibana_sample_data_ecommerce/_search |
比如计算汇率的时候可以用到。
- Match 请求对应了 Term 操作,在请求体的
query
中使用match
开始,默认的operator
是 OR,比如如下例子:
1 | POST movies/_search |
- 响应的也有 Match Phrase 查询对应了 Phrase 操作,在请求体的
query
中使用match_phrase
开始,如下:
1 | POST movies/_search |
可以输出
"title" : "One I Love, The"
。
9. Query String 和 Simple Query String 查询
- 类似与 URI Query。
- 在请求体的
query
中使用query_string
进行填充,df = default_field,在其中也能用到query
。 simple_query_string
和query_string
类似,但是会忽略一些错误的语法,同时只支持部分查询。- 不支持 AND OR NOT,都当做字符串处理。
- Term 之间默认关系是 OR,但是可以指定 Operator。
- 支持逻辑,
+
代替AND
,|
代替OR
,-
代替NOT
。
10. Dynamic Mapping 和常见字段类型
- Mapping 和 Dynamic Mapping
- Mapping 类似于 DB 中的 schema,可以定义索引中的字段,定义字段类型,进行倒排索引配置。
- Mapping 会将 JSON 映射成 Lucene 所需要的扁平格式。
- 字段类型自动识别
- 简单类型有 Text/Keyword,Date,Integer/Floating,Boolean,IPv4/IPv6。
- 复杂类型有对象和嵌套类型。
- 特殊类型有 geo_point/geo_shape/percolator。
- 控制 Mapping 的 Dynamic 属性
- 一个 Mapping 属于一个索引的 Type,现在一个索引只能有一个 Type。
- Dynamic Mapping 是在写入文档的时候,如果索引不存在就会自动创建索引,但是类型推断有时候会发生错误。
- 字符串且匹配日期格式,自动为 Date。
- 字符串且匹配数字,设置 float 或 long,该转换默认关闭。
- 其他字符串则为 Text。
- 布尔对应 boolean。
- 浮点对应 float。
- 整数对应 long。
- 对象对应 Object。
- 数组由第一个非空数值类型决定。
- 控制直接忽略。
- 如果 Dynamic 为 true,一旦有新字段加入,Mapping 会更新;如果 Dynamic 为 false,新字段无法被索引,但是信息会在
_source
中;如果 Dynamic 是 strict,文档写入失败。 - 对于已经有了的字段,一旦已经有数据写入,则不再支持字段定义的更改。
- 更改字段类型需要 Reindex API,重建索引。
11. 显式 Mapping 设置与常见参数
- 可以参考 API 手册,纯手写。
- 创建一个临时 Index,写入一些样本数据。
- 通过访问 Mapping API 获得该临时文件的动态 Mapping 定义。
- 修改该定义为你的索引。
- 删除临时索引。
index
控制是否字段被索引,false 时,倒排索引就不会被生成了。index_options
倒排索引的四个级别。docs
记录 doc id。(除 Text 默认)freqs
记录 doc id 和 term frequencies。positions
记录 doc id 和 term frequencies 和 term position。(Text 默认)offsets
记录 doc id 和 term frequencies 和 term position 和 character offects。
- 如果需要对 Null 值进行搜索,在 Keyword 类型下支持设定
null_value
,在搜索时是真正的 Null 值。 _all
被copy_to
替代,将字段值拷贝到目标字段,搜索可以用目标字段搜索,copy_to
字段不会出现在_source
中。- es 没有专门的数组类型,但是任何字段都可以包含多个相同类型的数值。
12. 多字段特性与 Mapping 中自定义 Analyzer
- 对某一个字段增加一个子字段,也可以指定不同的 Analyzer 进行分词。
- es 中的 Keyword 是一种精确值,包括数字、日期、具体的字符串,没有必要对其进一步分词;而全文本是非结构化的文本数据,就是 es 中的 Text。
- 当自带分词器无法满足需求,可以自定义分词器。
- Character Filter 分此前对文本进行特殊处理,会影响 position 和 offset 的信息,HTML Strip 去除 html 标签,Mapping 字符串替换,Pattern Replace 正则替换。
- Tokenizer 分词时把文本按照一定规则分成词,比如空格、正则、不处理、文件路径等。
- Token Filter 分词后进行二次加工,将输出的单词进行增加、修改、删除。
13. Index Template 和 Dynamic Template
- Index Templates 帮助设置 Mappings 和 Settings,按照一定的规则自动匹配到新创建的索引之上。
- 模板仅在一个索引被创建时才会有用,模板不会影响已经创建的索引。
- 可以设置多个索引模板,这些设置会被 merge 在一起。
- 可以指定
order
的数值,用来控制 merge 的过程。
- 当一个索引被创建:
- 应用 es 默认的 Settings 和 Mappings。
- 应用
order
值低的 Index Template 中的设定。 - 用高
order
设置覆盖低order
设定。 - 用户指定的 Settings 和 Mappings 覆盖之前的设定。
- Dynamic Template 是应用在一个具体的索引上的,结合字段名称,数据类型,来动态设置字段类型。
- 比如所有字符串都设置为 keyword,所有 is 开头都为 boolean,所有 long_ 开头都设置为 long 等。
14. es 聚合分析
- 所谓聚合就是数据统计分析,过滤结果。
- Bucket Aggregation 满足一些特定条件的文档的集合。
- Metric Aggregation 数学运算,可以对文档字段进行统计分析。
- Pipeline Aggregation 对其他的聚合结果进行二次聚合。
- Matrix Aggregation 支持对多个字段的操作提供一个结果矩阵。
1 | SELECT COUNT(brand) # Metrix |
- 聚合功能
aggs
可以叠加也可以嵌套。
1 | GET kibana_sample_data_flights/_search |
15. 总结
- 判断题:ES 支持使用 Http Put 写入新文档,并通过 Elasticsearch 生成文档 id
- 错,需要用 POST 命令创建
- 判断题:Update 一个文档,需要使用 Http Put
- 错,Update 文档,使用 POST,PUT 只能用来做 Index 或者 Create
- 判断题:Index 一个已存在的文档,旧的文档会先被删除,新的文档再被写入,同时版本号加 1
- 对
- 尝试描述创建一个新的文档到一个不存在的索引中,背后会发生一些什么
- 默认情况下,会创建相应的索引,并且自己设置 Mapping,当然,实际情况还是要看是否有合适的 Index Template
- ES7 中的合法的 type 是什么
- _doc
- 精确值和全文的本质区别是什么
- 精确值不会被 Analyzer 分词,全文本会
- Analyzer 由哪几个部分组成
- 三部分,Character Filter + Tokenizer + Token filter
- 尝试描述 match 和 match_phrase 的区别
- Match 中的 terms 之间是 or 的关系,Match phrase 的 terms 之间是 and 的关系,并且 term 之间位置关系也影响搜索的结果
- 如果你希望 match_phrase 匹配到更多结果,你应该配置查询中什么参数
- slop
- 如果 Mapping 的 dynamic 设置成 strict,索引一个包含新增字段的文档时会发生什么
- 直接报错
- 如果 Mapping 的 dynamic 设置成 false,索引一个包含新增字段的文档时会发生什么
- 文档被索引,新的字段在 _source 中可见。但是该字段无法被搜索
- 判断题:可以把一个字段的类型从 integer 改成 long,因为这两个类型是兼容的
- 错。字段类型修改,需要重新 reindex
- 判断题:你可以在 Mapping 文件中为 indexing 和 searching 指定不同的 analyzer
- 对。可以在 Mapping 中为 index 和 search 指定不同的 analyzer
- 判断题:字段类型为 Text 的字段,一定可以被全文搜索
- 错。可以通过为 Text 类型的字段指定 Not Indexed,使其无法被搜索