【发布时间】:2013-03-21 09:11:28
【问题描述】:
如何过滤具有数组字段且元素超过 N 个的文档?
如何过滤包含空数组字段的文档?
分面是解决方案吗?如果有,怎么做?
【问题讨论】:
标签: elasticsearch
如何过滤具有数组字段且元素超过 N 个的文档?
如何过滤包含空数组字段的文档?
分面是解决方案吗?如果有,怎么做?
【问题讨论】:
标签: elasticsearch
我会看看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 > params.param1"
"params" : {
"param1" : 10
}
}
}
【讨论】:
"script": "doc['title'].value.length() > 10" 但没有运气...
groovy.lang.MissingPropertyException: No such property: length for class: java.lang.String
javanna 的答案在 Elasticsearch 1.3.x 及更早版本上是正确的,因为 1.4 的默认脚本模块已更改为 groovy(原为 mvel)。
回答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
【讨论】:
仍然在此处发布与我遇到相同情况的人。 假设您的数据如下所示:
{
"_source": {
"fieldName" : [
{
"f1": "value 11",
"f2": "value 21"
},
{
"f1": "value 12",
"f2": "value 22"
}
]
}
}
然后过滤长度> 1的fieldName,例如:
"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。
【讨论】:
doc['fieldName.f1'].length > 2 在 es 7.x 上工作正常
恕我直言,使用脚本按大小过滤数组的正确方法是:
"filter" : {
"script" : {
"script" : "_source.fieldName.size() > 1"
}
}
如果我按照@javanna 的建议这样做,它会抛出异常groovy.lang.MissingPropertyException: No such property: length for class: java.lang.String
【讨论】:
fieldName,其他人使用了fieldname。
Groovy 为数组和字符串都提供了size()。如果不是 all 您的值都是数组,那么您将遇到您所做的问题,因为您尝试在不存在的字符串上使用长度 property .
如果您有一组未映射为 nested 的 对象,请记住,Elastic 会将它们展平为:
attachments: [{size: 123}, {size: 456}] --> attachments.size: [123, 456]
因此,您希望将您的字段引用为 doc['attachments.size'].length,而不是 doc['attachments'].length,这非常违反直觉。
doc.containsKey(attachments.size) 也一样。
.values 部分已弃用且不再需要。
【讨论】:
关于 lisak 的回答。
有 size() 函数返回列表的长度:
"filter" : {
"script" : {
"script" : "doc['fieldname'].values.size() > 10"
}
}
【讨论】:
最简单的方法是“非规范化”您的数据,以便您拥有一个包含计数和布尔值(如果存在或不存在)的属性。然后你就可以搜索这些属性了。
例如:
{
"id": 31939,
"hasAttachments": true,
"attachmentCount": 2,
"attachments": [
{
"type": "Attachment",
"name": "txt.txt",
"mimeType": "text/plain"
},
{
"type": "Inline",
"name": "jpg.jpg",
"mimeType": "image/jpeg"
}
]
}
【讨论】:
当您需要查找包含某个大小/长度应大于零的字段的文档时,@javanna 给出了正确答案。我只想添加如果您的 字段是文本字段 并且您想查找包含该字段中某些文本的文档,您不能使用相同的查询。您将需要执行以下操作:
GET index/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"FIELD_NAME": {
"gt": 0
}
}
}
]
}
}
}
这不是这个问题的确切答案,因为答案已经存在,但是我遇到的类似问题的解决方案,所以也许有人会觉得它有用。
【讨论】:
关于第二个问题的建议:
如何过滤包含空数组字段的文档?
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "fieldname"
}
}
}
}
}
将返回带有空 fieldname: [] 数组的文档。 must(而不是 must_not 将返回相反的结果)。
【讨论】:
这对我有用:
GET index/search {
"query": {
"bool": {
"filter" : {
"script" : {
"script" : "doc['FieldName'].length > 10"
}
}
}
}
}
【讨论】: