【问题标题】:elasticsearch script to check if field exists and create itelasticsearch脚本检查字段是否存在并创建它
【发布时间】:2017-08-09 19:14:07
【问题描述】:

我创建了一个脚本,该脚本记录了在弹性文档中应用的标签的历史记录。标签的名称是动态的,所以当我尝试将当前标签移动到历史字段时,对于还没有历史字段的标签会失败。

这是我将当前标签复制到标签历史字段的脚本:

script:"ctx._source.tags[params.tagName.toString()].history.add(ctx._source.tags[params.tagName.toString()].current)"

这是文档的样子:

"tags": {
                        "relevant": {
                            "current": {
                                "tagDate": 1501848372292,
                                "taggedByUser": "dev",
                                "tagActive": true
                            },
                            "history": [
                                {
                                    "tagDate": 1501841137822,
                                    "taggedByUser": "admin",
                                    "tagActive": true
                                },
                                {
                                    "tagDate": 1501841334127,
                                    "taggedByUser": "admin",
                                    "tagActive": true
                                },
                                }}}}

用户可以动态添加新标签,所以我想做的是创建历史对象,如果它不存在,然后我可以填充它。

弹性搜索脚本可用的文档很少,所以我希望明智的人知道答案,因为我确信检查字段并创建它是弹性脚本语言的基本内容。

更新

所以,重新考虑了这个索引的结构,我想要实现的是:

tags:[
   {hot:
    {current:{tagDate:1231231233, taggedbyUser: user1, tagStatus: true},
    history:[ {tagDate:123444433, taggedbyUser: user1, tagStatus: true},
         {tagDate:1234412433, taggedbyUser: user1, tagStatus: true}
   ]
 }

  {interesting:
     {current:{tagDate:1231231233, taggedbyUser: user1, tagStatus: true},
     history:[ {tagDate:123444433, taggedbyUser: user1, tagStatus: true},
           {tagDate:1234412433, taggedbyUser: user1, tagStatus: true}
     ]
} 
]

此示例中的标签名称是“热门”和“有趣”,但是用户可以输入他们想要的任何标签名称,因此这些名称绝不是预定义的。当用户在弹性中标记文档并且应用的标签已经存在于弹性中时,它应该将“当前”标签添加到“历史”数组中,然后用新值覆盖“当前”标签。

感谢您迄今为止的回复,但是示例代码对我不起作用。

我认为我遇到的问题是,首先代码需要遍历所有标签并获取名称。然后我想将这些中的每一个与我在参数中提供的名称进行比较。我认为这是第一个问题出现的地方。

然后我需要将“当前”对象移动到“历史”数组。这里似乎也有问题。我正在尝试使用“ctx._source.tags[i].history.add(params.param1),但是没有添加任何内容。

有什么想法吗?

谢谢!

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    这有点复杂,因为你需要在脚本中做三件事:

    • 如果history不存在,则初始化数组
    • 将当前标签移至历史记录
    • 用新标签替换旧的current标签

    假设您的初始文档看起来像这样(注意没有history):

    {
        "_id": "AV2uvqCUfGXyNt1PjTbb",
        "tags": {
            "relevant": {
                "current": {
                    "tagDate": 1501848372292,
                    "taggedByUser": "dev",
                    "tagActive": true
                }
            }
        }
    }
    

    为了能够执行这三个步骤,您需要运行以下脚本:

    curl -X POST \
      http://127.0.0.1:9200/script/test/AV2uvqCUfGXyNt1PjTbb/_update \
      -d '{ 
        "script": {
            "inline": "if (ctx._source.tags.get(param2).history == null) ctx._source.tags.get(param2).history = new ArrayList();  ctx._source.tags.get(param2).history.add(ctx._source.tags.get(param2).current); ctx._source.tags.get(param2).current = param1;",
            "params" : {
                "param1" : {
                    "tagDate": 1501848372292,
                    "taggedByUser": "my_user",
                    "tagActive": true
                },
                "param2": "relevant"
            }
        }
    }'
    

    结果我得到:

    {
        "_id": "AV2uvqCUfGXyNt1PjTbb",
        "_source": {
            "tags": {
                "relevant": {
                    "current": {
                        "tagActive": true,
                        "tagDate": 1501848372292,
                        "taggedByUser": "my_user"
                    },
                    "history": [
                        {
                            "tagDate": 1501848372292,
                            "taggedByUser": "dev",
                            "tagActive": true
                        }
                    ]
                }
            }
        }
    }
    

    使用parm1(新标签)的新内容运行相同的脚本会得到:

    {
        "_id": "AV2uvqCUfGXyNt1PjTbb",
        "_source": {
            "tags": {
                "relevant": {
                    "current": {
                        "tagActive": true,
                        "tagDate": 1501841334127,
                        "taggedByUser": "admin"
                    },
                    "history": [
                        {
                            "tagDate": 1501848372292,
                            "taggedByUser": "dev",
                            "tagActive": true
                        },
                        {
                            "tagActive": true,
                            "tagDate": 1501848372292,
                            "taggedByUser": "my_user"
                        }
                    ]
                }
            }
        }
    }
    

    更新 - 如果 `tags` 是一个列表

    如果tags是“内部json对象”的列表,例如:

    {
        "tags": [
            {
                "relevant": {
                    "current": {
                        "tagDate": 1501841334127,
                        "taggedByUser": "dev",
                        "tagActive": true
                    }
                }
            },
            {
                "new_tag": {
                    "current": {
                        "tagDate": 1501848372292,
                        "taggedByUser": "admin",
                        "tagActive": true
                    }
                }
            }
        ]
    }
    

    您必须遍历列表才能找到正确元素的索引。假设您要更新元素new_tag。首先,您需要检查此标签是否存在——如果存在,则获取其索引,如果不存在,则从脚本中返回。有了索引,只要得到正确的元素,你就可以和以前几乎一样了。脚本如下所示:

    int num = -1;
    for (int i = 0; i < ctx._source.tags.size(); i++) {
        if (ctx._source.tags.get(i).get(param2) != null) {
            num = i;
            break;
        };
    };
    if (num == -1) {
        return;
    };
    if (ctx._source.tags.get(num).get(param2).history == null)
        ctx._source.tags.get(num).get(param2).history = new ArrayList();
    ctx._source.tags.get(num).get(param2).history.add(ctx._source.tags.get(num).get(param2).current);
    ctx._source.tags.get(num).get(param2).current = param1;
    

    还有整个查询:

    curl -X POST \
      http://127.0.0.1:9200/script/test/AV29gAnpqbJMKVv3ij7U/_update \
      -d '{ 
        "script": {
            "inline": "int num = -1; for (int i = 0; i < ctx._source.tags.size(); i++) {if (ctx._source.tags.get(i).get(param2) != null) {num = i; break;};}; if (num == -1) {return;}; if (ctx._source.tags.get(num).get(param2).history == null) ctx._source.tags.get(num).get(param2).history = new ArrayList();  ctx._source.tags.get(num).get(param2).history.add(ctx._source.tags.get(num).get(param2).current); ctx._source.tags.get(num).get(param2).current = param1;",
            "params" : {
                "param1" : {
                    "tagDate": 1501848372292,
                    "taggedByUser": "my_user",
                    "tagActive": true
                },
                "param2": "new_tag"
            }
        }
    }
    ' 
    

    结果:

    {
        "tags": [
            {
                "relevant": {
                    "current": {
                        "tagDate": 1501841334127,
                        "taggedByUser": "dev",
                        "tagActive": true
                    }
                }
            },
            {
                "new_tag": {
                    "current": {
                        "tagActive": true,
                        "tagDate": 1501848372292,
                        "taggedByUser": "my_user"
                    },
                    "history": [
                        {
                            "tagDate": 1501848372292,
                            "taggedByUser": "admin",
                            "tagActive": true
                        }
                    ]
                }
            }
        ]
    }
    

    【讨论】:

    • 谢谢,这很好用!如果“标签”是一个数组,我将如何修改代码来解决这个问题?我已经证实 if (ctx._source.tags.get(param2).history == null) ctx._source.tags.get(param2).history = new ArrayList(); ctx._source.tags.get(param2).history.add(ctx._source.tags.get[param2].current); ctx._source.tags.get(param2).current = param1;我用 [] 替换了 (),但是这似乎不起作用。
    • 对于tags 是一个列表的情况,您需要一个额外的步骤 - 遍历集合以找到要更新的正确对象。我更新了我的答案,详细说明了如何做到这一点。
    • 谢谢,我无法让它工作。我已经更新了我上面的帖子。如果您有任何想法,将不胜感激。无痛就是痛苦。
    【解决方案2】:

    我认为你可以在 groovy 脚本中做这样的事情

    {
      "script": "if( ctx._source.containsKey(\"field_name\") ){ ctx.op = \"none\"} else{ctx._source.field_name= field_value;}"
    }
    

    【讨论】:

    • 谢谢,我试过了。我遇到的问题是“field_name”是一个参数,它对我不起作用。另外,我需要检查的字段是:ctx._source.tags[params.tagName.toString()].history,所以我可能将其指向错误的地方。我试过 ctx._source.tags[params.tagName.toString()].containsKey(\"history\") 但我得到了很多错误。
    • 您能用映射和示例更新您的问题吗?
    猜你喜欢
    • 2012-10-17
    • 1970-01-01
    • 2023-04-07
    • 2018-05-21
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    相关资源
    最近更新 更多