前面介绍了 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
}
现在我们想统计一下,年龄的分布情况,可以使用如下的查询条件,最外层的 size
为 0
这样可以不返回搜索命中的文档,只返回聚合的统计结果,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 服务。