ElasticSearch 入门教程 - 基础篇之一

大纲

版本说明

软件版本描述
ElasticSearch7.4.2ElasticSearch 的版本
Curl7.29.0Curl 的版本

ElasticSearch 介绍

ElasticSearch 概述

ElasticSearch 是基于 RESTful 标准的高扩展高可用的实时数据分析的全文搜索工具。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。ElasticSearch 是在 Lucene 的基础上用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。Elasticsearch 在云计算中,拥有实时搜索、稳定、可靠、快速、安装使用方便等优势。构建在全文检索开源软件 Lucene 之上的 Elasticsearch,不仅能对海量规模的数据完成分布式索引与检索,还能提供数据聚合分析的功能。

ElasticSearch 基础概念

  • Index - 类似于 MySQL 数据库中的 database
  • Type - 类似于 MySQL 数据库中的 table,ES 中可以在 Index 中建立 Type,通过 Mapping 进行映射
  • Document - 由于 ES 存储的数据是文档类型的,一条数据对应一个文档,相当于 MySQL 数据库中的一行数据 row
  • Field - ES 中一个文档中可以有多个字段,相当于 MySQL 数据库一行可以有多列
  • Mapping - 可以理解为 MySQL 或者 Solr 中对应的 schema,只不过有些时候 ES 中的 Mapping 增加了动态识别功能,实际生产环境上不建议使用,最好还是开始就制定好了对应的 schema
  • Indexed - 名义上的索引建立,MySQL 中一般会对经常使用的列增加相应的索引用于提高查询速度,而在 ES 中默认都是会加上索引的,除非特殊制定不建立索引只是进行存储用于展示,这个需要根据具体的需求和业务进行设定
  • Query DSL - 类似于 MySQL 的 SQL 语句,只不过在 ES 中是使用的 JSON 格式的查询语句,即 QueryDSL

值得一提的是,从 ES 7 及以上版本开始,Type 的概念已经被官方移除。

提示

ElasticSearch 基本架构

elasticsearch-architecture

  • Gateway 层:ES 用来存储索引文件的一个文件系统且它支持很多类型,例如:本地磁盘、共享存储(做 Snapshot 的时候需要用到)、Hadoop 的 HDFS 分布式存储、亚马逊的 S3。它的主要职责是用来对数据进行长持久化以及整个集群重启之后可以通过 Gateway 重新恢复数据。
  • Distributed Lucene Directory:Gateway 上层就是一个 Lucene 的分布式框架,Lucene 是做检索的,但是它是一个单机的搜索引擎,像这种 ES 分布式搜索引擎系统,虽然底层用 Lucene,但是需要在每个节点上都运行 Lucene 进行相应的索引、查询以及更新,所以需要做成一个分布式的运行框架来满足业务的需要。
  • 四大模块组件:Districted Lucene Directory 之上就是一些 ES 的模块,Index Module 是索引模块,就是对数据建立索引也就是通常所说的建立一些倒排索引等;Search Module 是搜索模块,就是对数据进行查询搜索;Mapping 模块是数据映射与解析模块,就是你的数据的每个字段可以根据你建立的表结构通过 Mapping 进行映射解析,如果没有建立表结构,ES 就会根据数据类型推测数据结构之后自己生成一个 Mapping,然后都是根据这个 Mapping 进行解析数据;River 模块在 ES2.0 之后应该是被取消了,它的意思表示是第三方插件,例如可以通过一些自定义的脚本将传统的数据库(MySQL)等数据源通过格式化转换后直接同步到 ES 集群里,这个 River 大部分是自己写的,写出来的东西质量参差不齐,将这些东西集成到 ES 中会引发很多内部 Bug,严重影响了 ES 的正常应用,所以在 ES2.0 之后考虑将其去掉。
  • Discovery、Scripting:ES 四大模块组件之上有 Discovery 模块:ES 是一个集群包含很多节点,很多节点需要互相发现对方,然后组成一个集群包括选主的,这些 ES 都是用的 Discovery 模块,默认使用的是 Zen,也可是使用 EC2;ES 查询还可以支撑多种 Script 即脚本语言,包括 Mvel、JS、Python 等。
  • Transport 协议层:再上一层就是 ES 的通讯接口 Transport,支持的也比较多:Thrift、Memcached 以及 Http,默认的是 Http,JMX 就是 Java 的一个远程监控管理框架,因为 ES 是通过 Java 实现的。
  • RESTful 接口层:最上层就是 ES 暴露出来的访问接口,官方推荐的方案就是这种 RESTful 接口,直接发送 Http 请求,方便后续使用 Nginx 做代理、分发包括可能后续会做权限的管理,通过 Http 很容易做这方面的管理。如果使用 Java 客户端它是直接调用 Api,在做负载均衡以及权限管理还是不太好做。

ElasticSearch 基础检索操作

节点检索操作

  • 查看 ES 的所有节点
1
curl -X GET http://127.0.0.1:9200/_cat/nodes
  • 查看 ES 的健康状况
1
curl -X GET http://127.0.0.1:9200/_cat/health
  • 查看 ES 的主节点
1
curl -X GET http://127.0.0.1:9200/_cat/master
  • 查看 ES 的所有索引
1
curl -X GET http://127.0.0.1:9200/_cat/indices

数据新增操作

往 ES 新增一条数据,需要说明新增在哪个索引的哪个类型下,指定用哪个唯一标识(可选)。例如,下面的命令都是在 customer 索引下的 external 类型下新增数据。

  • POST 可以是新增操作,也可以是更新操作。如果不指定 ID,会自动生成 ID,即永远是新增操作。如果指定 ID,且该 ID 对应的数据已存在,则会更新这条数据,并递增版本号
1
2
3
4
5
# Post 操作,不指定 ID
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external -d '{"name": "Jim"}'

# Post 操作,指定 ID
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim"}'
  • PUT 可以是新增操作,也可以是更新操作,但必须指定 ID。由于 PUT 需要指定 ID,一般都用来做更新操作,不指定 ID 会报错
1
2
# PUT 操作,必须指定 ID
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim"}'

提示

  • 往 ES 新增数据时,可以使用 POST,也可以使用 PUT
  • 无论是 POST 还是 PUT 操作,只要 ID 对应的数据不存在,第一次执行就是新增操作,第二次执行就是更新操作

数据查询操作

从 ES 查询一条数据,需要说明在哪个索引的哪个类型下,指定用哪个唯一标识来查询。

  • 查询在 customer 索引下的 external 类型下的 2 号数据
1
curl -X GET -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2
  • 返回的 JSON 结果
1
2
3
4
5
6
7
8
9
10
11
12
{
"_index": "customer", // 在哪个索引下
"_type": "external", // 在哪个类型下
"_id": "1", // 唯一标识
"_version": 12, // 版本号
"_seq_no": 1, // 并发控制字段,每次更新都会递增一,用来做乐观锁
"_primary_term": 1, // 同上,控制主分片重新分配,如重启,就会变化
"found": true,
"_source": { // 真正的数据内容
"name": "Jim"
}
}
  • 多线程并发更新数据时,需要携带 if_seq_noif_primary_term 参数来更新
1
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2?if_seq_no=1&if_primary_term=1 -d '{"name": "Jim"}'

数据更新操作

第一种更新方式

  • 使用 POST 操作,并结合 _update 路径一起使用,此方式会对比原始的数据,如果与原始数据一样,则什么都不会做,_version_seq_no 也都不会改变
1
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2/_update -d '{"doc": {"name": "Jim"}}'

特别注意

POST 操作结合 _update 路径一起使用时,更新的 JSON 数据必须包裹在 doc 字段内,例如:{"doc": {"name": "Jim"}}

第二种更新方式

  • 使用 POST 操作,总会将数据重新保存,并递增 version 版本号
1
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim"}'

第三种更新方式

  • 使用 PUT 操作,总会将数据重新保存,并递增 version 版本号
1
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim"}'

三种更新方式的使用场景

  • 对于高并发的更新,建议使用第二或者第三种方式(不带 _update 路径)
  • 对于高并发的查询,且偶尔更新的操作,建议使用第一种方式(带 _update 路径)

提示

上述三种方式,都支持在更新数据的同时,增加字段属性,如下所示:

1
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2/_update -d '{"doc": {"name": "Jim", "age": 18}}'
1
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim", "age": 18}'
1
curl -X PUT -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2 -d '{"name": "Jim", "age": 18}'

数据删除操作

  • 删除指定的数据
1
curl -X DELETE -H "Content-Type: application/json" http://127.0.0.1:9200/customer/external/2
  • 删除指定的索引(数据库)
1
curl -X DELETE -H "Content-Type: application/json" http://127.0.0.1:9200/customer

提示

ElasticSerach 不支持删除指定的类型(数据库表)。

Bulk 批量 API

Bulk API 以此按顺序执行所有的 Action(动作)。如果单个的动作因任何原因而失败,它将继续处理它后面剩余的动作。当 Bulk API 返回执行结果时,它将提供每个动作的状态(与发送的顺序相同),所以可以根据返回结果检测某个动作是不是执行成功。

语法格式

1
2
3
4
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n

批量新增操作的案例

  • 创建 JSON 数据文件(例如 data.json),这里 JSON 数据的末尾必须要有一行空行
1
2
3
4
5
{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"Jane Doe"}

  • 使用 Curl 命令并通过 --data-binary 参数指定 JSON 数据文件,这里的文件名必须以 @ 开头,否则加载数据文件时会造成空行被忽略
1
curl -X POST -H 'Content-Type:application/json' http://127.0.0.1:9200/customer/external/_bulk --data-binary @data.json

特别注意

  • JSON 数据必须以一行空行结束,否则 ES 无法正常解析请求参数
  • 使用 CURL 命令加载 JSON 数据文件时,往往会忽略文件末尾的空行,解决方法可以参考 这里

批量复杂操作的案例

  • 创建 JSON 数据文件(例如 data.json
1
2
3
4
5
6
7
8
{"delete":{"_index":"website","_type":"blog","_id":"123"}}
{"create":{"_index":"website","_type":"blog","_id":"123"}}
{"title":"My first blog post"}
{"index":{"_index":"website","_type":"blog"}}
{"title":"My second blog post"}
{"update":{"_index":"website","_type":"blog","_id":"123"}}
{"doc":{"title":"My updated blog post"}}

  • 使用 Curl 命令发送批量操作的请求,这里的 URL 路径并没有直接指定 ES 的索引和类型
1
curl -X POST -H 'Content-Type:application/json' http://127.0.0.1:9200/_bulk --data-binary @data.json

ElasticSearch 文档资源