ES为提供了一套HTTP RESTful API,开发和运维人员可以直接调用这些API来配置和访问ES服务。 这些API的功能十分丰富,从集群监控、运维管理到应用开发所需的索引、文档相关操作。本文将从应用开发的角度整理ES应用开发人员应该熟练掌握的API。

1.索引的创建、修改和删除

创建索引PUT /<index-name>,例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PUT /book-0.1.0
{
    "aliases": {
        "book":{}
    },
    "settings": {
        "analysis": {
            "normalizer": {
                "lowercase": {
                    "type": "custom",
                    "char_filter": [],
                    "filter": ["lowercase"]
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "name": {
                "type": "keyword",
                "normalizer": "lowercase"
            },
            "price": {
                "type": "double"
            },
            "summary": {
                "type": "text",
                "analyzer": "ik_max_word"
            },
            "author": {
                "type": "keyword"
            },
            "pubDate": {
                "type": "date"
            }
        }
    }
}

实践中在创建索引时,索引的名称一般会带上版本号,同时将不带版本号的名称设置为索引的别名(alias),开发中对索引文档的操作都是基于别名。 通过索引别名可以优雅的解决两个版本索引之间的无缝切换问题。

删除索引DELETE /<index-name>,例:

1
DELETE /book-0.1.0

查看索引信息GET /<index-name>,例:

1
GET /book-0.1.0

在应用开发的各个迭代过程中,经常需要对一个索引的mapping结构进行调整。 如果调整结构的需求是增加新的字段,可以直接调用API增加,如果是修改现有字段或删除现有字段,则只能通过创建新mapping结构的索引并重新reindex数据的方式实现。 调用API增加新字段举例如下:

1
2
3
4
5
6
7
8
PUT /book-0.1.0/_mapping
{
    "properties": {
        "pages": {
            "type": "integer"
        }
    }
}

2.文档的创建

索引创建好后就可以直接向索引中添加数据了。

1
2
3
4
5
6
7
PUT /<index-name>/_doc/<_id>

POST /<index-name>/_doc/

PUT /<index-name>/_create/<_id>

POST /<index-name>/_create/<_id>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
POST /book/_doc
{
  "name": "天龙八部",
  "author": "金庸",
  "pages": 1978,
  "price": 96.0,
  "pubDate": "1994-05-01",
  "summary": "天龙八部乃金笔下的一部长篇小说,与《射雕》,《神雕》等 几部长篇小说一起被称为可读性最高的金庸小说。《天龙》的故事情节曲折,内容丰富,也曾多次被改编为电视作品。是金庸作品中集大成的一部。故事以北宋末年动荡的社会环境为背景,展开波澜壮阔的历史画卷,塑造了乔峰、段誉、 虚竹、慕容复等形象鲜明的人物,成为武侠史上的经典之作。"
}

输出:
{
  "_index" : "book-0.1.0",
  "_type" : "_doc",
  "_id" : "y2W-mHkB3xk21-h8U9AP",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

文档创建成功后,会返回一个包含_id的json数据,_id即为刚刚创建的文档的ID由ES自动生成,唯一标识一个文档。 POST /<target>/_doc/这个API不具有幂等性,多次请求会创建_id不同的,但文档其他字段相同的重复数据。

可以在创建文档时手动指定文档ID:

1
2
3
4
5
6
7
8
9
POST /book/_doc/10001
{
  "name": "天龙八部",
  "author": "金庸",
  "pages": 1978,
  "price": 96.0,
  "pubDate": "1994-05-01",
  "summary": "天龙八部乃金笔下的一部长篇小说,与《射雕》,《神雕》等 几部长篇小说一起被称为可读性最高的金庸小说。《天龙》的故事情节曲折,内容丰富,也曾多次被改编为电视作品。是金庸作品中集大成的一部。故事以北宋末年动荡的社会环境为背景,展开波澜壮阔的历史画卷,塑造了乔峰、段誉、 虚竹、慕容复等形象鲜明的人物,成为武侠史上的经典之作。"
}

文档创建成功后,返回的_id为我们指定的ID值,多次发出这个创建请求,返回的结果是相同的,只是返回数据版本_version会增加。 操作是幂等的,也可以将上面的POST请求方式换成PUT请求。另外可以使用PUT /<index-name>/_create/<_id>POST /<index-name>/_create/<_id>创建文档时,如果_id已经存在时会失败并报版本冲突的错误,实际根据具体的需求选择使用哪个API。

3.文档的查询

使用GET <index-name>/_doc/<_id>API查询指定ID的文档:

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
GET /book/_doc/10001

输出:
{
  "_index" : "book-0.1.0",
  "_type" : "_doc",
  "_id" : "10001",
  "_version" : 5,
  "_seq_no" : 7,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "天龙八部",
    "author" : "金庸",
    "pages" : 1978,
    "price" : 96.0,
    "pubDate" : "1994-05-01",
    "summary" : ......
  }
}

使用GET <index-name>/_search查询所有的文档数据:

1
GET /book/_search

4.文档的更新和删除

更新文档包含两种情况,一种是完全覆盖性更新,另一种是局部性更新。

先来看完全覆盖性更新:

1
2
3
4
5
6
7
8
9
PUT /book/_doc/10001
{
  "name": "天龙八部",
  "author": "金庸",
  "pages": 1978,
  "price": 96.0,
  "pubDate": "1994-05-01",
  "summary": ""
}

再来看局部性更新:

1
2
3
4
5
6
POST /book/_update/10001
{
    "doc": {
        "name": "《天龙八部》"
    }
}

文档的删除:

1
DELETE /book/_update/10001

5.条件查询、分页和排序

前面已经介绍了文档的增、删、改、查,ES的优势还是在查询上。

简单的条件查询、分页和排序如下例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
GET /book/_search
{
  "query": {
    "match": {
      "author": "金庸"
    }
  },
  "from": 0,
  "size": 5,
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}

6.多条件查询和范围查询

多条件查询如下例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 多条件同时成立
GET /book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "author": "金庸"
          }
        },
        {
          "match": {
            "pages": 1978
          }
        }
      ]
    }
  }
}

# 多条件满足其一即可
GET /book/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "author": "金庸"
          }
        },
        {
          "match": {
            "pages": 1978
          }
        }
      ]
    }
  }
}

范围查询如下例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
GET /book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "author": "金庸"
          }
        },
        {
          "range": {
            "price": {
              "gte":50,
              "lte": 100
            }
          }
        }
      ]
    }
  }
}

7.全文检索与完全匹配

文档字段为text类型时,会将查询关键字进行分词并在倒排索引中进行匹配。

1
2
3
4
5
6
7
8
GET /book/_search
{
  "query": {
    "match": {
      "summary": "北宋射雕"
    }
  }
}

完全匹配:

1
2
3
4
5
6
7
8
GET /book/_search
{
  "query": {
    "match_phrase": {
      "author": "金庸"
    }
  }
}

高亮显示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
GET /book/_search
{
  "query": {
    "match": {
      "summary": "北宋射雕"
    }
  },
  "highlight": {
    "fields": {
      "summary": {}
    }
  }
}

8.聚合查询

下面的例子,使用aggs进行聚合查询,设置"size": 0只返回聚合统计结果,不要返回查询的hits结果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
GET /book/_search
{
  "aggs": {
    "author_agg_name": {
      "terms": {
        "field": "author"
      }
    }
  },
  "size": 0
}

例如查询作者为金庸的所有图书的平均价格:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
GET /book/_search
{
  "query": {
    "match_phrase": {
      "author": "金庸"
    }
  }, 
  "aggs": {
    "avg_price": {
      "avg": {
        "field": "price"
      }
    }
  },
  "size": 0
}

参考