ElasticSearch 在脚本中访问嵌套文档 - 空指针异常
ElasticSearch Accessing Nested Documents in Script - Null Pointer Exception
要点:尝试使用 painless 在嵌套文档上编写自定义过滤器。想在没有嵌套文档超过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 as indicated in this answer 的用法。它们不适合我们的用例,因为我们需要合并更多自定义逻辑。
不同的教程使用 ctx
、doc
,有些使用 params
。更让人困惑的是 Debug.explain(doc.members)
、Debug.explain(params._source.members)
return 空洞的回复,我很难弄清楚类型。
要点:尝试使用 painless 在嵌套文档上编写自定义过滤器。想在没有嵌套文档超过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]
因此您需要相应地引用它们。
以下是我为让它发挥作用所做的工作。
btw,我一直在用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"}
]
}
然后我做了这个查询(它只是一个 bool 过滤器,但我想让它适用于您自己的用例应该不会太困难)
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"
}
}
}
}
}
}
}
顺便说一句,你说你对 painless 的上下文有点困惑。您可以在文档中找到有关它的详细信息。
[doc]
在这种情况下,filter context 就是我们要查看的那个。
要点:尝试使用 painless 在嵌套文档上编写自定义过滤器。想在没有嵌套文档超过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 as indicated in this answer 的用法。它们不适合我们的用例,因为我们需要合并更多自定义逻辑。
不同的教程使用 ctx
、doc
,有些使用 params
。更让人困惑的是 Debug.explain(doc.members)
、Debug.explain(params._source.members)
return 空洞的回复,我很难弄清楚类型。
要点:尝试使用 painless 在嵌套文档上编写自定义过滤器。想在没有嵌套文档超过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]
因此您需要相应地引用它们。
以下是我为让它发挥作用所做的工作。
btw,我一直在用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"}
]
}
然后我做了这个查询(它只是一个 bool 过滤器,但我想让它适用于您自己的用例应该不会太困难)
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"
}
}
}
}
}
}
}
顺便说一句,你说你对 painless 的上下文有点困惑。您可以在文档中找到有关它的详细信息。 [doc]
在这种情况下,filter context 就是我们要查看的那个。