以下内容基于Elasticsearch 7.10,使用Kibana进行交互,只演示一些基本操作,其它操作或者更复杂操作的请阅读官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html
一、基本概念
在Elasticsearch中,一条数据就是一个文档(json格式)。每个文档都有与之关联的元数据,例如_index(文档所属的索引)、_type(文档的映射类型)和_id(文档编号)三个必须的元数据字段,当然在7.x版本中_type已经被弃用,它不在是创建索引时必须的了。
可以说ES算是面向文档型的非关系型数据库,当然它本身也是排名前十最流行的数据库管理系统之一,目前排在第8(数据来源:https://db-engines.com/en/ranking)。
最初,它们的结构:索引(index) ⇒ 类型(type) ⇒ 文档(docments) ⇒ 字段(fields),我们可以类比为关系型数据库:库 ⇒ 表 ⇒ 行 ⇒ 列。不过这并不是一个恰当的类比,但是为了帮助更好理解,我们先可以这样类比理解。在5.x版本中我们可以这样理解,6.x版本每个索引只允许使用一种类型,7.x版本中已经弃用。详细了解_type可以阅读:Elasticsearch 映射类型的变迁史
二、索引是什么
Elasticsearch 索引指相互关联的文档集合。Elasticsearch 会以 JSON 文档的形式存储数据。每个文档都会在一组键(字段或属性的名称)和它们对应的值(字符串、数字、布尔值、日期、数值组、地理位置或其他类型的数据)之间建立联系。
Elasticsearch 使用的是一种名为倒排索引的数据结构,这一结构的设计可以支持十分快速地进行全文搜索。倒排索引会列出在所有文档中出现的每个特有单词,并且可以找到包含每个单词的全部文档。通俗的来说倒排索引就是通过单词去找文档,像我们在购物网站上用各种条件筛选那就是,通过特定关键词去找包含关键词的商品。
三、创建索引
PUT /student
#获取索引信息
GET /student
在创建索引时,我们还可以指定索引设置、索引中字段的映射、索引别名。
1、设置分片和副本数量
分片和副本默认都为1。
PUT /my-index-1
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
#获取索引设置
GET /my-index-1/_settings
#获取索引指定设置
GET /my-index-1/_settings/*shard*
2、字段映射
在7.x之前,映射定义是包含在类型下,尽管现在不建议在请求中指定类型,但是如果需求,可以在请求中设置了参数include_type_name为true。
PUT /my-index-2
{
"mappings": {
"properties": {
"name" : { "type" : "keyword" },
"content": { "type": "text" },
"date" : { "type" : "date" }
}
}
}
#获取索引映射
GET /my-index-2/_mappings
#获取索引指定字段映射
GET /my-index-2/_mapping/field/content
GET /my-index-2/_mapping/field/name,date
GET /my-index-2/_mapping/field/n*
3、索引别名
PUT /my-index-3
{
"aliases": {
"alias_1": { }
}
}
#获取索引别名
GET /my-index-3/_alias
#通过别名获取索引信息(多个索引可以用一个别名)
GET /alias_1/_mapping
四、增
将JSON文档添加到指定索引中,如果文档已经存在,则请求将更新文档并增加其版本。
语法:
PUT /<target>/_doc/<_id>
POST /<target>/_doc/
1、自定义id
如果请求的索引不存在,将会自动创建该索引。
PUT /student/_doc/1
{
"name" : "xm",
"sex" : "male",
"age" : "18",
"hobby": [
"swimming",
"basketball"
]
}
结果:
{
"_index" : "student",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
2、随机id
对于随机id,我们需要使用POST,会为文档生成唯一的ID。
POST /student/_doc
{
"name" : "xh",
"sex" : "female",
"age" : "18",
"hobby": [
"swimming",
"yoga"
]
}
结果:
{
"_index" : "student",
"_type" : "_doc",
"_id" : "aTMmMnYBddrAqZGb1UsI",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
3、批量
如果有很多要存入索引的文档,则可以使用 bulk API 批量提交。使用批量处理文档操作比单独一个个提交要快得多,因为它可以最大程度地减少网络往返次数。
POST _bulk
{ "index" : { "_index" : "test1", "_id" : "1" } }
{ "name" : "test1" }
{ "index" : { "_index" : "test2", "_id" : "1" } }
{ "name" : "test2" }
4、获取文档数据
#查询索引所有数据
GET student/_search
#查询索引指定id的数据
GET /student/_doc/1
#查询索引指定id的文档源数据(不含其它信息,只有源数据)
GET /student/_source/1
输出信息解释
#GET student/_search
{
"took" : 0, # 查询时长(以毫秒为单位)
"timed_out" : false, # 搜索请求是否超时
"_shards" : { # 包含搜索了多少个分片,以及搜索成功、失败和跳过了多少个分片
"total" : 1, # 需要查询的分片总数
"successful" : 1, # 成功执行请求的分片数
"skipped" : 0, # 跳过请求的分片数
"failed" : 0 # 未能执行请求的分片数
},
"hits" : {
"total" : {
"value" : 2, # 找到了多少个匹配的文档
"relation" : "eq"
},
"max_score" : 1.0, # 找到相关文档的最大搜索评分
"hits" : [ # 包含文档内容
......省略
]
}
}
五、删
1、删除索引
DELETE /my-index-1
2、删除索引别名
DELETE /my-index-3/_alias/alias_1
3、删除索引指定文档
DELETE /student/_doc/1
4、通过查询删除
POST /student/_delete_by_query
{
"query": {
"match": {
"name": "xh"
}
}
}
六、改
1、为文档建立一个索引用于测试
PUT /test/_doc/1
{
"name" : "xm",
"sex" : "male",
"age" : "18"
}
2、更改name为xh
POST /test/_update/1
{
"doc": {
"name": "xh"
}
}
3、增加一个hobby字段
POST /test/_update/1
{
"doc": {
"hobby": [
"swimming",
"yoga"
]
}
}
4、通过查询进行更改
(1)将所有年龄为18的学生改成年龄为20
POST /test/_update_by_query
{
"script": {
"source": "ctx._source['age']='20'",
"lang": "painless"
},
"query": {
"term": {
"age": "20"
}
}
}
(2)将名字为xh的学生年龄改为18
POST /test/_update_by_query
{
"script": {
"source": "ctx._source['age']='20'",
"lang": "painless"
},
"query": {
"term": {
"name": "xh"
}
}
}
七、查
1、term和match
term搜索数据时为完全匹配不进行分词,适用于精确查询。match搜索时会进行分词。
GET /student/_search
{
"query": {
"term": {
"name": "xm"
}
}
}
GET /student/_search
{
"query": {
"match": {
"name": "xm"
}
}
}
我们可以实验下
PUT /tweet/_doc/1
{
"content" : "hello world"
}
PUT /tweet/_doc/2
{
"content" : "hello"
}
PUT /tweet/_doc/3
{
"content" : "world"
}
分别用term和match搜索“content=hello”,再分别搜索“content=hello world”
当条件为“content=hello”:
因为是单个单词,无论是term还是match,搜索结果为包含hello数据全部搜索出来。
当条件为“content=hello world”:
term,执行无数据。match,三条数据全部出来了,即match将“hello world“,进行了拆分再检索匹配。
对于拆分我们可以查询拆成了那几个单词,从结果来看拆分成了hello和world两个单词。即match会将“hello world”,拆分成了hello和world两个单词,然后再检索匹配这两个单词。那么意思就是从content字段中查询包含hello或者world的文档。
GET /tweet/_analyze
{
"text" : "hello world"
}
如果只想匹配到“hello world”这条短语呢?这就要用到match_phrase,它用来匹配短语。
GET /tweet/_search
{
"query": {
"match_phrase": {
"content" : "hello world"
}
}
}
2、bool查询
要实现更复杂的查询,可以使用bool查询来组合多个查询条件。
主要参数:
• must:文档必须全部满足这些查询条件。
• must_not:文档必须全部不满足这些查询条件。
• should:文档满足其中一个条件即可。
• filter:过滤搜索结果,文档必须都满足过滤条件才会展示出来。
3、must
查询年龄为18并且爱好为瑜伽的学生信息。
GET /student/_search
{
"query": {
"bool": {
"must": [
{ "term": { "age": "18"}},
{ "term": { "hobby": "yoga"}}
]
}
}
}
4、must_not
查询性别不为女生并且爱好要有游泳的学生信息。
GET /student/_search
{
"query": {
"bool": {
"must_not": [
{ "term": { "sex": "female" }}
],
"must": [
{ "term": { "hobby": "swimming"}}
]
}
}
}
5、should
查询爱好为游泳或者瑜伽的学生信息。
GET /student/_search
{
"query": {
"bool": {
"should": [
{ "term": { "hobby": "swimming"}},
{ "term": { "hobby": "yoga"}}
]
}
}
}
6、filter
查询爱好为swimming和yoga的学生信息。
GET /student/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "hobby": "swimming" }},
{ "term": { "hobby": "yoga" }}
]
}
}
}