You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

465 lines
13 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# ElasticSearch
## 什么是ElasticSearch?
Elasticsearch是基于Apace Lunence构建的开源分布式具有高可用性和高拓展性的全文检索引擎。Elasticsearch具有开箱即用的特性提供RESTful接口是面向文档的数据库文档存储格式为JSON可以水平扩展至数以百计的服务器存储来实现处理PB级别的数据。
## ES有哪些节点类型
一个节点就是一个Elasticsearch的实例每个节点需要显示指定节点名称可以通过配置文件配置或者启动时候`-E node.name=node1`指定
#### 节点类型
每个节点在集群承担承担不同的角色,也可以称为节点类型。
**候选主节点(Master-eligible nodes)和主节点(Master Node)**
- 每个节点启动之后默认就是一个Master eligible节点Master-eligible节点可以参加选主流程成为Master节点
- 当第一个节点启动时候它会将自己选举成为Master节点
- 在每个节点上都保存了集群的状态信息,但**只有Master节点才能修改集群的状态信息**。集群状态(Cluster State)中必要信息包含
- 所有节点的信息
- 所有的索引以及其Mapping与Setting信息
- 分片的路由信息
**数据节点(Data Node)和协调节点(Coordinating Node)和Ingest节点**
- Data Node
- **用于保存数据的节点。负责保存分片的数据,在数据拓展上起到至关重要的作用**
- Coorination Node
- **负责接受Client的请求将请求分发到合适的节点最终把结果汇集到一起**
- **每个节点默认都起到Cooridinating Node的职责**这就意味着如果一个node将node.masternode.datanode.ingest全部设置为false那么它就是一个纯粹的coordinating Node node仅仅用于接收客户端的请求同时进行请求的转发和合并
- Ingest节点
- 用于预处理可以运行pipeline脚本用来对document写入索引文件之前进行预处理的
在生产环境部署上可以部署独立(dedicate)的 Ingest Node 和 Coordinate node在前端的Load Balance前面增加转发规则把读分发到coording node写分发到 ingest node。 如果集群负载不高可以配置一些节点同时具备coording和ingest的能力。然后将读写全部路由到这些节点。不仅配置简单还节约硬件成本
**其他类型节点**
- 冷热节点(Hot & Warm Node)
- 不同硬件配置的Data Node用来实现Hot & Warm架构降低集群部署的成本。通过设置节点属性来实现
- 机器学习节点(Machine Learning Node)
- 负责跑机器学习的Job用来异常检测
配置原则:
- 开发环境一个节点可以承担多种角色,节省服务器资源
- 生产环境中应该设置单一的角色的节点即dedicated node
节点类型 | 配置参数 | 默认值
---|---|----
候选主节点 | node.master | true
数据节点 | node.data | true
ingest节点 | node.ingest | true
协调节点 | 无 | 每个节点默认都是协调节点
机器学习节点 | node.ml | true
## 为什么说ES是准实时的
![](https://static.cyub.vip/images/202107/es_index_flow.jpeg)
Document首先写入到Indexing buffer中当 buffer 中的数据每隔index.refresh_interval秒或者Indexing buffer满了)缓存 refresh 到filesystem cache 中时,此时文档是可以检索到了
## 怎么解决ES深度分页问题
深度分页指的是假设我们请求第 1000 页—​结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。在分布式系统中,对结果排序的成本随分页的深度成指数上升。
解决办法就是业务上面避免。
## doc values为了解决什么
doc_values是为了解决排序和聚合问题。doc_values不适合text类型字段对于text类型字段需要使用Fielddata
```
PUT /myindex/_mapping/doc
{
"properties": {
"myfield": {
"type": "text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
}
}
}
```
上面myfield是不可以聚合的但是myfield.keyword是可以聚合的
## ES中副本分片的目的是做什么
1. 副本分片的主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。
2. 副本分片可以服务于读请求,可以通过增加副本的数目来提升查询性能
## 怎样在不停机情况下,进行索引重建?
索引别名
## ES数据建模有哪些模式
加入我们正在根据用户名称,搜索其博客文章
### 应用层联接
根据user索引搜索到用户id然后根据id去搜索文章索引blogpost
```
PUT /my_index/user/1
{
"name": "John Smith",
"email": "john@smith.com",
"dob": "1970/10/24"
}
PUT /my_index/blogpost/2
{
"title": "Relationships",
"body": "It's complicated...",
"user": 1
}
```
### 反范式设计
用于1对多模式下将1的信息存放在N这一边。下面就是把用户信息存放一份在blogpost这里面
```
PUT /my_index/user/1
{
"name": "John Smith",
"email": "john@smith.com",
"dob": "1970/10/24"
}
PUT /my_index/blogpost/2
{
"title": "Relationships",
"body": "It's complicated...",
"user": {
"id": 1,
"name": "John Smith"
}
}
```
### 嵌套对象
假定们可以将一篇博客文章的评论以一个 comments 数组的形式和博客文章放在一起:
```
PUT /my_index/blogpost/1
{
"title": "Nest eggs",
"body": "Making your money work...",
"tags": [ "cash", "shares" ],
"comments": [
{
"name": "John Smith",
"comment": "Great article",
"age": 28,
"stars": 4,
"date": "2014-09-01"
},
{
"name": "Alice White",
"comment": "More like this please",
"age": 31,
"stars": 5,
"date": "2014-10-22"
}
]
}
```
我们想要搜索到评论者是Alice且年龄是28岁的评论搜索语句如下
```
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Alice" }},
{ "match": { "age": 28 }}
]
}
}
}
```
搜索结果却能够搜索到记录。这是不符合预期的。
这是因为对象数组中JSON 格式的文档被处理成如下的扁平式键值对的结构comments对象中字段失去关联
```
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ],
"comments.name": [ alice, john, smith, white ],
"comments.comment": [ article, great, like, more, please, this ],
"comments.age": [ 28, 31 ],
"comments.stars": [ 4, 5 ],
"comments.date": [ 2014-09-01, 2014-10-22 ]
}
```
这时候我们可以使用nested object来保证子对象关系未打散
```
{
"comments.name": [ john, smith ],
"comments.comment": [ article, great ],
"comments.age": [ 28 ],
"comments.stars": [ 4 ],
"comments.date": [ 2014-09-01 ]
}
{
"comments.name": [ alice, white ],
"comments.comment": [ like, more, please, this ],
"comments.age": [ 31 ],
"comments.stars": [ 5 ],
"comments.date": [ 2014-10-22 ]
}
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ]
}
PUT /my_index
{
"mappings": {
"blogpost": {
"properties": {
"comments": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"comment": { "type": "string" },
"age": { "type": "short" },
"stars": { "type": "short" },
"date": { "type": "date" }
}
}
}
}
}
}
```
### 父子文档
在 nested objects 文档中,所有对象都是在同一个文档中,而在父-子关系文档中,父对象和子对象都是完全独立的文档。
父-子关系的主要优势有:
- 更新父文档时,不会重新索引子文档。
- 创建,修改或删除子文档时,不会影响父文档或其他子文档。这一点在这种场景下尤其有用:子文档数量较多,并且子文档创建和修改的频率高时。
- 子文档可以作为搜索结果独立返回。
## ES索引生命周期管理是怎么回事
ES索引生命周期管理分为4个阶段hot、warm、cold、delete其中hot主要负责对索引进行rollover操作warm、cold、delete分别对rollover后的数据进一步处理。
phases | desc
--- | ---
hot | 索引更新和查询很活跃
warm | 索引不再更新,但仍然有查询
cold | 索引不再更新,只有很少的查询,而且查询速度也很慢
delete | 索引不需要了,可以安全的删除
### 操作
#### timing
ILM各个阶段的action几乎都需要用到定时器例如下面这个操作
```
curl -X PUT "localhost:9200/_ilm/policy/my_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"warm": {
"min_age": "1d",
"actions": {
"allocate": {
"number_of_replicas": 1
}
}
},
"delete": {
"min_age": "30d",
"actions": {
"delete": {}
}
}
}
}
}
'
# 应用到模板上
PUT _index_template/my_template
{
"index_patterns": ["test-*"],
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1,
"index.lifecycle.name": "my_policy",
"index.lifecycle.rollover_alias": "test-alias"
}
}
}
```
上述warm阶段通过min_age配置了1d意思是索引从创建至少需要经历1天的时间才会被移入到warm阶段另一个delete阶段min_age配置了30d意思是索引在创建后的30天会被删除通常情况下warm、cold、delete的起始时间是从索引创建开始算起的但是如果配置了hot那么后面phrase配置的时间应该大于rollover的时间。
#### Hot Rollover
```
curl -X PUT "localhost:9200/_ilm/policy/datastream_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "30d"
}
}
}
}
}
'
```
我们定义了一个策略策略中使用了hot rollover action当引用该策略的索引满足rollover中任一一个条件时就会触发滚动操作生成新的索引新索引的格式是 ^.*-\d+$ (如index_name-000001)
#### Warm Allocate
allocate action主要有两个操作1、转移数据到warm节点2、修改索引副本数。
```
PUT _ilm/policy/my_policy
{
"policy": {
"phases": {
"warm": {
"actions": {
"allocate" : {
"number_of_replicas": 0,
"include" : {
"box_type": "cold,warm"
}
}
}
}
}
}
}
```
其中include配置的标签需要和elasticsearch.yml中配置的标签名一致allocate支持的参数有
参数 | 描述
number_of_replicas | 分配后索引保持的分片数
include | 至少满足其中一个标签
exclude | 排除包含这些标签的服务器
require | 需要同时满足所有配置的标签
#### Warm Read-Only
配置索引为只读模式
```
curl -X PUT "localhost:9200/_ilm/policy/my_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"warm": {
"actions": {
"readonly" : { }
}
}
}
}
}
'
```
#### Warm Force-Merge
指定索引合并后保留的segment数过多的 segment 对查询性能有影响,为了充分合并数据,建议设置为 max_num_segments = 1
```
curl -X PUT "localhost:9200/_ilm/policy/my_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"warm": {
"actions": {
"forcemerge" : {
"max_num_segments": 1
}
}
}
}
}
}
'
```
需要注意的是设置forcemerge action后索引会被修改为只读模式
#### Warm Shrink
通过shrink action可以降低索引的分片数量同样执行该action操作后索引会被修改为只读模式同时索引名也会发生变化如原来索引名称是“logs”执行后的名称会多一个shrink-前缀即“shrink-logs”。
```
curl -X PUT "localhost:9200/_ilm/policy/my_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"warm": {
"actions": {
"shrink" : {
"number_of_shards": 1
}
}
}
}
}
}
'
```
#### Cold Freeze
冻结索引意思就是关闭索引。
```
PUT _ilm/policy/my_policy
{
"policy": {
"phases": {
"cold": {
"actions": {
"freeze" : { }
}
}
}
}
}
```