常用 API 介绍

前面介绍了 Elasticsearch 和 Kibana 的安装,这一节主要来介绍一下在 Kibana 里面的 DevTools 下,具体如何来进行最基本的 Elasticsearch 操作。Elasticsearch 大部分 API 的输入输出都是 JSON 数据结构。有关 JSON 的更完整的介绍可访问: https://www.json.org/json-zh.html

增删改查

首先是索引的操作,其实在第一节关于 Elasticsearch 安装的时候,已经介绍过,我们再来回顾一下。

假设我们创建一个有包含 2 个字段的索引文档。

POST twitter/doc/1
{
  "name":"jack",
  "age":30
}

返回结果为:

{
  "_index": "twitter",
  "_type": "doc",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

如果要取回这个文档,只需要将 POST 换成 GET,如下:

GET twitter/doc/1

返回结果为:

{
  "_index": "twitter",
  "_type": "doc",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "name": "jack",
    "age": 30
  }
}

返回结果里面的 found 说明找到了该文档,_source 即我们 POST 进去的原始文档。

如果要修改这个文档,有两种方式,一种是完全替换,使用相同的路径即可,我们修改 age 为 35,如下:

PUT twitter/doc/1
{
  "name":"jack",
  "age":35
}

返回结果:

{
  "_index": "twitter",
  "_type": "doc",
  "_id": "1",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}

还一种更新叫做部分更新,你只需指定要更新的字段和该字段的值即可,不用准备完整的 JSON 文档,如下:

POST twitter/doc/1/_update
{
    "doc" : {
        "name" : "mark"
    }
}

最外层的 doc 是固定的结构,我们只需要准备要更新的字段放在里面就行。

最后我们再来看看删除,只需要把取回文档操作的 GET 换成 DELETE 就行了,如下:

DELETE twitter/doc/1

返回:

{
  "_index": "twitter",
  "_type": "doc",
  "_id": "1",
  "_version": 4,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}

很好,result 显示删除成功。

搜索的使用

我们创建两个索引文档,ID 分别是 1 和 2,如下:

POST twitter/doc/1
{
  "name":"jack",
  "age":30
}

POST twitter/doc/2
{
  "name":"mark",
  "age":35
}

现在我们想通过名称来进行搜索,可以使用 _search 接口,然后指定条件 q 来传递查询关键字,如下:

GET twitter/_search?q=jack

返回:

{
  "took": 51,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "twitter",
        "_type": "doc",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "name": "jack",
          "age": 30
        }
      }
    ]
  }
}

hits 就是我们搜索返回的结果,total 是搜索命中的结果总数,下面的 hits 是本次返回的部分搜索结果,是一个数组结构,里面是具体的索引文档。

我们再看看如何通过年龄来进行检索,如下:

GET twitter/_search?q=35

返回:

{
  "took": 9,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "twitter",
        "_type": "doc",
        "_id": "2",
        "_score": 1,
        "_source": {
          "name": "mark",
          "age": 35
        }
      }
    ]
  }
}

另外,我们还能限定查询的字段,如只对年龄字段进行查询,如下:

GET twitter/_search?q=age:35

除此以外,还能使用 QueryDSL 来写查询表达式,即将查询表达式以 JSON 的方式来通过请求体(request body)来传递,而不是走 URL 网址参数,如下:

GET twitter/_search
{
  "query": {
    "match": {
      "age": 35
    }
  }
}

搜索结果应该和前面 url 传参效果一致,读者可以自行尝试一下。

聚合的使用

聚合是 Elasticsearch 里面用来对搜索结果的数据进行统计和聚合操作的过程,通过聚合,我们可以对搜索结果做到按各个维度的统计,结合丰富的前端展现,从而实现良好的搜索体验。

我们再创建两个索引文档,如下:

POST twitter/doc/3
{
  "name":"john",
  "age":30
}
POST twitter/doc/4
{
  "name":"mark",
  "age":40
}

现在我们想统计一下,年龄的分布情况,可以使用如下的查询条件,最外层的 size0 这样可以不返回搜索命中的文档,只返回聚合的统计结果,aggs 就是我们描述聚合查询语句根节点,我们使用 terms 聚合类型来对 age 字段的值进行统计,并且只返回前 10 个统计值,然后这些统计结果我们命名为 age_stats,如下图:

GET twitter/_search
{
  "size": 0,
  "aggs": {
    "age_stats": {
      "terms": {
        "field": "age",
        "size": 10
      }
    }
  }
}

返回:

{
  "took": 55,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "age_stats": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 30,
          "doc_count": 2
        },
        {
          "key": 35,
          "doc_count": 1
        },
        {
          "key": 40,
          "doc_count": 1
        }
      ]
    }
  }
}

可以看到查询返回的 JSON 里面包含了表示聚合结果的 aggregations 节点,下面有我们的统计结果 age_stats,下面 buckets 表示聚合的具体值 key 和统计数据 doc_count,也就是各个年龄分别有多少个文档,出现了多少次。

索引的管理

Elasticsearch 还有很多 API 可以用来对索引进行管理,比如我们还可以通过 _cat API 来查看索引列表:

GET _cat/indices?v

返回:

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .kibana 3UiUi8MZQDeF3p97eRWyFw   1   0          2            1      9.7kb          9.7kb
yellow open   index   VpNv75DzQESBfX8DcLLcww   5   1          1            0      4.3kb          4.3kb

返回的结果不是 JSON,而是精简的表格类型,第一行是字段名,后面行是具体的数据,可以看到索引的列表、各索引状态、文档数和索引大小等参数,各字段分别说明如下:

字段名 说明
health  索引健康状态,green 表示健康;yellow 表示数据完整,但是缺少副本;red 则表示有数据损坏。
status  索引工作状态,open 表示索引打开中,可以被使用;close 表示索引被关闭,不能使用。
index  索引名称。
uuid  索引的唯一 ID 标识。
pri  索引的主分片个数。
rep  索引的副本分片个数。
docs.count  索引内的文档个数。
docs.deleted  索引内已经删除的文档个数。

如果要删除索引,可以执行下面的动作来清理整个索引,twitter 就是其中要删除的索引名:

DELETE twitter

集群管理的接口很多,我们这里不展开,我们只需要能够知道查看索引是否存在、索引有多少文档,索引是否正常和能够删除索引,我们就可以继续后面的实战了。

集群的监控

除此之外,我们还可以查看集群的健康状况:

GET _cluster/health

返回:

{
  "cluster_name": "elasticsearch",
  "status": "yellow",
  "timed_out": false,
  "number_of_nodes": 1,
  "number_of_data_nodes": 1,
  "active_primary_shards": 14,
  "active_shards": 14,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 13,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 51.85185185185185
}

这里我们只需要关注 status 字段,当值为 green 或者 yellow 时,我们就可以正常使用该 Elasticsearch 服务。