引子

在上一篇博文 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

5、https://elasticsearch.cn/article/601

6、https://www.cnblogs.com/huangfox/p/9460361.html

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐