ElasticSearch从指定的术语中查找具有不同嵌套列表元素的索引对象

时间:2017-06-16 17:21:55

标签: c# elasticsearch nest elasticsearch-painless

假设我们有一个学生,其中包含得分嵌套列表,如下所示:

public class Student
{
    public string FullName { get; set; }
    public List<Score> Scores { get; set; } = new List<int>();
}

public class Score
{
    public int Value { get; set; }
}

如何使用 NEST (或简单查询)编写 ElasticSearch 查询,以便让所有至少有2个不同分数的学生从7到10。

因此,例如,如果一个学生得分{2,7,10}或{8,10},他应该在我们的结果中,而一个学生{10,6,5}或{8,8}或{2,7}不应该进入我们的结果。

我想出的是:

GET /index/student/_search
{
  "query": {
    "nested": {
      "path": "scores",
      "query": {
        "bool": {
          "should":
          [
            {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "scores.value": [7, 10] 
                    }
                  },
                  {
                    "terms":{
                      "scores.value": [8, 9]
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "scores.value": [7, 8] 
                    }
                  },
                  {
                    "terms":{
                      "scores.value": [9, 10]
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
}

但ElasticSearch似乎不允许 TERMS 查询的连接(返回0次点击)。即使它确实有效,我仍然需要更优雅的东西,因为如果我们有超过4个允许值,这将成为一种痛苦。

更新

我已尝试过以下脚本,但也获得了0个结果:

GET /index/student/_search
{
  "query": {
    "nested": {
      "path": "scores",
      "query": {
        "bool": {
          "filter": [
            {
              "exists": {
                "field": "scores"
              }
            },
            {
              "script": {
                "script": """
                   boolean condition = false;
                   def availableScores = [7, 8, 9, 10];
                   def scores = doc['scores.id'].values;
                   
                   for (int i = 0; i < scores.length; i++)
                    for(int j = 0; j < availableScores.length; j++)
                      if (scores[i] == availableScores[j])
                      {
                        if (condition == true) 
                          return (true);
                          
                        condition = true;
                        availableScores.remove(j);
                        break;
                      } 
                   return (false)"""
              }
            }
          ]
        }
      }
    }
  }
}

1 个答案:

答案 0 :(得分:1)

过了一会儿,我找到了一个有效的查询:

GET /index/student/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              {
                "nested": {
                  "path": "scores",
                  "query": {
                    "terms": {
                      "scores.value": [
                        7,
                        10
                      ]
                    }
                  }
                }
              },
              {
                "nested": {
                  "path": "scores",
                  "query": {
                    "terms": {
                      "scores.value": [
                        8,
                        9
                      ]
                    }
                  }
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "nested": {
                  "path": "scores",
                  "query": {
                    "terms": {
                      "scores.value": [
                        7,
                        9
                      ]
                    }
                  }
                }
              },
              {
                "nested": {
                  "path": "scores",
                  "query": {
                    "terms": {
                      "scores.value": [
                        8,
                        10
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

这里的技巧是将1个嵌套查询分成多个,并将它们放在should查询中。

我仍然想要一个更优雅的解决方案(通过script,我猜),但就目前而言,我将其作为最终答案。