簡體   English   中英

Elasticsearch - 腳本過濾嵌套對象列表

[英]Elasticsearch - Script Filter over a list of nested objects

我試圖找出如何解決我的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 - 過濾文檔,其中數組的第一個元素具有“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
                   }

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

1 - 過濾員工數組大小== 3的文檔

對於第一個問題,最好的做法是添加另一個根級別字段(例如NbEmployees ),其中包含Employee數組中的項目數,以便您可以使用range查詢而不是昂貴的script查詢。

然后,每當您修改Employee數組時,還會相應地更新該NbEmployees字段。 效率更高!

2 - 過濾文檔,其中數組的第一個元素具有“Name”==“John”

關於這個,您需要知道嵌套字段是Lucene中的單獨(隱藏)文檔,因此無法在同一查詢中同時訪問所有嵌套文檔。

如果您知道需要在查詢中檢查第一個員工的姓名,只需添加另一個根級別字段FirstEmployeeName並在該字段上運行查詢。

作為瓦爾注意到,你不能訪問_source的腳本文件查詢在最近版本的Elasticsearch的。 但是elasticsearch允許您在“得分上下文”中訪問此_source

因此,可能的解決方法(但需要注意性能)是在查詢中使用腳本分數和min_score。

您可以通過elasticsearch中嵌套字段值的總和在查詢文檔中查找此堆棧溢出中此行為的示例。

在您的情況下,像這樣的查詢可以完成這項工作:

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

應在參數中設置Employee和first name的數量,以避免腳本重新編譯此腳本的每個用例。

但請記住,Val已經提到過,它可能對您的集群非常沉重。 您應該通過在function_score query添加過濾器(我的示例中為match_all)來縮小您將應用腳本的文檔集。 在任何情況下,它都不是Elasticsearch應該使用的方式,並且你不能期望在這樣的黑客查詢中表現出色。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM