我正在尝试实现类似于Mysql的行为,即通过ES管道为我索引的每个文档在元数据上添加insertd_at / updated_at。
我的管道就像:
{
"description": "Adds createdAt and updatedAt style timestamps",
"processors": [
{
"set": {
"field": "_source.indexed_at",
"value": "{{_ingest.timestamp}}",
"override": false
}
},
{
"set": {
"field": "_source.updated_at",
"value": "{{_ingest.timestamp}}",
"override": true
}
}
]
}
我想没有映射只尝试添加一个文档:
POST test_pipelines/doc/1?pipeline=timestamps
{
"foo": "bar"
}
管道成功创建了indexed_at
和updated_at
:
{
"_index": "test_pipelines",
"_type": "doc",
"_id": "1",
"_score": 1,
"_source": {
"indexed_at": "2018-07-12T10:47:27.957Z",
"updated_at": "2018-07-12T10:47:27.957Z",
"foo": "bar"
}
}
但是,如果我尝试更新文档1,则字段indexed_at
每次都会更改为与文档更新的日期相同。
更新请求示例:
POST test_pipelines/doc/1?pipeline=timestamps
{
"foo": "bor"
}
有什么方法可以告诉处理器不要更新indexed_at
字段?
答案 0 :(得分:3)
发生这种情况的原因是,set
处理器将仅在您要发送的文档的上下文中运行,而不是在存储的文档(如果有)中运行。因此,override
在这里无效,因为您发送的文档既不包含indexed_at
也不包含updated_at
,这就是在每次调用时都设置两个字段的原因。
第二次PUT
文档时,您没有更新它,实际上是从头开始为它重新编制索引(即,您覆盖了您发送的第一个版本)。提取管道do not work with update operations。例如,如果您尝试以下更新调用,它将失败。
POST test_pipelines/doc/1/_update?pipeline=timestamps
{
"doc": {
"foo": "bor"
}
}
如果您要坚持使用摄取管道,那么使其生效的唯一方法是首先GET
文档,然后更新所需的字段。例如,
# 1. index the document the first time
PUT test_pipelines/doc/1?pipeline=timestamps
{
"foo": "bar"
}
# 2. GET the indexed document
GET test_pipelines/doc/1
# 3. update the foo field and index it again
PUT test_pipelines/doc/1?pipeline=timestamps
{
"indexed_at": "2018-07-20T05:08:52.293Z",
"updated_at": "2018-07-20T05:08:52.293Z",
"foo": "bor"
}
# 4. When you GET the document the second time, you'll see your pipeline worked
GET test_pipelines/doc/1
这将返回:
{
"indexed_at": "2018-07-20T05:08:52.293Z",
"updated_at": "2018-07-20T05:08:53.345Z",
"foo": "bor"
}
我绝对同意这确实很麻烦,但是我上面给出的链接列举了更新操作不支持管道的所有原因。
使它按您喜欢的方式(没有管道)工作的另一种方法是使用脚本化的upsert操作(其工作方式与上述步骤2和3相同,即在单个原子操作中对文档进行GET和PUT),并且也可以与您的批量通话配合使用。基本上是这样的。首先,您需要存储一个将用于索引和更新操作的脚本:
POST _scripts/update-doc
{
"script": {
"lang": "painless",
"source": "ctx._source.foo = params.foo; ctx._source.updated_at = new Date(); if (ctx._source.indexed_at == null) ctx._source.indexed_at = ctx._source.updated_at;"
}
}
然后,您可以像这样第一次在文档中建立索引:
POST test_pipelines/doc/1/_update
{
"script": {
"id": "update-doc",
"params": {
"foo": "bar"
}
},
"scripted_upsert": true,
"upsert": {}
}
索引文档将如下所示:
{
"updated_at": "2018-07-20T05:57:40.510Z",
"indexed_at": "2018-07-20T05:57:40.510Z",
"foo": "bar"
}
更新文档时,您可以使用完全相同的调用:
POST test_pipelines/doc/1/_update
{
"script": {
"id": "update-doc",
"params": {
"foo": "bor" <--- only this changes
}
},
"scripted_upsert": true,
"upsert": {}
}
更新后的文档将如下所示,正是您想要的:
{
"updated_at": "2018-07-20T05:58:42.825Z",
"indexed_at": "2018-07-20T05:57:40.510Z",
"foo": "bor"
}