ElasticSearch——Rest 风格操作索引、映射及文档

208 阅读12分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

ElasticSearch提供了一个REST API,通过HTTP通过JSON访问。

1、索引操作

1、索引的基本操作:

PUT /索引名      创建索引
DELETE /索引名   删除索引
DELETE /*       删除全部索引
GET /索引名      查看指定索引信息
GET /_cat/indices?v  查看全部索引信息,v表示查看表头信息

创建索引

命令:PUT /索引名,索引名不能出现大写字母

在这里插入图片描述

在创建索引时还可以指定配置信息:

在这里插入图片描述

查看全部索引信息

命令:GET /_cat/indices?v

在这里插入图片描述

命令:GET /索引名 ,查看指定索引信息

删除索引

删除某个所有,命令:DELETE /索引名

删除所有索引,命令:DELETE /*

2、映射操作

映射是存储在索引中的文档的大纲。它定义数据类型。

字段数据类型

核心类型

  • 字符串类型 string,text,keyword
  • 整数类型 integer,long,short,byte
  • 浮点类型 double,float,half_float,scaled_float
  • 逻辑类型 boolean
  • 日期类型 date
  • 范围类型 range
  • 二进制类型 binary

复合类型

  • 数组类型 array
  • 对象类型 object
  • 嵌套类型 nested
  • 地理类型 地理坐标类型 geo_point
  • 地理地图 geo_shape

特殊类型

  • IP类型 ip
  • 范围类型 completion
  • 令牌计数类型 token_count
  • 附件类型 attachment
  • 抽取类型 percolator

创建映射

创建过程如下:

在这里插入图片描述

创建完成后通过 GET /ems 命令查看ems索引的信息:可以查看到映射信息和配置信息

在这里插入图片描述

如果指向查看映射信息,就输入 GET /ems/_mapping 命令:

在这里插入图片描述

如果我们没有指定映射,那么ElasticSearch 会默认帮我们指定字段类型。

3、操作文档

3.1、文档的基本操作

ElasticSearch 提供Rest API 的增删改查操作说明:当使用特定映射对相应索引发出请求时,它有助于在索引中添加或更新JSON文档

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id通过文档id查询文档
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

创建文档(指定文档id)

启动ElasticSearch、elasticsearch-head 和 Kibana。

1、创建一个文档,并指定文档id为1

在这里插入图片描述

自动创建索引:当请求将JSON对象添加到特定索引时,如果该索引不存在,那么会自动创建该索引以及该特定JSON对象的基础映射。

版本控制: 内部版本控制是以1开头的默认版本,每次更新都会增加,包括删除。

版本控制是一个实时过程,它不受实时搜索操作的影响。

操作类型:操作类型用于强制创建操作,这有助于避免覆盖现有文档。

2、查看创建的文档及索引

在这里插入图片描述

创建文档(随机文档id)

当在索引操作中未指定id时,Elasticsearch自动为文档生成id。

在这里插入图片描述

查看文档数据

API通过对特定文档执行get请求来帮助提取JSON对象。

命令:GET /索引/类型/文档id

在这里插入图片描述

这个操作是实时的,不受索引刷新率的影响。

还可以指定版本,然后 ElasticSearch 将仅提取该版本的文档。

还可以在请求中指定_all,以便 ElasticSearch 可以在每种类型中搜索该文档id,并且它将返回第一个匹配的文档。

还可以从该特定文档的结果中指定所需的字段。

根据规则查询文档信息

如,查看text1索引下type1类型,name带有”万里“的文档信息:

命令:GET /text1/type1/_search?q=name:万里

在这里插入图片描述

删除文档

可以通过向**ElasticSearch **发送HTTP DELETE请求来删除指定的索引,映射或文档。

在这里插入图片描述

可以看到id为1的文档已经被删除:

在这里插入图片描述

修改文档

在ems索引中创建一条文档:

在这里插入图片描述

修改方式一

在创建文档命令中直接修改值,然后再次运行:

在这里插入图片描述

修改方式二(推荐使用)

使用post请求修改,保留原始数据的基础上进行更新,"doc"会先查询出原始文档的数据,然后拿doc里面的新字段来替换原始文档里的字段

修改后,查看修改后的文档信息:

在这里插入图片描述

使用post请求修改,不保留原始数据

修改后,查看修改后的文档信息:可以看到文档中只剩下name字段了

在这里插入图片描述

3.2、文档的复杂查询操作

3.2.1、环境搭建

添加四条文档数据

PUT /wanli/user/1
{
  "name":"万里顾一程",
  "age":"3",
  "desc":"高级Java开发工程师",
  "tags":["技术宅","钻研","运动"]
}


PUT /wanli/user/2
{
  "name":"万里",
  "age":"18",
  "desc":"初级Java开发工程师",
  "tags":["技术宅","直男","运动"]
}


PUT /wanli/user/3
{
  "name":"神明",
  "age":"6",
  "desc":"ELK工程师",
  "tags":["游戏","音乐","腼腆"]
}


PUT /wanli/user/4
{
  "name":"方唐镜",
  "age":"12",
  "desc":"数据库管理员",
  "tags":["诚实","踏实","热心"]
}

3.2.2、指定字段搜索

请求语句:

#在wanli索引的user类型中查询name 包含"万里"的文档
GET /wanli/user/_search
{
  "query":{
    "match": {
      "name": "万里"
    }
  }
}

返回结果:

{
  "took" : 23,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2, #匹配到的文档总数
      "relation" : "eq"
    },
    "max_score" : 1.605183,  #最大分数,最符合结果的文档,从而优先显示
    "hits" : [
      {
        "_index" : "wanli", #索引
        "_type" : "user", #类型
        "_id" : "2", #文档id
        "_score" : 1.605183,  #分数
        "_source" : {   #文档数据,可以遍历出来
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.0892314,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        }
      }
    ]
  }
}

返回结果说明:

  • took:执行整个搜索请求耗费了多少毫秒

  • timed_out :查询是否超时。

  • _shards :在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。

  • max_score:与查询所匹配文档的 _score 的最大值。

  • hits:返回结果中最重要的部分是 hits ,它 包含 total 字段来表示匹配到的文档总数

  • hits数组:一个 hits 数组包含所查询结果的前十个文档。在 hits 数组中每个结果包含文档的 _index 、 _type 、 _id ,加上 _source (文档数据)。这意味着我们可以直接从返回的搜索结果中使用整个文档。

  • _score :每个结果还有一个 _score ,它衡量了文档与查询的匹配程度。分数越大,匹配度越高,越先显示。

在_source 中返回指定字段(结果过滤)

请求语句:

GET /wanli/user/_search
{
  "query":{
    "match": {
      "name": "万里"
    }
  },
  "_source":["name","desc"]
}

返回结果:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.605183,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.605183,
        "_source" : {
          "name" : "万里",
          "desc" : "初级Java开发工程师"
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.0892314,
        "_source" : {
          "name" : "万里顾一程",
          "desc" : "高级Java开发工程师"
        }
      }
    ]
  }
}

3.2.3、排序

请求语句:

#在wanli索引的user类型中查询name 包含"万里"的文档 ,并按年龄排序
GET /wanli/user/_search
{
  "query":{
    "match": {
      "name":"万里"
    }
  },
  "sort": [
    { 
    "age.keyword": { 
      "order":"desc" 
     }
   }
 ],
  "from": 0,
  "size": 1
}

返回结果:排序不会显示分数 _score

{
  "took" : 13,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        },
        "sort" : [
          "3"
        ]
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        },
        "sort" : [
          "18"
        ]
      }
    ]
  }
}

3.3.4、分页

请求语句:

#在wanli索引的user类型中查询name 包含"万里"的文档 ,按年龄排序,并进行分页,每页显示一条数据
GET /wanli/user/_search
{
  "query":{
    "match": {
      "name":"万里"
    }
  },
  "sort": [
    { 
    "age.keyword": { 
      "order":"desc" 
     }
   }
 ],
  "from": 0, #从第1条数据开始
  "size": 1  #只显示一条数据
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        },
        "sort" : [
          "3"
        ]
      }
    ]
  }
}

3.3.5、bool布尔值查询

must :所有的条件都要符合(and)

在 wanli 索引的 user 类型中查询 name 包含"万里",并且年龄为18 的文档信息

GET /wanli/user/_search
{
  "query":{
    "bool": {
      "must": [  #must :所有的条件都要符合(and)
        {
          "match": {
            "name": "万里"
            }
          },
          {
            "match":{
              "age": 18
            }
        }
      ]
    }
  }
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.809156,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 2.809156,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        }
      }
    ]
  }
}

should:只要符合一个条件即可被查询(or)

在 wanli 索引的 user 类型中查询 name 包含"万里",或者年龄为3 的文档信息

GET /wanli/user/_search
{
  "query":{
    "bool": {
      "should": [
        {
          "match": {
            "name": "万里"
            }
          },
          {
            "match":{
              "age": 3
            }
        }
      ]
    }
  }
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 2.2932043,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 2.2932043,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.605183,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        }
      }
    ]
  }
}

must_not :查询出不符合条件的文档(not)

在 wanli 索引的 user 类型中查询 name 不包含"万里"的文档信息

GET /wanli/user/_search
{
  "query":{
    "bool": {
      "must_not": [
        {
          "match": {
            "name": "万里"
            }
          }
      ]
    }
  }
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "name" : "神明",
          "age" : "6",
          "desc" : "ELK工程师",
          "tags" : [
            "游戏",
            "音乐",
            "腼腆"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "4",
        "_score" : 0.0,
        "_source" : {
          "name" : "方唐镜",
          "age" : "12",
          "desc" : "数据库管理员",
          "tags" : [
            "诚实",
            "踏实",
            "热心"
          ]
        }
      }
    ]
  }
}

3.3.6、范围查询

在 wanli 索引的 user 类型中查询 name 包含"万里",并且年龄大于10岁的文档信息

GET /wanli/user/_search
{
       "query": {
         "bool": {
           "must": [
             {
               "match": {
                 "name.keyword": "万里"
               }
             }
           ],
           "filter": {
             "range": {
               "age.keyword": {
                 "gt": 10          
               }
             }
           }
         }
    }
}
  • gte 大于和等于

  • gt 大于

  • lte 小于和等于

  • lt 小于

返回结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.2039728,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.2039728,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        }
      }
    ]
  }
}

3.3.7、匹配多个条件查询

请求语句:

#查询标签中带有 “男” 和 “技术” 的文档信息
GET /wanli/user/_search
{
  "query" :{
    "match":{
      "tags": "男 技术"  #中间空格隔开
    }
  }
}

返回结果:根据结果看出,越符合条件的查询结果分数越高

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 2.511242,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 2.511242,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.3440006,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        }
      }
    ]
  }
}

3.3.8、完全匹配查询

term:代表完全匹配,也就是精确查询,搜索前不会再对搜索词进行分词拆解。

term 只能完完整整的匹配搜索词,不做任何改变的匹配。

创建一个映射:

PUT testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "desc":{
        "type": "keyword"
      },
    }
  }
}

上面映射中指定 name 字段为 text 类型,desc 字段为 keyword 类型。

text 会被分词器解析,keyword不会被分词器解析。

添加文档数据:

PUT testdb/_doc/1
{
  "name":"万里顾一程",
  "desc":"当那一天真的来临"
}

PUT testdb/_doc/2
{
  "name":"万里顾一程",
  "desc":"当那一天真的真的来临"
}

使用 term查询 name字段:

GET testdb/_search
{
  "query": {
    "term": {
        "name": "万"
    }
  }
}

返回结果:返回两条结果,因为name字段类型是text类型,分词器对name字段进行分词解析,把name中含有“万”的结果都返回了。

{
  "took" : 1086,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.18232156,
    "hits" : [
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "万里顾一程",
          "desc" : "当那一天真的来临"
        }
      },
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.18232156,
        "_source" : {
          "name" : "万里顾一程",
          "desc" : "当那一天真的真的来临"
        }
      }
    ]
  }
}

使用 term查询 desc 字段:

GET testdb/_search
{
  "query": {
    "term": {
        "desc": "当那一天真的来临"
    }
  }
}

返回结果:只返回一条结果,因为desc字段类型是keyword类型,分词器对desc字段不会进行分词解析,只能完完整整的匹配搜索词。

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.6931471,
    "hits" : [
      {
        "_index" : "testdb",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.6931471,
        "_source" : {
          "name" : "万里顾一程",
          "desc" : "当那一天真的来临"
        }
      }
    ]
  }
}

term和match的区别

match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,而term会直接对关键词进行查找。一般模糊查找的时候,多用match,而精确查找时可以使用term。

多个值进行完全匹配查询

GET testdb/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
              "name": "万"
          },
          "term": {
              "name": "万里"
          }
        }
      ]
    }
  }
}

3.3.9、高亮查询

默认高亮

查询请求语句:使用highlight属性来实现结果高亮显示,需要的字段名称添加到fields内即可,elasticsearch会自动帮我们实现高亮。

GET wanli/user/_search
{
  "query":{
    "match": {
      "name": "万里"
    }
    },
    "highlight":{
    "fields": {
      "name": {}
    }
  }
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 61,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.605183,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.605183,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        },
        "highlight" : {
          "name" : [
            "<em>万</em><em>里</em>"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.0892314,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        },
        "highlight" : {
          "name" : [
            "<em>万</em><em>里</em>顾一程"
          ]
        }
      }
    ]
  }
}

elasticsearch 会自动将检索结果用标签包裹起来,用于在页面中渲染。

自定义高亮显示

如果我们不想用em标签,想用个p标签时,可以自定义标签。

查询请求语句:pre_tags用来实现我们的自定义标签的前半部分,在这里,我们也可以为自定义的标签添加属性和样式。post_tags实现标签的后半部分,组成一个完整的标签。至于标签中的内容,则还是交给fields来完成。

GET wanli/user/_search
{
  "query":{
    "match": {
      "name": "万里"
    }
    },
    "highlight":{
    "pre_tags": "<p class='key',style:'color=red'>", 
    "post_tags": "</p>", 
    "fields": {
      "name": {}
    }
  }
}

返回结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.605183,
    "hits" : [
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.605183,
        "_source" : {
          "name" : "万里",
          "age" : "18",
          "desc" : "初级Java开发工程师",
          "tags" : [
            "技术宅",
            "直男",
            "运动"
          ]
        },
        "highlight" : {
          "name" : [
            "<p class='key',style:'color=red'>万</p><p class='key',style:'color=red'>里</p>"
          ]
        }
      },
      {
        "_index" : "wanli",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.0892314,
        "_source" : {
          "name" : "万里顾一程",
          "age" : "3",
          "desc" : "高级Java开发工程师",
          "tags" : [
            "技术宅",
            "钻研",
            "运动"
          ]
        },
        "highlight" : {
          "name" : [
            "<p class='key',style:'color=red'>万</p><p class='key',style:'color=red'>里</p>顾一程"
          ]
        }
      }
    ]
  }
}