【问题标题】:Compare sum of nested fields比较嵌套字段的总和
【发布时间】:2020-08-19 12:07:19
【问题描述】:

我正在尝试创建将嵌套属性与非嵌套属性进行比较的请求

映射:

{
    "mappings": {
        "publishers": {
            "properties": {
                "Accounts": {
                    "type": "nested",
                    "properties": {
                        "FollowersCount": {
                            "type": "long"
                        }
                    }
                },
                "TotalSubscribers": {
                    "type": "long"
                }
            }
        }
    }
}

我想查找 Accounts.FollowersCount 的总和不等于 TotalSubscribers 的文档。

怎么做?

PS: 我正在尝试创建这样的东西:

{
    "_source": [
        "TotalSubscribers",
        "Accounts.FollowersCount"
    ],
    "query": {
        "bool": {
            "filter": {
                "script": {
                    "script": {
                        "source": "int total = 0; for (int i = 0; i < doc['Accounts'].length; ++i) {total += doc['Accounts'][i].FollowersCount;} return total == doc['TotalSubscribers'];",
                        "lang": "painless"
                    }
                }
            }
        }
    }
}

但它不起作用。当我将脚本移动到嵌套块中时,同样的问题。然后我无法访问 TotalSubscribers

更新1: ES 版本 = 6.8

请求1

{
    "query": {
        "term": {
            "PublisherId": 349438
        }
    },
    "script": {
        "source": "ctx._source.TotalSubscribers = ctx._source.Accounts.stream().map(a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));"
    }
}

错误:

{
    "error": {
        "root_cause": [
            {
                "type": "script_exception",
                "reason": "runtime error",
                "script_stack": [
                    "java.util.stream.Collectors.lambda$summingInt$11(Collectors.java:467)",
                    "java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)",
                    "java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)",
                    "java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)",
                    "java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)",
                    "java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)",
                    "java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)",
                    "java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)",
                    "java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)",
                    "a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));",
                    "                                                     ^---- HERE"
                ],
                "script": "ctx._source.TotalSubscribers = ctx._source.Accounts.stream().map(a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));",
                "lang": "painless"
            }
        ],
        "type": "script_exception",
        "reason": "runtime error",
        "script_stack": [
            "java.util.stream.Collectors.lambda$summingInt$11(Collectors.java:467)",
            "java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)",
            "java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)",
            "java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)",
            "java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)",
            "java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)",
            "java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)",
            "java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)",
            "java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)",
            "a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));",
            "                                                     ^---- HERE"
        ],
        "script": "ctx._source.TotalSubscribers = ctx._source.Accounts.stream().map(a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));",
        "lang": "painless",
        "caused_by": {
            "type": "null_pointer_exception",
            "reason": null
        }
    },
    "status": 500
}

请求2

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "PublisherId": 349438
                    }
                }
            ]
        }
    },
    "script": {
        "source": "int total = 0; for(int i=0;i<=ctx._source.Accounts.size()-1;i++){total += ctx._source.Accounts[i].FollowersCount} ctx._source['TotalSubscribers'] = total"
    }
}

也有错误,靠近“total += ctx._source.Accounts[i].FollowersCount

请求3

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "PublisherId": 349438
                    }
                }
            ]
        }
    },
    "script": {
        "source": "int total = 0; for(int i=0;i<=ctx._source.Accounts.size()-1;i++){total += i} ctx._source['TotalSubscribers'] = total"
    }
}

工作正常,更新后 totalSubscribers == count Account items。但是需要获取 Accounts 属性,而不是我...

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    这可以通过script 查询解决,但由于无法访问script 查询中的嵌套文档,因此您必须采取不同的方式。在这些情况下,在顶层添加一个包含FollowersCount 总和的新字段总是容易得多,您可以将其命名为TotalFollowersCount

    首先,您需要使用_update_by_query 端点创建该字段,如下所示:

    POST your-index/_update_by_query
    {
      "script": {
        "source": """
        ctx._source.TotalFollowersCount = ctx._source.Accounts
          .stream()
          .map(a -> a.FollowersCount ?: 0)
          .collect(Collectors.summingInt(Integer::intValue));
        """
      }
    }
    

    然后您可以使用script 查询来查找有问题的文档:

    GET your-index/_search
    {
      "query": {
        "script": {
          "script": "doc.TotalFollowersCount.value != doc.TotalSubscribers.value"
        }
      }
    }
    

    【讨论】:

    • { "query": { "term": { "PublisherId": 349438 } }, "script": { "source": "ctx._source.TotalSubscribers = ctx._source.Accounts.stream().map(a -&gt; a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));" } } 错误:"a -> a.FollowersCount).collect(Collectors.summingInt(Integer::intValue));", "^---- HERE" Integer:: 附近出错整数值
    • 也许用完整的错误更新你的问题,它更清晰......你能告诉你正在使用哪个版本的ES吗?
    • 我已经通过查询脚本更新了更新,请重试
    • 太棒了!太好了!
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-07
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    相关资源
    最近更新 更多