Elasticsearch-脚本过滤嵌套对象列表



我试图弄清楚如何解决我对ES 5.6索引遇到的两个问题。

"mappings": {
    "my_test": {
        "properties": {
            "Employee": {
                "type": "nested",
                "properties": {
                    "Name": {
                        "type": "keyword",
                        "normalizer": "lowercase_normalizer"
                    },
                    "Surname": {
                        "type": "keyword",
                        "normalizer": "lowercase_normalizer"
                    }
                }
            }
        }
    }
}

我需要创建两个单独的脚本过滤器:

1-滤波器文档,其中员工数组的大小为== 3

2-滤波器文档,其中数组的第一个元素具有"名称" ==" John"

我试图迈出一些第一步,但是我无法迭代列表。我总是有一个空指针异常错误。

{
  "bool": {
    "must": {
      "nested": {
        "path": "Employee",
        "query": {
          "bool": {
            "filter": [
              {
                "script": {
                  "script" :     """
                   int array_length = 0; 
                   for(int i = 0; i < params._source['Employee'].length; i++) 
                   {                              
                    array_length +=1; 
                   } 
                   if(array_length == 3)
                   {
                     return true
                   } else 
                   {
                     return false
                   }
                     """
                }
              }
            ]
          }
        }
      }
    }
  }
}

正如Val所注意到的,您无法访问Elasticsearch最近版本中脚本查询中文档的_source。但是Elasticsearch允许您在"得分上下文"中访问此_source

因此,可能的解决方法(但是您需要谨慎性能(是使用脚本分数与查询中的min_score结合在一起。

您可以在此堆栈溢出的查询文档中找到此行为的示例。

中的嵌套字段值的总和。

在您的情况下,这样的查询可以完成工作:

POST <your_index>/_search
{
      "min_score": 0.1,
      "query": {
        "function_score": {
          "query": {
            "match_all": {}
          },
          "functions": [
            {
              "script_score": {
                "script": {
                  "source": """
                    if (params["_source"]["Employee"].length === params.nbEmployee) {
                      def firstEmployee = params._source["Employee"].get(0);
                      if (firstEmployee.Name == params.name) {
                        return 1;
                      } else {
                        return 0;
                      }
                    } else {
                      return 0;
                    }
                  """,
                  "params": {
                    "nbEmployee": 3,
                    "name": "John"
                  }
                }
              }
            }
          ]
        }
      }
}

应该在参数中设置员工数量和名字的数量,以避免对此脚本的每个用例重新编译脚本。

,请记住,正如已经提到的val,在群集上可能非常沉重。您应该通过在function_score query中添加过滤器(在我的示例中(添加过滤器来缩小设置文档的应用。无论如何,这不是应该使用Elasticsearch的方式,并且您不能期望使用这种黑客查询的表现出色。

1-滤波器文档,其中员工数组的大小为== 3

对于第一个问题,最好的办法是添加另一个根级字段(例如NbEmployees(,该字段包含Employee数组中的项目数,以便您可以使用range查询而不是昂贵的script查询。

然后,每当您修改Employee数组时,您也可以相应地更新该NbEmployees字段。效率要高得多!

2-滤波器文档,其中数组的第一个元素具有"名称" ==" John"

关于这一点,您需要知道嵌套字段是Lucene中的单独(隐藏(文档,因此无法在同一查询中立即访问所有嵌套的文档。

如果您知道您需要在查询中检查第一个员工的姓名,只需添加另一个根级字段FirstEmployeeName并在该问题上运行查询。

最新更新