ElasticSearch概述
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful接口。它可以近乎实时的存储、检索数据;本身扩展性非常好,一个ES节点就可以认为是一个集群(默认支持集群),它可以扩展到上百台服务器。ES的生产环境至少在8GB以上
Lucene和ES的关系
- Lucene只是一个库,必须使用Java作为开发语言将他集成到应用中,使用起来十分复杂
- ElasticSearch也是使用Java开发并使用Lucene作为其核心来实现所有索引和搜索功能,它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,让全文搜索变得简单
ES和Mysql对比理解
MySQL | Elastic Search |
---|---|
Database | Index |
Table | Type |
Row | Document |
Column | Field |
Schema | Mapping |
Index | Everything is indexed |
SQL | Query DSL |
SELECT* FORM table… | GET http://… |
UPDATE table SET… | PUT http://… |
- 关系型数据库中schema定义了表,字段以及表和字段之间的关系。与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引json文档、是否需要分词处理、如何进行分词处理等等
- Mysql主要用途:存储数据,用来完成强一致性,保证ACID的数据,逻辑性事务性操作
- Redis主要用途:存储数据,做缓存
- ES主要用途:存储数据,提供全文检索
ES核心概念
- 索引Index:ES中的索引类似关系型数据库中的数据库,里面存放用户文档数据,因为ES是封装的Lucene,所以底层还是由Lucene的一个或者多个索引组成,数据的增删改查也是由底层的Lucene完成,ES中的分片或副本实际上就是一个Lucene索引
- 文档Document:文档是ES中存储数据的主体,ES中所有操作都是建立在文档的基础上的,每个文档都是由各种Field组成,每一个Field有一个名称和一个或多个值构成,文档展示给用户就是一个JSON对象
- 类型Type:ES中Type是一种逻辑上的概念,类似关系型数据库中的表,每个文档都属于某一种类型,如果没有定义类型会有默认值,ES每个索引可以包含多种类型。现在ES5.0之后,就不推荐使用Type了,全部叫_doc
- 映射Mapping:映射类似关系型数据库中的schema,用于定义field的属性,如字段类型、是否分词等,这里有一点和关系型数据库不同的是ES会在用户没有定义字段属性的情况下,自动嗅探该字段的类型进行自动识别
- 集群Cluster:多个ES节点工作在一起组成一个集群,ES对于集群的支持几乎是无缝的
- 节点Node:一个ES实例就是一个节点,说的再简单点,一台部署了ES服务器的机器就是一个节点,同时一台机器如果硬件资源允许也可以同时启动多个ES实例,ES中每个节点都和集群(如果是多个节点的集群)中的其他节点相互通信,了解多有文档存储位置并能转发用户的请求到对应的数据节点上
- 分片Shard:因为ES是分布式架构,类似有HDFS的存储方式,所以数据被打散存储在集群的多个节点上,一个分片实际上就是底层Lucene的一个索引,这里说分片指的是ES中的主分片,分片的方式是ES自动完成,用户可以指定分片的数量,主分片一旦指定就不能修改,因为ES打散数据的方式和索引创建时指定的主分片数量有关,后期改变会导致分片中的数据不可搜索
- 副本Replia:副本就是分片的一个备份,不仅能提高自身容灾,而且在请求量巨大的情况下可以分担Shard的压力,承担查询功能,副本个数可以在创建完成之后调整
索引
正向索引—MySQL索引
- 创建mysql索引:
CREATE INDEX 索引名称 ON 表明(字段名)
添加索引后能够有效提高程序检索的效率,插入200w数据,没用索引查询时间约1.2s;加入索引后查询时间约为0.005s,数据量越大,区别越明显。对于需要频繁修改的字段,不要添加索引,原因是mysql索引基于B+树(这也是添加索引查询变快的原因) - 聚集索引:主键就是聚集索引,且在一个表中,只能有一个聚集索引,聚集索引直接在表上进行了排序,这也就是为什么插入数据的时候id为2的比id为3的后插入但是会排在id为3的之前
- 非聚集索引:mysql中非聚集索引无限制,排序没有在表上排序,而是在索引中排序的。通过非聚集索引查询时会先查询到聚集索引,在通过聚集索引查询数据
- 索引的建立要花时间,就是一种排序算法
- 普通的crud,B+树完全可以胜任,但是B+树一定要建立在高基数的列上,比如身份证号、电话号码等
B+树索引
B+树的特征:
- 有k个子树的中间节点包含有k-1个元素,每个元素不保存数据,只用来索引,所有数据都保存在叶子节点
- 所有叶子节点中包含了全部元素信息,及指向含这些元素记录的指针,且叶子节点本身依关键字的大小而自小而大顺序连接
- 所有中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)的元素
m阶B+树插入:
- 若为空树,则创建一个子结点,然后将记录插入其中,此时这个叶子结点也是根结点,插入操作结束
- 针对叶子类型的结点,根据key值找到叶子结点,想这个叶子结点插入记录,插入后,若当前结点key的个数小于等于m-1,则插入结束,否则这个叶子结点分裂成左右两个子结点,左叶子结点包含前m/2个记录,右叶子结点包含剩下的记录,将第m/2+1个记录进位到父结点中(父结点一定是索引类型结点),进位到父结点的key做左孩子指针指向左节点,右孩子指针指向右结点当前结点指针指向父结点,然后执行第三步
- 针对索引类型结点,若当前结点key的个数小于等于m-1,则插入结束;否则该索引类型分裂成两个索引结点,左索引结点包含前m/2个记录,右索引结点包含剩下的记录,将第m/2+1个记录移动到父结点中,进位到父结点的key做左孩子指针指向左节点,右孩子指针指向右结点当前结点指针指向父结点,重复执行直到插入结束
B+树的查找
B+树就是一个排序算法将一组数据排好了顺序,每个父结点右边顺序等于或高于于父结点的顺序,左边都等于或低于父结点的顺序;查找时由父结点开始一层层向子结点比较。效率比一个个比较子结点效率要高的多
正向索引
在对比如数字这样能够轻易排序的类型使用正向索引,创建对应的B+树,在查找时就可以很快的找到对应的列
倒排索引—ES索引
对于全文检索,检索字符串中的某一段字符时,就只能进行模糊查询,索引就失效了。而倒排索引会先对字段进行分词,然后每个分词对应一组document的唯一标识,所有单词存储在一个B+树实现的单词字典中(字典中还存有单词和倒排列表之间的联系,倒排列表包含document的标识);查询时会将查询的内容进行分词,然后通过b+树查询找到对应分词就可以找到对应的ducument,这比mysql模糊查询的全盘查找快得多
ES的安装(docker)
docker search -f stars=100 elasticsearch
docker pull elasticsearch:7.0.0
docker images
检查是否拉取成功- 启动容器:
docker run --name=my_es -d -p9200:9200 -e "discovery.type=single-node" docker.io/elasticsearch:7.0.0
- 配置防火墙:
firewall-cmd --zone=public --add-port=9200/tcp --permanent
、firewall-cmd --reload
- 浏览器敲地址查看是否正常访问
Kibana
kibana是为ES设计的开源分析和可视化平台,可以使用kibana来搜索,查看存储在ES索引中的数据并与之交互
kibana的安装过程和es相同,启动是配置环境变量:docker run --name=kibana -e ELASTICSEARCH_HOSTS=es的地址与端口 -e SERVER_PORT=5601 -e SERVER_HOST=0.0.0.0 -p 5601:5601 -d kibana
ES命令
_cat命令(查看集群状态)
/_cat/allocation
:查看单节点的shard分配整体情况/_cat/shards
:查看各shard的详细情况/_cat/shards/{index}
:查看指定分片的详细情况/_cat/master
:查看master节点的信息/_cat/nodes
:查看所有节点的信息/_cat/indices
:查看集群中所有index的详细信息/_cat/indices/{index}
:查看集群中指定index的详细信息/_cat/segments
:查看各index的segment的详细信息,包括segment名,所属shard,内存(磁盘)占用大小,是否刷盘/_cat/segments/{index}
:查看指定index的segment的详细信息,包括segment名,所属shard,内存(磁盘)占用大小,是否刷盘/_cat/count
:查看当前集群的document数量/_cat/count/{index}
:查看指定索引的document数量/_cat/recovery
:查看集群内每个shard的recovery的过程,调整replica/_cat/recovery/{index}
:查看指定索引shard的recovery过程/_cart/health/
:查看集群当前健康状态,红、黄、绿/_cat/pending_tasks/
:查看当前集群的pending task(等待任务)/_cat/aliases/
:查看集群中所有索引的alias(别名)信息/_cat/aliases/{alias}
:查看指定索引的alias信息/_cat/thread_pool
:查看集群各节点内部不同类型的threadpool的统计信息/_cat/plugins
:查看集群各个节点的插件信息/_cat/fielddata
:查看集群各个节点的fielddata内存使用情况/_cat/fielddata/{fields}
:查看指定field的内存使用情况,里面传field属性对应的值/_cat/nodeattrs
:查看单节点的自定义属性/_cat/repositores
:输出集群中注册快照存储库/_cat/templates
:输出当前正在存在的模板信息
简单的增删改查
增加
- INDEX
PUT 索引名/类型名(统一使用_doc)/id
{
json对
}
- CREATE
PUT 索引名/create/id
{
json对
}
POST 索引名/create (不指定id自动生成)
{
json对
}
两种操作的区别
- create操作如果id已经存在,会失败
- index操作,如果id不存在,会创建新的文档,否则先删除现有文档再创建新的文档,版本会增加
查询
GET /_search{}
:空查询,将返回所有索引库中所有文档信息- 基本查询
GET 索引名/_doc/_search
:查询索引下的全部文档
GET 索引名/_doc/id
:通过id查询文档
GET 索引名
:查看索引信息
GET 索引名/_doc/_search?q=key:value
:简单条件查询 - match_all查询
简单匹配所有文档,在没有指定查询方式时,它是默认的查询;_source表示查询的字段,没有表示查询所有字段;from和size用作分页查询;sort表示按照字段进行排序,asc正序,desc倒序
GET 索引名/_search
{
"_source":["字段1","字段2"],
"query":{
"match_all":{
}
},
"from":0,
"size":2,
"sort":{
"字段":{
"order":"asc/desc"
}
}
}
更新
ES的更新数据可以添加新的字段,这是mysql所不能的
- PUT更新
PUT 索引名/_doc/id
{
json对
}
删除原有的文档并创建新的文档,版本增加
2. POST更新
PUT 索引名/_doc/id
{
json对
}
在原有的文档上更新字段,版本增加
PUT和POST的区别
- 更新:PUT会将新的json值完全替换掉旧的;而POST方式只会更新相同的字段的值,其他数据不会改变,新提交的字段若不存在则增加
- PUT和DELETE操作是幂等的,所谓幂等是指不管进行多少次操作,结果都一样,比如用PUT修改一个文档,然后再做同样的操作,每次操作后结果并没有什么不同,DELETE也是一样
- POST操作不是幂等的,比如常见的POST重复加载问题,多次发出同样的POST请求后,其结果是创建了若干的资源
- 创建操作可以使用POST,也可以使用PUT,区别在于POST作用在一个集合资源之上的,而PUT操作时作用在一个具体资源之上的;即POST是指在_doc基础上创建一个文档,而PUT是指在具体文档的基础上创建它
删除
DELETE 索引名
:删除索引DELETE 索引名/_doc/id
:通过id删除文档
Mapping
概述
ES的Mapping,定义了索引的结构,类似于关系型树库的schema。ES的Setting中定义分片和副本数以及搜索的最关键组件,即Analyzer分词器。
Mapping主要包含以下内容:
1. 定义索引中字段的名称
2. 定义字段的数据类型
3. 可对字段设置倒排索引的相关配置,如是否需要分词,使用什么分词器
从7.x开始,一个Mapping只属于一个索引的type,默认为_doc
每个文档属于一个type
一个type只有一个Mapping定义
从7.x开始,不需要在Mapping中指定type信息,默认type为_doc
Mapping中的字符串类型
- text:类型适用于需要被全文检索的字段,text类型会被Lucene分词器处理为一个个单词,并使用Lucene倒排索引存储,text字段不能被用于排序,如果需要使用该类型的字段只需要定义映射时指定JSON中对应字段的type为text
- keyword:关键字的整体,不会被分词,适合简短,结构化字符串,如主机名、姓名、商品名称,可以用于过滤、排序、联合检索、也可以用于精确查询
Mapping字段类型的指定
Mapping中的字段类型会自动识别,如果输入的JSON是字符串而且格式为日期格式,ES会自动设置成Date类型;当输入的字符串是数字的时候,ES默认也会当成字符串来处理。
如果想要指定字段类型,需要在创建索引时对某个字段的类型进行指定,这样新增的该字段数据就是该类型的;对于已经存在的字段,是不支持修改的,如果希望更改已存在的字段的类型,必须重建索引
指定类型
PUT 索引名
{
"mappings": {
"properties": {
"字段名":{
"type":"类型"
}
}
}
}