在 painless 脚本的 Array contains 方法的幕后,painless 到底做了什么

what exactly does painless do under the hood of painless script's Array contains method

假设我有一个如下所示的文档映射字段

{
    "template": {
        "mappings":{
            "template":{
                "properties": {
                    "sth": {
                        "type": "long"
                    }
                }
            }
        }
    }
}

字段sth为数组类型

我想检查字段 sth 是否包含一个值,所以我写了无痛脚本 doc['sth'].values.contains(1)

它失败了,我读了这个 article,明白为什么它失败了,因为我必须通过一个 Longcontains 方法,所以我将无痛脚本更改为 doc['sth'].values.contains(1L)

它有效,但一些进一步的实验让我更加疲惫。

剧本

doc['sth'].values[0] == 1doc['sth'].values[0] == 1L

两者都可以,好的,我阅读了painless document,了解到整数类型将被提升为long类型。

但是doc['sth'].values[0] == Integer.valueOf(156)也可以,但是根据文档

If a comparison is made between a primitive type value and a reference type value.

它应该引发错误吗?或者自动 unboxing/boxing 发生在某处?

尽管如此,我写了脚本 doc['sth'].values[0] instanceof Longdoc['sth'].values[0] instanceof long, 两者都可以工作 return true.

无痛数组类型存储的是原始类型,还是装箱引用类型?

最后,来到主题问题,painless 脚本的 Array contains 方法背后到底做了什么。

这只是我不负责任的猜测

Array::contains有一个类似contains(Object o)的签名,用==来 将参数与其存储进行比较?

但如果这是真的,为什么 doc['sth'].values[0] == 1 成功但 doc['sth'].values[0] == 1 失败?

values 实际上是 ScriptDocValues (an abstract subclass of AbstractList). For a field typed with long, the actual concrete implementation is ScriptDocValues.Longs.

类型

因此,为了回答您的问题,在幕后,.contains() 方法将简单地委托给 AbstractCollection.contains(),后者在幕后调用 .equals()。这就是 doc['sth'].values.contains(1) 失败而 doc['sth'].values.contains(1L) 成功的原因。

如您所见,这些值在内部存储在 long 数组(原始类型)中。然而,get()方法returns一个Long(盒装类型)为了满足AbstractList契约和getValue()returns一个原始long 从对 get() 的调用中拆箱。这就是 doc['sth'].values[0] == 1doc['sth'].values[0] == 1L 都成功的原因。

如果您调用 get() 并且没有文档值,您将得到一个 IllegalStateException 说明您应该...

use doc[].size()==0 to check if a document is missing a field!