elasticsearch根据作为数组的字段的大小进行过滤

时间:2013-03-21 09:11:29

标签: elasticsearch

如何过滤具有数组且具有多于N个元素的字段的文档?

如何过滤具有空数组字段的文档?

方面是解决方案吗?如果是这样,怎么样?

9 个答案:

答案 0 :(得分:51)

我会看一下script filter。以下过滤器应仅返回fieldname字段中至少包含10个元素的文档,该字段是一个数组。请记住,这可能会很昂贵,具体取决于索引中包含的文档数量。

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

关于第二个问题:那你真的有一个空阵列吗?或者它只是一个没有值的数组字段?您可以使用missing filter获取对特定字段没有价值的文档:

"filter" : {
    "missing" : { "field" : "user" }
}

否则我猜你需要再次使用脚本,类似于我上面提到的,只是输入的长度不同。如果长度是常量,我会把它放在params部分,这样脚本将被elasticsearch缓存并重复使用,因为它始终是相同的:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > param1"
        "params" : {
            "param1" : 10
        }
    }
}

答案 1 :(得分:12)

javanna的回答在Elasticsearch 1.3.x及更早版本中是正确的,因为1.4默认脚本模块已更改为groovymvel)。

回答OP的问题。

在Elasticsearch 1.3.x及更早版本中,请使用以下代码:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.length > 10"
    }
}

在Elasticsearch 1.4.x及更高版本中,使用以下代码:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.size() > 10"
    }
}

此外,在Elasticsearch 1.4.3及更高版本中,由于安全性问题,您需要启用动态脚本,因为默认情况下已禁用该脚本。请参阅:https://www.elastic.co/guide/en/elasticsearch/reference/1.4/modules-scripting.html

答案 2 :(得分:6)

Imho使用脚本按大小过滤数组的正确方法是:

"filter" : {
    "script" : {
        "script" : "_source.fieldName.size() > 1"
    }
}

如果我这样做,因为@javanna建议它抛出异常groovy.lang.MissingPropertyException: No such property: length for class: java.lang.String

答案 3 :(得分:5)

还在这里贴出与我相同情况的人。 假设您的数据如下所示:

{
    "_source": {
        "fieldName" : [
            {
                "f1": "value 11",
                "f2": "value 21"
            },
            {
                "f1": "value 12",
                "f2": "value 22"
            }
        ]
    }
}

然后过滤fieldName长度>例如1:

"query": {
    "bool" : {
        "must" : {
            "script" : {
                "script" : {
                    "inline": "doc['fieldName.f1'].values.length > 1",
                    "lang": "painless"
                 }
            }
        }
    }
}

脚本语法与ES 5.4文档https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html一样。

答案 4 :(得分:4)

基于此: https://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/collect/RegularImmutableList.java?r=707f3a276d4ea8e9d53621d137febb00cd2128da

依赖于里萨克的回答。

有size()函数返回列表的长度:

"filter" : {
    "script" : {
        "script" : "doc['fieldname'].values.size() > 10"
    }
}

答案 5 :(得分:2)

最简单的方法是对数据进行“非规范化”,以便拥有包含计数的属性和布尔值(如果存在或不存在)。然后你可以搜索这些属性。

例如:

{
   "id": 31939,
   "hasAttachments": true,
   "attachmentCount": 2,
   "attachments": [
      {
         "type": "Attachment",
         "name": "txt.txt",
         "mimeType": "text/plain"
      },
      {
         "type": "Inline",
         "name": "jpg.jpg",
         "mimeType": "image/jpeg"
      }
   ]  
}

答案 6 :(得分:2)

如果您有未映射为nested object 数组,请记住Elastic会将其展平为:

attachments: [{size: 123}, {size: 456}] --> attachments.size: [123, 456]

因此,您要将字段引用为doc['attachments.size'].length,而不是doc['attachments'].length,这很违反直觉。

doc.containsKey(attachments.size)相同。

.values部分已弃用,不再需要。

答案 7 :(得分:1)

当您需要查找包含某些字段的文档时,该字段的大小/长度应该更大,然后零@javanna给出了正确的答案。我只想添加如果您的字段是文本字段,并且您想查找包含该字段中某些文本的文档,则不能使用相同的查询。您将需要执行以下操作:

GET index/_search 
{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "FIELD_NAME": {
                            "gt": 0
                        }
                    }
                }
            ]
        }
    }
}

这不是对这个问题的确切答案,因为答案已经存在,但是我已经解决了类似问题,所以也许有人会觉得有用。

答案 8 :(得分:0)

关于第二个问题的建议:

<块引用>

如何过滤包含空数组字段的文档?

{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "fieldname"
        }
      }
    }
  }
}

将返回带有空 fieldname: [] 数组的文档。 must(而不是 must_not 会返回相反的结果)。