ES 操作-文档管理

创建文档

ES 提供了一套遵守 Restful 语义的接口,相关的操作可以通过不同的请求方法来进行调用,比如简单的新增可以使用 POST 请求或者 PUT 请求

1
2
3
4
5
6
7
8
9
10
11
12
# PUT 多次请求结果幂等,仅增加文档版本号,文档编号不可省略
PUT /<索引>/<类型>/<编号>
{
"字段A": "值A",
"字段B": "值B"
}
# POST 请求在版本号省略时,可以自动生成字符串文档编号
POST /<索引>/<类型>/[编号]
{
"字段A": "值A",
"字段B": "值B"
}

简单查询

单一文档指定查询

查询特定的文档,(先不考虑条件查询等)需要明确指定索引名称,类型名称和文档编号,如果文档存在,返回的 found 域会为 true

1
2
3
4
# 使用 GET 请求获取指定的文档信息
GET /<索引名称>/<类型名称>/<文档编号>
# 可以使用利用版本号-version来控制资源的时效性(ES 悲观锁机制),版本号不正确会抛出异常
GET /<索引名称>/<类型名称>/<文档编号>?version=<期望版本号>

如果不需要文档内容,只需要确认文档是否存在可以使用 HEAD 请求

1
2
# HEAD 请求,200 成功,404 未找到
HEAD /<索引名称>/<类型名称>/<文档编号>

多个文档指定查询

在指定查询多个文档时候需要使用 _mget API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /[公共索引名称]/[公共类型名称]/_mget
{
"docs": [
{
"_index": "具体索引名称A", # 当未指定公共索引名称时需要
"_type": "具体类型名称A", # 当未指定公共类型名称时需要
"_id": "具体文档编号"
},
{
"_index": "具体索引名称B",
"_type": "具体类型名称B",
"_id": "具体文档编号"
}
]
}

在查询同一索引同一类型时最简写法:

1
2
3
4
GET /<公共索引名称>/<公共类型名称>/_mget
{
"ids": ["编号1", "编号2", "编号3"]
}

文档更新

简单更新操作

文档更新时候,ES 会删除旧的文档,更新文档内容后索引新的文档。通常,最简单的更新操作可以直接使用 PUT 操作完成:

1
2
3
4
5
PUT /<索引>/<类型>/<编号>
{
"字段A": "新值A",
"新字段B": "新值B"
}

ES 悲观锁机制,默认情况下每次更新会使得版本号增 1,其实也可以手动指定值(当然指定的版本号需要大于当前版本号)

1
2
3
4
5
PUT /<索引>/<类型>/<编号>?version=<版本号>&version_type=external
{
"字段A": "新值A",
"新字段B": "新值B"
}

脚本更新操作

更为复杂的更新操作可以使用 POST 请求操作 _update API,下面是一个简单例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /<索引>/<类型>/<编号>/_update
{
# 声明使用脚本进行操作文档
"script": {
# 书写脚本内容(the 'inline' is deprecated)
# 这里五个语句分别是:字段值修改,移除字段,新增字段(类似修改),字段值修改(api调用),文档删除
"source": "ctx._source.count += params.count; ctx._source.remove(\"to_be_removed\"); ctx._source.tags=[]; ctx._source.tags.add(params.class); ctx._source.op=\"delete\"",
# 声明脚本语言
"lang": "painless",
# 输入脚本入参集合
"params": {
"count": 3,
"class": "Java"
}
},
# 可选,当指定更新的资源不存在时,进行插入
"upsert": {
"字段A": "值A"
}
}

条件过滤更新

同时 ES 也支持条件查询后对文档进行更新,使用 _update_by_query,类似 SQL 中 update…where 的形式

1
2
3
4
5
6
7
8
9
10
11
12
POST /[索引名]/[类型名]/_update_by_query
{
# 脚本的具体使用同上
"script": {
},
# 查询条件,具体之后深入
"query": {
"term": {
"age": 18
}
}
}

删除操作

简单删除操作

很简单的,使用 DELETE 方法并指定资源即可:

1
2
3
4
# 删除指定文档,自动路由
DELETE /<索引>/<类型>/<文档编号>
# 删除指定文档,并给定路由参数
DELETE /<索引>/<类型>/<文档编号>?routing=<路由值>

条件过滤删除

如同更新操作,可以在删除前进行查询操作,以过滤出需要删除的文档,使用 _delete_by_query API 操作:

1
2
3
4
5
6
POST /[索引名]/[类型名]/_delete_by_query
{
"query": {
# 查询条件
}
}

批量操作

很多时候需要同时操作大量的文档,一个一个来执行命令显然是不可能的。ES 提供了 _bulk API,并支持多文档的创建,更新,删除等操作,但是对格式有一定的要求。首先需要一个 JSON 格式的内容:

1
2
3
4
5
6
7
8
9
10
# 新建
{"create / index": {"_index": "索引名称", "_type": "类型名称", "_id": "不指定则自动生成"}}
{<文档内容>}

# 删除
{"delete": {"_index": "索引名称", "_type": "类型名称", "_id": "id值"}}

# 更新
{"update": {"_index": "索引名称", "_type": "类型名称", "_id": "id值", "_retry_on_conflict": 3}}
{"doc": {<需要更新的内容>}}

然后使用一个 POST 请求:

1
curl -XPOST "地址/_bulk?pretty" --data-binary @JSON文件名

bulk 请求时注意文件的大小,因为整个请求会被加载进被请求的节点,所以同时可供其他请求的内存会相应变小。合适的大小值不是一个固定值,这取决机器配置和索引复杂度,搜索负载等。一个合适的批次通常在 5~15 MB之间。


参考:

  • 《从Lucene到Elasticsearch全文检索实战》 姚攀
码路加油
显示评论