在elasticsearch过滤器中实现Array.Except(Array2)> 0查询?

Eva*_*tis 6 elasticsearch nest

假设我已将以下文档编入索引:

[
    {
        "Id": 1,
        "Numbers": [1, 2, 3]
    },
    {
        "Id": 2,
        "Numbers": [4, 5]
    }    
]
Run Code Online (Sandbox Code Playgroud)

我有一个参数[1,2,4,5],它定义了哪些数字我不被允许看到 - 我想找到文件,其中"Numbers"数组包含至少一个不在我的输入数组中的元素(所以在这种情况下)应该返回第一份文件).

真实场景是查找哪些(或谁的子组)不包含属于某种产品类型的产品的组.我递归索引产品类型ID(在示例中表示为数字),我想找到包含不属于我的输入参数的产品的组(我的输入参数是产品类型ID的数组,我不允许看到)

我应该使用哪个查询/过滤器以及如何构建它?我考虑过以下几点:

        return desc.Bool(b => b
            .MustNot(mn => mn.Bool(mnb => mnb.Must(mnbm => mnbm.Terms(t => t.ItemGroups, permissions.RestrictedItemGroups) && mnbm.Term(t => t.ItemGroupCount, permissions.RestrictedItemGroups.Count())))));
Run Code Online (Sandbox Code Playgroud)

但问题是如果我有6个受限制的项目组,其中给定的组包含3个受限制的组,那么我将找不到任何匹配项,因为计数将不匹配.这现在有点意义.作为一种解决方法,我在C#中实现了Results.Except(Restricted)以在搜索后过滤掉受限制的组,但是我希望在elasticsearch中实现它.

Val*_*Val 5

新答案

我将离开下面的旧答案,因为它可能对其他人有用.在您的情况下,您希望过滤掉不匹配的文档,而不仅仅标记它们.因此,以下查询将为您提供您所期望的,即只有第一个文档:

POST test/_search
{
  "query": {
    "script": {
      "script": {
        "source": """
          // copy the doc values into a temporary list
          def tmp = new ArrayList(doc.Numbers.values);

          // remove all ids from the params
          tmp.removeIf(n -> params.ids.contains((int)n));

          // return true if the array still contains ids, false if not
          return tmp.size() > 0;
        """,
        "params": {
          "ids": [
            1,
            2,
            4,
            5
          ]
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

较老的答案

解决此问题的一种方法是使用脚本字段,该字段将根据您的条件返回true或false:

POST test/_search
{
  "_source": true,
  "script_fields": {
    "not_present": {
      "script": {
        "source": """
      // copy the numbers array
      def tmp = params._source.Numbers;

      // remove all ids from the params
      tmp.removeIf(n -> params.ids.contains(n));

      // return true if the array still contains data, false if not
      return tmp.length > 0;
""",
        "params": {
          "ids": [ 1, 2, 4, 5 ]
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

结果如下所示:

  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "Id" : 2,
          "Numbers" : [
            4,
            5
          ]
        },
        "fields" : {
          "not_present" : [
            false                           <--- you don't want this doc
          ]
        }
      },
      {
        "_index" : "test",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "Id" : 1,
          "Numbers" : [
            1,
            2,
            3
          ]
        },
        "fields" : {
          "not_present" : [
            true                            <--- you want this one, though
          ]
        }
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)