Elasticsearch入门(五):Elasticsearch基础概念与基本操作
引子在上一篇博文 Elasticsearch入门(四):使用docker搭建Elasticsearch 7.0.0 集群,安装head插件中,我讲了如何在docker环境下搭建ES集群、安装head插件。接下来本文中,我将讲一些Elasticsearch的基础知识,以及一些基础操作。该文章,我是跟着慕课网的Elasticsearch教程第三、四章节走的。基础概念1、索引(Index...
引子
在上一篇博文 Elasticsearch入门(四):使用docker搭建Elasticsearch 7.0.0 集群,安装head插件中,我讲了如何在docker环境下搭建ES集群、安装head插件。接下来本文中,我将讲一些Elasticsearch的基础知识,以及一些基础操作。
该文章,我是跟着慕课网的Elasticsearch教程第三、四章节走的。
基础概念
1、索引(Index)、类型(Type)、文档(Document)
- 索引是含有相同属性的文档集合。索引在ES中是通过一个名字来识别的,且必须是英文字母小写,且不含中划线(-);可类比于 MySQL 中的 database ;但是,后文会提到,在 7.0中,由于类型(Type)的移除,我们可以理解为,一个索引就是一张 table。
一个索引中可以定义一个或多个类型,文档必须属于一个类型;可类比于 MySQL 中的 table;- 文档是可以被索引的基本数据单位。文档是Elasticsearch中最小的数据存储单位。可类比于 MySQL 中 一个table 中的一行记录。
注意事项:
从ES6.0开始,官方便不建议一个索引中创建多个类型;在ES7.0中,更是移除了类型(Type)这个概念。为什么呢?
在Elasticsearch索引中,不同类型(Type)中具有相同名称的字段在内部由相同的Lucene字段支持。一个index中多个Type在Lucene中会有许多问题。具体的可以参考官方说明。
2、分片、备份
- 在ES中,每个索引都有多个分片,每个分片都是一个Lucene索引。假设一个索引的数据量很大,就会造成硬盘压力很大,同时,搜索速度也会出现瓶颈。我们可以将一个索引分为多个分片,从而分摊压力;分片同时还允许用户进行水平地扩展和拆分,以及分布式的操作,可以提高搜索以及其他操作的效率。
- 拷贝一份分片,就完成了分片的备份。备份的好处是,当一个主分片出现问题时,备份的分片就能代替工作,从而提高了ES的可用性。同时,备份的分片还可以执行搜索操作,以分摊搜索的压力。
ES在创建索引时,默认会创建5个分片,一份备份。这个数量是可以修改的,但是需要注意的是,分片数量只能在创建索引的时候指定,后期不能修改;而备份是可以动态修改的。
3、还有一些其他概念、术语,可以参考官方文档:ES 术语表
基础操作
ES的API组成结构
ES提供了一系列RESTFul风格的API供我们对ES数据进行操作。下面是它的基本格式:
http://<ip>:<port>/<索引>/<类型>/<文档ID>// 从ES 7.0.0开始,移除Type(类型)这个概念http://<ip>:<port>/<索引>/_doc/<文档ID> // Type 字段那里变为固定值 _doc
需要执行的动作,由请求方式决定。下面是常见的请求方式,具体意义后面会详细讲:
GET/POST/PUT/DELETE/HEAD
有了上面这些知识储备,下面我们来看看ES的基本操作:
创建索引
1、第一种方式,直接在head插件上创建索引。
如上图所示,选中 索引 - 新建索引 ;然后在弹出框中输入索引名称,这里我输入的是 book ,点击 “OK” 按钮即可。
如上图所示,概览页也出现了变化。图中的所有方框都是ES索引的分片,边框加粗的就是主分片,而未加粗就是分片的备份;比如:边框不加粗的0号分片就是 0号主分片的备份。
这样创建索引,是进行了一次 非结构化创建。什么意思呢,类比 我们创建一个数据库,但是没有创建任何表、也没有任何表结构。简而言之,就是我们创建了一个没有任何数据结构的索引。
如何确定一个索引是结构化还是非结构化的呢?
如上图,我们点击 概览-信息-索引信息,在弹出的窗口中找到 mappings 项,其值是空的,就代码该索引是非结构化的。那么,如何将其修改为结构化的呢?也就是说,我们需要为book索引构建出数据结构(类比于,为book表构建出表结构)。这里先暂时提一下,后文会详细介绍:
我们在 head 插件上点击 复合查询 - 查询,然后在这个模块中输入图示的信息,勾选 已读 ,然后点击 验证JSON,JSON内容便会格式化为已读的状态;然后点击 提交请求 ,操作成功后,右侧便会显式提示信息,如下图:
此时,我们点击 概览 - 刷新,然后选择 book 索引的 信息 - 索引信息,就可以在弹出窗口中查看到 book 索引的文档数据结构:
如上图所示。这里值得一提的是,在慕课网的教程中,讲师的json请求体是下面这样的:
在上面我已经提到,从ES 7.0.0 开始,Type就被移除了,而讲师录课程时ES的版本还比较低。如果像讲师那样去创建接口,将会得到一个报错:
"type": "illegal_argument_exception",
"reason": "Types cannot be provided in put mapping requests, unless the include_type_name parameter is set to true."
如下图所示:
所以,这里需要大家注意下。在后面的内容中,我将直接使用去掉Type后官方推荐的方式进行操作。
2、第二种方式,使用 PostMan 等第三方HTTP客户,通过ES RestFul API来创建索引。这里,我使用的IntelliJ IDEA的 Http Request工具。大家可以根据自己的习惯,选择合适工具。
如上图,我随便新建了一个项目,选中一个包,右键菜单 - New - New HTTP Request(最后一项)。弹出窗口中,输入http文件名,随便取,我这里命名为 es ——输入 es,点击 OK,文件就创建好并自动打开了。删除里面所有的备注内容。
这里,语法我不讲,多看几个例子,大家就明白了。
首先,我们创建一个新的 people 索引。在es.http文件中输入:
### 创建一个新的 people 索引,注意,将IP替换为你们自己的主机地址
PUT http://10.247.63.97:9200/people
Content-Type: application/json
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"type": {"type": "keyword"},
"name": {"type": "text"},
"country": {"type": "keyword"},
"age": {"type": "integer"},
"date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || epoch_millis"
}
}
}
}
这里,解释一下上面JSON内容的意思:
- settings字段:用于指定我们索引的配置
- number_of_shards:指定当前索引的分片数
- number_of_replicas:指定当前索引的备份数
- mappings字段:指定索引的数据映射定义:
- properties:指定索引的属性定义;这里,这里,定义了 5 个字段,分别为 type、name、country、age、date;需要注意的是,这里的type,这是一个字段,和我们上文中提到的在7.0中移除了的类型(Type)并不是同一个东西;官方推荐我们的是,如果我们有 类型(Type)定义 这个需求,我们可以在字段中自定义一个字段,用来标识当前 document 属于哪个 Type;这里,我们就使用这个名为 “type” 字段(可以按照自己的习惯自定义名称),来标识当前文档属于哪个 Type;
- 后面的 {"type" : "integer"}、{"type" : "text"}分别表示当前字段数据的类型为 整数、文本,以及 关键字(keyword)、日期类型等。
- date字段中,我们可以为其指定匹配多种格式,使用 || 分隔;
如上图所示,我们写好后,可以点击左边 行号 附近的 小三角,发送这个 PUT请求。请求完毕后,若索引创建成功,则会在Run Tool Bar中看到如下输出:
这时,我们再去head插件中确认一下,点击 刷新 按钮,即可看到我们刚刚新创建的people索引:
查看 people 的索引信息,我们可以看到 people 索引存储数据的结构:
数据插入
在ES中,数据插入又分为两种:
- 指定文档ID插入:手动指定ID
- 自动产生文档ID插入:不是MySQL那样的AutoIncrement,而是类似MongoDB那样的自动生成ID
指定文档ID插入:
在刚刚的es.http文件中,使用 ### (三个#号)将请求分隔开,在下面输入:
### 向 people索引中插入一条 指定ID的数据,注意请求方式为 PUT
# 路径格式为 http://<ip>:<port>/<索引>/_doc/<文档ID>,下面我们插入了一条 ID 为 1 的数据
PUT http://10.247.63.97:9200/people/_doc/1
Content-Type: application/json
{
"type": "man",
"name": "Zereao",
"country": "China",
"age": "23",
"date": "1995-11-27"
}
然后执行,可以看到下面的输出:
自动生成ID插入:
### 向 people索引中插入一条 自动生成ID的数据,注意,请求方式为 POST,并删除URL末尾的 ID
POST http://10.247.63.97:9200/people/_doc/
Content-Type: application/json
{
"type": "man",
"name": "AutoZereao",
"country": "China",
"age": "23",
"date": "1995-11-27 12:25:35"
}
输出结构这里我就不贴了。上面我们分别插入了两条数据,一条是手动指定ID,PUT请求方式;一条是自动生成ID,POST请求方式。我们可以从Head插件上查看到我们刚刚插入的数据:点击 数据浏览,选中 people索引,即可查看数据:
数据修改
数据修改也分为两种方式:
- 直接修改文档
- 通过脚本修改文档
直接修改文档:
### 修改 ID 为 1 的文档的 name 字段值为 UpdateZereao,格式:{index}/_update/{id}
POST http://10.247.63.97:9200/people/_update/1/
Content-Type: application/json
{
"doc": {
"name": "UpdateZereao"
}
}
运行后,我们可以通过Head插件查看更改,点击 更新 后,我们可以看到数据:
这里额外补充一下,最开始,我按照教程,上面我填写的URL是 http://10.247.63.97:9200/people/_doc/1/_update/ ;结果我运行执行更新的时候,得到了这样一条输出:
Warning: 299 Elasticsearch-7.0.0-b7e28a7 "[types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead."
也就是这种请求方式已经过时了,同时提示也给出了新的推荐的请求方式。我们在实际操作过程中,也要注意一些输出,尽量不要使用一些过时的操作。
通过脚本修改文档:
这里我不讲,有需求的同学还请自行百度。
删除操作
这里呢,我主要讲两个删除操作:
- 1、文档删除
- 2、索引删除
删除people索引中,ID为1的文档:
### 删除 people索引中 ID = 1 的文档
DELETE http://10.247.63.97:9200/people/_doc/1/
Content-Type: application/json
输出结果这里我就不贴了,可以打开head插件,刷新数据后,我们便可以看到,people 索引中ID为1的文档已经被删除成功了。
删除索引:
这里,有两种方式。第一种是,我们可以通过 head 插件进行删除。
如上图,我们点击 概览 - 动作 - 删除,在弹出窗口中输入 “删除” 两个字,然后点击确定,即可将 book 索引删除。
第二种方式,通过RestFul API:
### 删除 people 索引
DELETE http://10.247.63.97:9200/people
Content-Type: application/json
点击运行,我们就可以将 people 索引删除掉。删除成功后,我们可以从 head 插件中看到索引已经被删除了。
需要注意的是,删除一个索引后,该索引下的所有数据,包括所有类型和文档,都会被删除。对于删除操作,我们要万分小心。
查询操作
ES的查询可以分为简单查询、条件查询、聚合查询。
首先,我们先造一批数据。首先新建一个 book 索引,然后指定ID插入多条文档。具体语句这里不给出,在文末的附件中的es_book.http文件中,我会给出我插入数据的语句,总共插入了12条文档记录。有需要的同学可以去下载。
简单查询:
### 简单查询,查询 book 索引中,ID为1 的文档
GET http://10.247.63.97:9200/book/_doc/1
Content-Type: application/json
查询结果如图:
条件查询:
查询book索引中的所有数据:
### 条件查询,查询所有数据
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"query": {
"match_all": {}
}
}
这里,查询结果我就不贴出来了。值得一提的是,最外层的hits 字段下就是我们查出来的数据;hits字段下的total字段代表记录总条数;hits字段下还有一个 hits json数组,这就是查出的每一条记录的详情。默认情况下,只查出10条,hits json数组的大小为10,这个我们可以通过 from 、size 属性手动指定返回哪些数据:
### 条件查询,指定返回数据大小以及从哪里开始返回
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"query": {
"match_all": {}
},
"from": 1,
"size": 1
}
关键词匹配:
### 条件查询,查询标题中包含 传 字的文档
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"query": {
"match": {
"title": "传"
}
}
}
这里,将会查出两条数据。默认情况下,查询出的结果 hits json数组中的数据,是按照_score字段的值大小倒序排序的。我们也可以指定排序方式:
### 条件查询,指定排序方式为 按照 publish_date 降序 排序
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"query": {
"match": {
"title": "传"
}
},
"sort": [
{
"publish_date": {
"order": "desc"
}
}
]
}
聚合查询:
单个分组聚合:
### 聚合查询,按照 这一批 book 的字数进行聚合; 这是一个单个分组聚合
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"aggs": {
"group_by_word_count": {
"terms": {
"field": "word_count"
}
}
}
}
注意,上面的 group_by_word_count 表示该聚合的名称,是自定义的,可以自己为该聚合命名。
多个分组聚合:
### 聚合查询,按照 这一批 book 的字数和出版日期进行聚合; 这是一个多个分组聚合
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"aggs": {
"group_by_word_count": {
"terms": {
"field": "word_count"
}
},
"group_by_publish_date": {
"terms": {
"field": "publish_date"
}
}
}
}
计算某一字段的数据:
### 聚合查询,计算 word_count 字段的相关数据
POST http://10.247.63.97:9200/book/_search
Content-Type: application/json
{
"aggs": {
"grades_word_count": {
"stats": {
"field": "word_count"
}
}
}
}
这里,grades_word_count也是可以自定义的,stats表示对字段值进行计算。执行后,我们可以得到一段这样的数据:
如图,上面计算除了 word_count 字段的 最大值、最小值、均值、数量、总和等数据。
至此,我们Elasticsearch基础概念与基本操作就介绍完毕了。
附件信息
本文中使用到的所有http请求信息包含 es.http和 es_book.http:点我下载资源
参考文档
1、https://www.imooc.com/learn/889
2、https://www.elastic.co/guide/en/elasticsearch/reference/current/glossary.html
3、https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html
4、https://blog.csdn.net/zyc88888/article/details/83027458
更多推荐
所有评论(0)