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的用法,如这个答案所示。它们不适合我们的用例,因为我们需要包含更多的自定义逻辑。
不同的教程使用ctx
、doc
,有些使用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]
在这种情况下,过滤器上下文是我们想要查看的