在无痛脚本的Array包含方法的框架下,无痛到底做了什么

时间:2019-09-30 08:11:35

标签: elasticsearch elasticsearch-painless

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

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

字段sth是数组的类型。

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

它失败了,我读了此article,了解它失败的原因,因为我必须通过一个 Long改为contains方法,因此我将无痛脚本更改为 doc['sth'].values.contains(1L)

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

脚本

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

两者都可以工作,好吧,我读了painless document,了解整数类型将被提升为长类型。

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

  

如果在原始类型值和引用类型值之间进行比较。

是否会引发错误?还是在某处自动取消装箱/装箱?

尽管如此,我还是写了剧本 doc['sth'].values[0] instanceof Longdoc['sth'].values[0] instanceof long, 两者都可以工作并返回true。

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

最后,来到主题问题,在无痛脚本的Array contains方法的幕后,无痛到底做了什么。

这只是我不负责任的猜测

Array::contains是否具有contains(Object o)之类的签名,并使用== 将参数与其存储进行比较?

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

1 个答案:

答案 0 :(得分:1)

values实际上是ScriptDocValues类型(AbstractList的抽象子类)。对于用long键入的字段,实际的具体实现是ScriptDocValues.Longs

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

如您所见,这些值在内部存储在long数组(原始类型)中。但是,get()方法返回Long(装箱的类型)以满足AbstractList的约定,而getValue()返回从调用中取消装箱的原语longget()。这就是doc['sth'].values[0] == 1doc['sth'].values[0] == 1L都成功的原因。

如果您致电get()并且没有文档值,则会收到IllegalStateException声明应该...

  

使用doc []。size()== 0检查文档是否缺少字段!