Elasticsearch学习笔记

115 阅读13分钟

一. ES基本使用 (es7)

1.HTTP方式

1.1.索引

1.1.1.创建索引
创建一个名为shopping的索引

请求
PUT http://127.0.0.1:9200/shopping

响应
{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "shopping"
}
1.1.2.查询所有索引
查询所有索引信息

请求
GET http://127.0.0.1:9200/_cat/indices?v=

响应
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   shopping qBEYH-J-Qwyp4Oj26PYlUQ   1   1          3            0     10.3kb         10.3kb

响应字段说明

字段含义
health当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
status索引状态(开、关)
index索引名
uuid索引编号
pri主分片数量
rep副本数量
docs.count可用文档数量
docs.deleted文档删除状态(逻辑删除)
store.size主分片和副分片整体占空间大小
pri.store.size主分片占空间大小
1.1.3.查询单个索引
查询单个索引信息

请求
GET http://127.0.0.1:9200/shopping

响应
{
    "shopping": {
        "aliases": {},
        "mappings": {},
        "settings": {
            "index": {
                "creation_date": "1692944013337", //创建索引的时间戳
                "number_of_shards": "1", // 主分片数量
                "number_of_replicas": "1", // 副本分片数量
                "uuid": "qBEYH-J-Qwyp4Oj26PYlUQ",
                "version": {
                    "created": "7080099" // 版本号
                },
                "provided_name": "shopping" // 索引名称
            }
        }
    }
}
1.1.4.删除索引
删除名称为shopping的索引

请求
DELETE http://127.0.0.1:9200/shopping

响应
{
    "acknowledged": true
}

1.2.文档

1.2.1.文档创建
在shopping索引下创建文档,未指定索引唯一标识,由es自动生成

POST http://127.0.0.1:9200/shopping/_doc

请求
{
    "title":"小米手机",
    "category":"小米",
    "images":"http://www.gulixueyuan.com/xm.jpg",
    "price":3999.00
}

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "gfwjOooBJ0MTev-ZEfGK",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
在shopping索引下创建文档,指定索引唯一标识1,指定了唯一标识,此处也可以用PUT请求

POST http://127.0.0.1:9200/shopping/_doc/1
or
PUT http://127.0.0.1:9200/shopping/_doc/1

请求
{
    "title":"小米手机",
    "category":"小米",
    "images":"http://www.gulixueyuan.com/xm.jpg",
    "price":3999.00
}

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}
1.2.2.文档主键查询
查询shopping索引下文档id为1的数据

GET http://127.0.0.1:9200/shopping/_doc/1

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 1,
    "_seq_no": 1,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "title": "小米手机",
        "category": "小米",
        "images": "http://www.gulixueyuan.com/xm.jpg",
        "price": 3999
    }
}
1.2.3.文档全查询
查询shopping索引下文档的所有数据

GET http://127.0.0.1:9200/shopping/_search

响应
{
    "took": 133,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1,
        "hits": [
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "ANQqsHgBaKNfVnMbhZYU",
                "_score": 1,
                "_source": {
                    "title": "小米手机",
                    "category": "小米",
                    "images": "http://www.gulixueyuan.com/xm.jpg",
                    "price": 3999
                }
            },
            {
                "_index": "shopping",
                "_type": "_doc",
                "_id": "1",
                "_score": 1,
                "_source": {
                    "title": "小米手机",
                    "category": "小米",
                    "images": "http://www.gulixueyuan.com/xm.jpg",
                    "price": 3999
                }
            }
        ]
    }
}
1.2.4.文档全局修改
和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖.

POST http://127.0.0.1:9200/shopping/_doc/1

请求
{
    "title":"华为手机",
    "category":"华为",
    "images":"http://www.gulixueyuan.com/hw.jpg",
    "price":1999.00
}

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 2,
    "result": "updated",    //updated 表示数据被更新
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}
1.2.5.文档局部修改
修改数据时,只修改某一条数据的局部信息

POST http://127.0.0.1:9200/shopping/_update/1

请求
{
    "doc": {
        "title":"小米手机",
        "category":"小米"
    }
}

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 3,
    "result": "updated",//updated 表示数据被更新
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 3,
    "_primary_term": 1
}
1.2.6.文档条件查询
1.URL带参数查询

查找category为小米的文档
GET http://127.0.0.1:9200/shopping/_search?q=category:小米

2.请求体带参查询

查找category为小米的文档
GET http://127.0.0.1:9200/shopping/_search
{
    "query":{
        "match":{
            "category":"小米"
        }
    }
}

3.带请求体方式的查找所有内容

GET http://127.0.0.1:9200/shopping/_search
{
    "query":{
        "match_all":{}
    }
}

4.查询指定字段

查询文档中的title字段
GET http://127.0.0.1:9200/shopping/_search
{
    "query":{
        "match_all":{}
    },
    "_source":["title"]
}

1.2.7.文档分页查询
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "match_all":{}
    },
    "from":0,
    "size":2
}
1.2.8.文档查询排序
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "match_all":{}
    },
    "sort":{
        "price":{
            "order":"desc"
        }
    }
}
1.2.9.文档多条件查询
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "bool":{
            "must":[{
                "match":{
                    "category":"小米"
                }
            },{
                "match":{
                    "price":3999.00
                }
            }]
        }
    }
}
1.2.10.文档范围查询
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "bool":{
            "should":[{
                "match":{
                    "category":"小米"
                }
            },{
                "match":{
                    "category":"华为"
                }
            }],
            "filter":{
                "range":{
                    "price":{
                        "gt":2000
                    }
                }
            }
        }
    }
}
1.2.11.全文检索
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "match":{
            "category" : "小华"
        }
    }
}
1.2.12.完全匹配
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "match_phrase":{
            "category" : "为"
        }
    }
}
1.2.13.高亮查询
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "query":{
        "match_phrase":{
            "category" : "为"
        }
    },
    "highlight":{
        "fields":{
            "category":{}   //高亮这字段
        }
    }
}
1.2.14.聚合查询

1.分组查询
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "aggs":{//聚合操作
        "price_group":{     //名称,随意起名
            "terms":{       //分组
                "field":"price" //分组字段
            }
        }
    }
}

2.求price的平均值
GET http://127.0.0.1:9200/shopping/_search

请求
{
    "aggs":{
        "price_avg":{   //名称,随意起名
            "avg":{     //求平均
                "field":"price"
            }
        }
    },
    "size":0
}
1.2.15.文档删除
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)

DELETE http://127.0.0.1:9200/shopping/_doc/1

响应
{
    "_index": "shopping",
    "_type": "_doc",
    "_id": "1",
    "_version": 4,
    "result": "deleted",//删除成功
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 4,
    "_primary_term": 1
}

1.3.映射

1.3.1.映射

ES中的映射(mapping)相当于mysql中的table,用来约束索引下的文档字段信息。

1.3.2.创建映射
1.创建索引user
PUT http://127.0.0.1:9200/user

2.创建user索引的映射
PUT http://127.0.0.1:9200/user/_mapping
请求
{
    "properties": {
        "name":{
            "type": "text",  // text,可以被分词查询
            "index": true
        },
        "sex":{
            "type": "keyword",// keyword,不可以被分词查询,只能全匹配
            "index": true
        },
        "tel":{
            "type": "keyword",
            "index": false // 代表不能被索引查询,即不能作为条件查询
        }
    }
}

二.ES原理

2.1.核心概念

2.1.1.索引

索引就是拥有相似特征的文档集合。在一个集群中,可以定义任意多的索引。

2.1.2.类型

  • 类型是索引的一个逻辑上的分类/分区。在一个索引中,你可以定义一种或多种类型。
  • 7.X版本后,默认不再支持自定义索引类型(默认类型为: _doc)

2.1.3.文档

一个文档是一个可被索引的基础信息单元,也就是一条数据。

2.1.4.字段

相当于是数据表的字段,对文档数据根据不同属性进行的分类标识。

2.1.5.映射

ES中的映射(mapping)相当于mysql中的table,用来约束索引下的文档字段信息。 如:某个字段的数据类型、默认值、分析器、是否被索引等等

ES数据类型

1.text
当一个字段需要被全文搜索(会被分词),比如产品的描述信息等。

2.keyword
当一个字段需要按照精确值进行过滤、排序、聚合等操作时, 就应该使用keyword类型。该类型的字段值不会被分析器处理(分词)

3.数字类型
byte、short、integer、long、float、double、half_float、scaled_float	

4.boolean
可以使用boolean类型的(truefalse)也可以使用string类型的(“true”、“false”)。

5.binary
二进制类型是Base64编码字符串的二进制值,不以默认的方式存储,且不能被搜索。

6.日期
使用双竖线||分隔指定多种日期格式,每个格式都会被依次尝试,直到找到匹配的。

curl -X PUT "localhost:9200/my_index?pretty" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_type": {
      "properties": {
        "date": {
          "type":   "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        }
      }
    }
  }
}'

2.1.6.分片

  • 一个索引的数据超出硬件节点的限制或者数据量太大影响性能,可以把一个大的索引拆分成多份,每一份称之为分片。
  • 每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。

分片的作用

  1. 允许水平分割/扩展内容容量。
  2. 允许在分片之上进行分布式的、并行的操作,进而提高性能/吞吐量。

2.1.7.副本

ES允许创建分片的一份或多份拷贝,这些拷贝叫做复制分片(副本)。 副本的作用

  1. 在分片/节点失败的情况下,提供了高可用性。
    • 复制分片从不与原/主要(original/primary)分片置于同一节点上
  2. 扩展搜索量/吞吐量,因为搜索可以在所有的副本上并行运行。

2.2.ES节点类型

ES根据节点主要职能,大致有三种类型节点: master主节点、data数据节点、协调节点。每个节点都能设置三个类中的一个。

2.2.1.master节点

  1. 默认情况下任何节点都可以成为master节点。实际上master节点仅有一个, 但是可以设置多个候选的master节点。在节点的配置中设置node.master=true即可将节点设为master主节点。在当前master节点意外退出后, 集群会在候选节点中重新选举一个master主节点。
  2. master节点主要负责创建索引、节点健康状态监控、节点上下线等工作

2.2.2.数据节点

数据节点负责保存数据、执行数据相关操作。对节点的CPU、内存和IO要求较高。在节点的配置中设置node.data=true, node.master=false即可将节点设为数据节点。数据读写流程只和数据节点交互。

2.2.3.协调节点

协调节点用于客户端请求集群时使用,默认情况下任意节点都能成为协调节点,协调节点会在接受请求的时候根据情况转发给其他节点,并汇总结果返回给客户端,在节点的配置中设置node.data=false, node.master=false即可将节点设为协调节点。 协调节点在汇总数据时也可能需要很高CPU和内存,最好有单独协调节点

2.3.集群

2.3.1.水平扩容

es-集群.png

总结

  1. 当集群中有了新的节点加入、或者节点宕机,ES会重新调整分片及副本的策略。
  2. 主分片在创建索引的时候分配之后,就不能在改变,这是由于ES的路由计算策略决定。
  3. 读操作-可以同时被主分片、副本分片所处理,所以当副本分片越多时,也能提升集群性能。
  4. 在运行的集群上是可以动态调整副本分片数目,从而提升集群性能。

调整分片副本数量

调整users索引的副本分片数量

PUT http://127.0.0.1:1001/users/_settings

{
    "number_of_replicas" : 2
}

2.3.2.路由计算

ES通过路由计算来确定一个索引的读写是在那个主分片上

路由计算策略

shard = hash(routing) % number_of_primary_shards

1.routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。
2.routing 通过hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数
3.这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

2.3.3.选举流程

2.3.3.1.ES7.X版本之前(基于Bully算法)

ES的ZenDiscovery模块负责选举,它采用Bully算法的思想进行。

Bully算法思路

  1. 它假定所有的节点都有一个唯一ID,使用该ID对节点进行排序。
  2. Leader节点就是排序的第一个节点。

Bully算法缺点: Leader节点因为负载过重假死,集群中第二位节点被选为Leader,这时原来的Leader恢复,再次被选举为Leader,然后又假死。导致集群异常。

ES的选举流程 ES针对Bully算法的缺点,做出以下优化

  1. ES 通过推迟选举,直到当前的 Master 失效来解决上述问题,只要当前主节点不挂掉,就不重新选主。
  2. 但是容易产生脑裂(双主),为此,再通过“法定得票人数过半”解决脑裂问题。在弹性搜索中,法定大小是一个可配置的参数。(一般配置成:可以成为master节点数n/2+1)
2.3.3.2.ES7.X版本开始(基于Raft算法)

Raft算法

es-raft.png

Raft节点的三种状态

  1. Leader:领导者
  2. Candidate:候选人
  3. Follower:跟随者

正常情况下,集群中只有一个Leader,其他节点全是Follower。Follower 都是被动接收请求,从不主动发送任何请求。Candidate候选人是从Follower到Leader的中间状态。

Raft中引入任期(term) 的概念,每个term内最多只有一个Leader。term 在Raft算法中充当逻辑时钟的作用。服务器之间通信的时候会携带这个term,如果节点发现消息中的term小于自己的term,则拒绝这个消息;如果大于本节点的term,则更新自己的term。如果一个Candidate或者Leader发现自己的任期过期了,它会立即回到Follower状态。

Raft选举流程

  1. 增加当前节点本地的current term,切换到Candidate状态;
  2. 当前节点投自己一票,并且并行给其他节点发送RequestVote RPC (让大家投他)

然后等待其他节点的响应,会有如下三种结果:

  1. 如果接收到大多数服务器的选票,那么就变成Leader。成为Leader后,向其他节点发送心跳消息来确定自己的地位并阻止新的选举。
  2. 如果收到了别人的投票请求,且别人的term比自己的大,那么候选者退化为Follower;
  3. 如果选举过程超时,再次发起一轮选举;

ES的Raft实现

  1. ES中,候选人不先投自己,而是直接发起选举投票。这相当于候选人有投票给其它候选者的机会(比较term大小),从而避免多个节点同时成为候选人,都投自己,无法成功选举。
  2. ES不限制每个节点在某个Term上只能投一票,节点可投多票。这样会引起产生多个Leader的情况。
  3. 对于这种情况,ES的处理是让最后当选的Leader成功,作为Leader。如果收到RequestVote请求,他会无条件退出Leader状态。

参考:blog.csdn.net/qq_26222859…

2.4.读写机制

2.4.1.读机制

es-数据读取.png

  1. 客户端发起查询请求到协调节点
  2. 协调节点计算数据所在的主分片及全部副本分片位置
  3. 为了能够负载均衡,轮询查询所有分片
  4. 请求转发给具体节点
  5. 节点返回查询结果并反馈客户端

2.4.2.写机制

es-数据写入.png

  1. 客户端发起写入请求到协调节点
  2. 协调节点根据路由算法计算数据写入的主分片节点
  3. 转发请求到主分片节点
  4. 主分片保存数据,并发送数据给副本分片保存
  5. 副本保存完成后,主分片进行反馈结果

2.4.3.更新文档

  • 因为ES使用了乐观锁,在更新某一条文档时会认为不会有其他进程对该文档进行修改, 所以不会加锁。

  • 当更新某一个文档的时候,先回读取该文档, 获取version值, 然后将version和更新数据写回分片,这时候会对比分片文档中version和更新数据的中version是否相同,相同的话则更新成功version值加1, 不同的话更新失败。所以同时对一个文档进行多个更新,成功更新只能有一个。

2.5.倒排索引

  • 正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。
  • 倒排索引是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程。

1.倒排索引的两个概念

  1. 文档:用来搜索的数据,每一条数据就是一个文档。
  2. 词条:对文档数据或者用户搜索数据,利用分词算法,得到具备含义的词语就是词条。
  3. 倒排表:用来存储词条和包含词条文档id的数据表。

2.倒排索引是对正向索引的一种特殊处理,流程如下:

  1. 将每一个文档的数据利用算法分词,得到一个个词条
  2. 创建倒排表,每行数据包括词条、词条所在文档id、位置等信息
  3. 因为词条唯一性,可以给词条创建索引,例如hash表结构索引

3.倒排索引的搜索流程

  1. 用户输入条件进行查询
  2. 对用户输入内容进行分词,得到相关词条
  3. 根据词条在倒排表中查询,得到包含词条的文档ID
  4. 根据文档ID到正向索引表中查找具体文档