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

yh2wf1be  于 2023-08-03  发布在  ElasticSearch
关注(0)|答案(2)|浏览(166)

我试图找出如何解决这两个问题,我有我的ES 5. 6指数。

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

字符串
我需要创建两个单独的脚本过滤器:
1 -筛选employee数组大小为== 3的文档
2 -过滤数组第一个元素为“Name”==“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
                   }

                     """
                }
              }
            ]
          }
        }
      }
    }
  }
}

tzcvj98z

tzcvj98z1#

正如瓦尔所注意到的,在最近版本的Elasticsearch中,你不能在脚本查询中访问_source文档。但是elasticsearch允许你在“score context”中访问这个_source
因此,一个可能的解决方法(但需要注意性能)是在查询中使用脚本分数和min_score。
你可以在elasticsearch中通过嵌套字段值的总和查询文档的堆栈溢出post中找到这种行为的例子。
在您的情况下,这样的查询可以完成这项工作:

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"
                  }
                }
              }
            }
          ]
        }
      }
}

字符串

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

但是请记住,正如瓦尔已经提到的那样,它可能对您的集群非常沉重。您应该通过在function_score query中添加过滤器(在我的示例中为match_all)来缩小设置范围,将脚本应用于该文档。在任何情况下,这都不是Elasticsearch应该使用的方式,你不能指望这样一个被黑客攻击的查询有出色的表现。

ljsrvy3e

ljsrvy3e2#

1 -筛选employee数组大小为== 3的文档
对于第一个问题,最好的办法是添加另一个根级别字段(例如NbEmployees),它包含Employee数组中的项数,这样您就可以使用range查询,而不是代价高昂的script查询。
然后,每当修改Employee数组时,也会相应地更新NbEmployees字段。效率更高!
2 -过滤数组第一个元素为“Name”==“John”的文档
关于这一点,你需要知道嵌套字段在Lucene中是独立的(隐藏的)文档,所以没有办法在同一个查询中一次访问所有嵌套文档。
如果您知道需要在查询中检查第一个雇员的姓名,只需添加另一个根级别字段FirstEmployeeName并在该字段上运行查询。

相关问题