ElasticSearch访问脚本中的嵌套文档-空指针异常



Gist:尝试使用无痛方法在嵌套文档上编写自定义过滤器。当没有嵌套文档超过null_pointer_exception时,希望编写错误检查

我有一个这样的映射(简化和模糊(

{
"video_entry" : {
"aliases" : { },
"mappings" : {
"properties" : {

"captions_added" : {
"type" : "boolean"
},
"category" : {
"type" : "keyword"
},

"is_votable" : {
"type" : "boolean"
},

"members" : {
"type" : "nested",
"properties" : {
"country" : {
"type" : "keyword",
},
"date_of_birth" : {
"type" : "date",
}
}
}
}

每个video_entry文档可以有0个或多个members嵌套文档。

样本文件

{
"captions_added": true,
"category"      : "Mental Health",
"is_votable:    : true,
"members": [
{"country": "Denmark", "date_of_birth": "1998-04-04T00:00:00"},
{"country": "Denmark", "date_of_birth": "1999-05-05T00:00:00"}
]
}

如果存在一个或多个嵌套文档,我们希望编写一些无痛的脚本,在所有嵌套文档中检查某些字段。我的脚本处理一些文档的映射,但当我在更大的文档集上尝试它时,尽管有可能的所有空检查,我还是会得到空指针异常。我尝试过各种访问模式和错误检查机制,但都有例外。

POST /video_entry/_search
{
"query": {
"script": {
"script": {
"source": """
// various NULL checks that I already tried
// also tried short circuiting on finding null values
if (!params['_source'].empty && params['_source'].containsKey('members')) {

def total = 0;


for (item in params._source.members) {
// custom logic here
// if above logic holds true 
// total += 1; 
} 

return total > 3;
}

return true;

""",
"lang": "painless"
}
}
}
}

我尝试过的其他声明

if (params._source == null) {
return true;
}
if (params._source.members == null) {
return true;
}
if (!ctx._source.contains('members')) {
return true;
}
if (!params['_source'].empty && params['_source'].containsKey('members') && 
params['_source'].members.value != null) {

// logic here
}
if (doc.containsKey('members')) {
for (mem in params._source.members) {
}
}

错误消息

&& params._source.members",
^---- HERE"
"caused_by" : {
"type" : "null_pointer_exception",
"reason" : null
}

我已经研究过更改结构(使文档变平(和must_not的用法,如这个答案所示。它们不适合我们的用例,因为我们需要包含更多的自定义逻辑。

不同的教程使用ctxdoc,有些使用params。更令人困惑的是,Debug.explain(doc.members)Debug.explain(params._source.members)返回空响应,我很难弄清楚类型。


Gist:尝试使用无痛程序在嵌套文档上编写自定义筛选器。想要在没有嵌套文档的情况下编写错误检查以超过null_pointer_exception

感谢您的帮助。

TLDr

Elastic使对象变平。这样

{
"group" : "fans",
"user" : [ 
{
"first" : "John",
"last" :  "Smith"
},
{
"first" : "Alice",
"last" :  "White"
}
]
}

转换为:

{
"group" :        "fans",
"user.first" : [ "alice", "john" ],
"user.last" :  [ "smith", "white" ]
}

要访问members内部值,您需要使用doc['members.<field>']引用它,因为members本身并不存在。

详细信息

正如您所知,Elastic以自己的方式处理内部文档。[doc]

因此,您需要相应地参考它们。

以下是我为使它发挥作用所做的工作。顺便说一句,我一直在使用kibana 的Dev tools

PUT /so_test/
PUT /so_test/_mapping
{
"properties" : {
"captions_added" : {
"type" : "boolean"
},
"category" : {
"type" : "keyword"
},
"is_votable" : {
"type" : "boolean"
},
"members" : {
"properties" : {
"country" : {
"type" : "keyword"
},
"date_of_birth" : {
"type" : "date"
}
}
}
}
}
POST /so_test/_doc/
{
"captions_added": true,
"category"      : "Mental Health",
"is_votable"    : true,
"members": [
{"country": "Denmark", "date_of_birth": "1998-04-04T00:00:00"},
{"country": "Denmark", "date_of_birth": "1999-05-05T00:00:00"}
]
}
PUT /so_test/_doc/
{
"captions_added": true,
"category"      : "Mental breakdown",
"is_votable"    : true,
"members": []
}
POST /so_test/_doc/
{
"captions_added": true,
"category"      : "Mental success",
"is_votable"    : true,
"members": [
{"country": "France", "date_of_birth": "1998-04-04T00:00:00"},
{"country": "Japan", "date_of_birth": "1999-05-05T00:00:00"}
]
}

然后我做了这个查询(它只是一个布尔过滤器,但我想让它为您自己的用例工作应该不会太困难(

GET /so_test/_search
{
"query":{
"bool": {
"filter": {
"script": {
"script": {
"lang": "painless",
"source": """
def flag = false;

// /! notice how the field is referenced /!
if(doc['members.country'].size() != 0)
{
for (item in doc['members.country']) {
if (item == params.country){
flag = true
}
} 
}
return flag;
""",
"params": {
"country": "Japan"
}
}
}
}
}
}
}

顺便说一句,你是说你对无痛的上下文有点困惑。您可以在文档中找到有关它的详细信息。[doc]

在这种情况下,过滤器上下文是我们想要查看的

最新更新