0%

Elasticsearch Index API

文档

什么是文档

程序中大多的实体或对象能够被序列化为包含键值对的JSON对象,键(key)是字段(field)或属性(property)的名字,值(value)可以是字符串、数字、布尔类型、另一个对象、值数组或者其他特殊类型,比如表示日期的字符串或者表示地理位置的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"name": "John Smith",
"age": 42,
"confirmed": true,
"join_date": "2014-06-01",
"home": {
"lat": 51.5,
"lon": 0.1
},
"accounts": [
{
"type": "facebook",
"id": "johnsmith"
},
{
"type": "twitter",
"id": "johnsmith"
}
]
}

通常,我们可以认为对象(object)和文档(document)是等价相通的。不过,他们还是有所差别:对象(Object)是一个JSON结构体——类似于哈希、hashmap、字典或者关联数组;对象(Object)中还可能包含其他对象(Object)。 在Elasticsearch中,文档(document)这个术语有着特殊含义。它特指最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中)。

归结

  1. Json Object,由字段组成:

    • 字符串:text, keyword
    • 数值型:long,integer,short,byte,double,float,half_float,scled_float
    • 布尔:boolean
    • 日期:date
    • 二进制:binary
    • 范围类型:integer_range,float_range,long_range,double_range,date_range
  2. 每个文档有唯一的id标识

    • 自行指定
    • es生成
  3. 元数据,用于标注文档的相关信息

    • _index:文档所在的索引名
    • _type:文档所在的类型名
    • _id:文档唯一id
    • _uid:组合id,由_type和_id组成(6.x_type不再起作用,同_id一样)
    • _source:文档的原始Json数据,可以从这里获取每个字段的内容
    • _all:整合所有字段内容到该字段,默认禁用

文档元数据

一个文档不只有数据。它还包含了元数据(metadata)——关于文档的信息。三个必须的元数据节点是:

节点说明
_index文档存储的地方
_type文档代表的对象的类
_id文档的唯一标识

_index

索引(index)类似于关系型数据库里的“数据库”——它是我们存储和索引关联数据的地方。

事实上,我们的数据被存储和索引在分片(shards)中,索引只是一个把一个或多个分片分组在一起的逻辑空间。然而,这只是一些内部细节——我们的程序完全不用关心分片。对于我们的程序而言,文档存储在索引(index)中。剩下的细节由Elasticsearch关心既可。

_type
在应用中,我们使用对象表示一些“事物”,例如一个用户、一篇博客、一个评论,或者一封邮件。每个对象都属于一个类(class),这个类定义了属性或与对象关联的数据。user类的对象可能包含姓名、性别、年龄和Email地址。
在关系型数据库中,我们经常将相同类的对象存储在一个表里,因为它们有着相同的结构。同理,在Elasticsearch中,我们使用相同类型(type)的文档表示相同的“事物”,因为他们的数据结构也是相同的。
每个类型(type)都有自己的映射(mapping)或者结构定义,就像传统数据库表中的列一样。所有类型下的文档被存储在同一个索引下,但是类型的映射(mapping)会告诉Elasticsearch不同的文档如何被索引。

在7.0前,一个index可以设置多个type,在7.0后type统一为_doc

_id

id仅仅是一个字符串,它与_index和_type组合时,就可以在Elasticsearch中唯一标识一个文档。当创建一个文档,你可以自定义_id,也可以让Elasticsearch帮你自动生成。

Index Api

以下操作均在es7.2版本操作

Index(createorupdate)

PUT {_index}/{_type}/{_id}
POST {_index}/{_type}/{_id}(id可不指定)

创建一个索引

1
PUT test_index

创建一个索引并指定文档内容和id

1
2
3
4
5
PUT /test_index/_doc/1
{
"username":"alfred",
"age":1
}

创建一个索引指定文档内容自动生成id

1
2
3
4
5
POST /test_index/_doc
{
"username":"lili",
"age":22
}

文档不存在执行的是创建操作,存在的话回变为更新操作,并且_version会增加1

Create

有两种方式:

第一种方法使用op_type查询参数:

1
2
3
4
5
PUT /test_index/_doc/1?op_type=create
{
"username":"alfred",
"age":1
}

或者第二种方法是在URL后加/_create做为端点:

1
2
3
4
5
PUT /test_index/_doc/1/_create
{
"username":"alfred",
"age":1
}

如果请求成功的创建了一个新文档,Elasticsearch将返回正常的元数据且响应状态码是201 Created。
另一方面,如果包含相同的_index、_type和_id的文档已经存在,Elasticsearch将返回409 Conflict响应状态码,错误信息类似如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, document already exists (current version [6])",
"index_uuid": "vENoH2YDQRiFHvu_pfzDcg",
"shard": "0",
"index": "test_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, document already exists (current version [6])",
"index_uuid": "vENoH2YDQRiFHvu_pfzDcg",
"shard": "0",
"index": "test_index"
},
"status": 409
}

POST和PUT的区别是POST不用加具体的id,它是作用在一个集合资源之上的(/uri),而PUT操作是作用在一个具体资源之上的(/uri/xxx)。
在ES中,如果不确定document的ID(documents具体含义见下),那么直接POST对应uri( “POST /website/blog” ),ES可以自己生成不会发生碰撞的UUID;
如果确定document的ID,比如 “PUT /website/blog/123”,那么执行创建或修改(修改时_version版本号提高1)

Update

1
2
3
4
5
6
PUT /test_index/_update/1
{
"doc": {
"hobby": "hit"
}
}

Delete

1
DELETE test_index

Get

获取所有

1
GET /test_index/_search

指定id

1
GET /test_index/_doc/1

归结

操作请求
CreatePUT /test_index/_doc/1/_create
{“username”:”alfred”,”age”:1}
POST /test_index/_doc/
{“username”:”alfred”,”age”:1}(不指定id自动生成)
IndexPUT Or POST /test_index/_doc/1/
{“username”:”alfred”,”age”:1}
ReadGET /test_index/_doc/1
UpdatePOST /test_index/_update/1
{“doc”: {“sex”: “女”}}
DeleteDELETE test_index2

Index和Update
Index实际上是文档不存在会创建一个文档,存在则会删除原来的文档,新的文档被索引,并且version加1
Update不会删除原来的文档,实现真正的更新,POST方法的payload需包含在”doc”里

Bulk

1
2
3
4
5
6
POST _bulk
{"index":{"_index":"test_index","_id":"3"}}
{"username":"alfred","age":20}
{"delete":{"_index":"test_index","_id":"1"}}
{"update":{"_id":"2","_index":"test_index"}}
{"doc":{"age":"20"}}

批量查询api

es允许一次查询多个文档,如果你需要从Elasticsearch中检索多个文档,相对于一个一个的检索,更快的方式是在一个请求中使用multi-get或者mget API。

mget API参数是一个docs数组,数组的每个节点定义一个文档的_index、_type、_id元数据。如果你只想检索一个或几个确定的字段,也可以定义一个_source参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST _mget
{
"docs": [
{
"_id": 1,
"_index":"test_index"
},
{
"_id": 2,
"_index":"test_index"
}
]
}

响应体也包含一个docs数组,每个文档还包含一个响应,它们按照请求定义的顺序排列。每个这样的响应与单独使用get request响应体相同:

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
{
"docs" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 17,
"_primary_term" : 2,
"found" : true,
"_source" : {
"name" : "lili",
"age" : "10"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"_seq_no" : 16,
"_primary_term" : 2,
"found" : true,
"_source" : {
"name" : "john",
"age" : "40"
}
}
]
}

如果你想检索的文档在同一个_index中,你就可以在URL中定义一个默认的/_index。
你依旧可以在单独的请求中使用这些值:

1
2
3
4
5
6
7
POST /test_index/_doc/_mget
{
"docs" : [
{ "_id" : 2 },
{ "_id" : 1 }
]
}

在7.0以上版本后,_doc在mget中可以省略,不省略会提示#! Deprecation: [types removal] Specifying types in multi get requests is deprecated.

事实上,如果所有文档具有相同_index,你可以通过简单的ids数组来代替完整的docs数组:

1
2
3
4
POST /test_index/_mget
{
"ids" : [ "4", "1" ]
}

不存在的文档会显示found:false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"docs" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "4",
"found" : false
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 17,
"_primary_term" : 2,
"found" : true,
"_source" : {
"name" : "lili",
"age" : "10"
}
}
]
}

尽管前面提到有一个文档没有被找到,但HTTP请求状态码还是200。事实上,就算所有文档都找不到,请求也还是返回200,原因是mget请求本身成功了。如果想知道每个文档是否都成功了,你需要检查found标志。