【问题标题】:elasticsearch filtering by the size of a field that is an arrayelasticsearch按数组字段的大小过滤
【发布时间】:2013-03-21 09:11:28
【问题描述】:

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

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

分面是解决方案吗?如果有,怎么做?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    我会看看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" 但没有运气...
    • 我也有同样的问题,字段是一个数组,但是ES把它看成String,所以会抛出groovy.lang.MissingPropertyException: No such property: length for class: java.lang.String
    • @lisak 试试这个:"script": "doc['fieldname'].size() > 50"
    • @david_adler 我为这类问题发布了答案(当字段是文本字段时)。 stackoverflow.com/a/54213332/1987830
    【解决方案2】:

    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

    【讨论】:

      【解决方案3】:

      仍然在此处发布与我遇到相同情况的人。 假设您的数据如下所示:

      {
          "_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 上工作正常
      【解决方案4】:

      恕我直言,使用脚本按大小过滤数组的正确方法是:

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

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

      【讨论】:

      • Source 比 doc 慢得多,它会命中磁盘。
      • 另外,请注意您使用了fieldName,其他人使用了fieldname
      • 原因是Groovy 为数组和字符串都提供了size()。如果不是 all 您的值都是数组,那么您将遇到您所做的问题,因为您尝试在不存在的字符串上使用长度 property .
      • ``` "caused_by": { "type": "illegal_argument_exception", "reason": "变量 [_source] 未定义。" } ```
      【解决方案5】:

      如果您有一组未映射为 nested对象,请记住,Elastic 会将它们展平为:

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

      因此,您希望将您的字段引用为 doc['attachments.size'].length,而不是 doc['attachments'].length,这非常违反直觉。

      doc.containsKey(attachments.size) 也一样。

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

      【讨论】:

        【解决方案6】:

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

        关于 lisak 的回答。

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

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

        【讨论】:

          【解决方案7】:

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

          例如:

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

          【讨论】:

            【解决方案8】:

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

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

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

            【讨论】:

            • 在索引时计算它会更聪明,而不是在搜索时计算它会很慢,因为它必须经过所有命中。特别是如果您有 match_all 查询。
            【解决方案9】:

            关于第二个问题的建议:

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

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

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

            【讨论】:

              【解决方案10】:

              这对我有用:

              GET index/search {
                  "query": {
                     "bool": {
                        "filter" : {
                           "script" : {
                              "script" : "doc['FieldName'].length > 10"
                              }
                          }
                       }
                     }
              }
              

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              猜你喜欢
              • 2016-04-03
              • 2021-08-23
              • 2014-11-17
              • 1970-01-01
              • 2021-10-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多