ElasticSearch NEST:将AND与OR查询组合

4

问题

如何编写NEST代码来生成此简单布尔逻辑的弹性搜索查询?

term1 && (term2 || term3 || term4)

我使用Nest(5.2)语句查询ElasticSearch(5.2)的实现逻辑伪代码如下:

// additional requirements
( truckOemName = "HYSTER" && truckModelName = "S40FT" && partCategoryCode = "RECO" && partID != "")

//Section I can't get working correctly
AND (
    ( SerialRangeInclusiveFrom <= "F187V-6785D" AND SerialRangeInclusiveTo >= "F187V-6060D" )
    OR 
    ( SerialRangeInclusiveFrom = "" || SerialRangeInclusiveTo = "" )
)

相关文档的解释

编写布尔查询中的"使用||或should子句组合查询"提到:

bool查询与编程语言中您期望的布尔逻辑不完全相同。 term1 && (term2 || term3 || term4) 不会变成

bool
|___must
|   |___term1
|
|___should
   |___term2
   |___term3
   |___term4

您可以获得仅包含term1的结果

这正是我认为正在发生的事情。

但他们解决这个问题的答案超出了我如何在Nest中应用它的理解范围。答案是?

  1. 添加括号以强制评估顺序(我正在做)
  2. 使用boost因子?(什么?)

代码

这是NEST代码

 var searchDescriptor = new SearchDescriptor<ElasticPart>();
 var terms = new List<Func<QueryContainerDescriptor<ElasticPart>, QueryContainer>>
 {
     s =>
         (s.TermRange(r => r.Field(f => f.SerialRangeInclusiveFrom)
              .LessThanOrEquals(dataSearchParameters.SerialRangeEnd))
          &&
          s.TermRange(r => r.Field(f => f.SerialRangeInclusiveTo)
              .GreaterThanOrEquals(dataSearchParameters.SerialRangeStart)))
         //None of the data that matches these ORs returns with the query this code generates, below.
         ||
         (!s.Exists(exists => exists.Field(f => f.SerialRangeInclusiveFrom))
          ||
          !s.Exists(exists => exists.Field(f => f.SerialRangeInclusiveTo))
         )
 };

 //Terms is the piece in question
 searchDescriptor.Query(s => s.Bool(bq => bq.Filter(terms))
     && !s.Terms(term => term.Field(x => x.OemID)
         .Terms(RulesHelper.GetOemExclusionList(exclusions))));

 searchDescriptor.Aggregations(a => a
     .Terms(aggPartInformation, t => t.Script(s => s.Inline(script)).Size(50000))
 );
 searchDescriptor.Type(string.Empty);
 searchDescriptor.Size(0);

 var searchResponse = ElasticClient.Search<ElasticPart>(searchDescriptor);

这是生成的ES JSON查询:
{
   "query":{
      "bool":{
         "must":[
            {
               "term":{ "truckOemName": { "value":"HYSTER" }}
            },
            {
               "term":{ "truckModelName": { "value":"S40FT" }}
            },
            {
               "term":{ "partCategoryCode": { "value":"RECO" }}
            },
            {
               "bool":{
                  "should":[
                     {
                        "bool":{
                           "must":[
                              {
                                 "range":{ "serialRangeInclusiveFrom": { "lte":"F187V-6785D" }}
                              },
                              {
                                 "range":{ "serialRangeInclusiveTo": { "gte":"F187V-6060D" }}
                              }
                           ]
                        }
                     },
                     {
                        "bool":{
                           "must_not":[
                              {
                                 "exists":{ "field":"serialRangeInclusiveFrom" }
                              }
                           ]
                        }
                     },
                     {
                        "bool":{
                           "must_not":[
                              {
                                 "exists":{ "field":"serialRangeInclusiveTo" }
                              }
                           ]
                        }
                     }
                  ]
               }
            },
            {
               "exists":{
                  "field":"partID"
               }
            }
         ]
      }
   }
}

这是我们想要生成的查询,似乎可以正常工作。
{
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "must": [
              {
                "term": { "truckOemName": { "value": "HYSTER" }}
              },
              {
                "term": {"truckModelName": { "value": "S40FT" }}
              },
              {
                "term": {"partCategoryCode": { "value": "RECO" }}
              },
              {
                "exists": { "field": "partID" }
              }
            ],
            "should": [
              {
                "bool": {
                  "must": [
                    {
                      "range": { "serialRangeInclusiveFrom": {"lte": "F187V-6785D"}}
                    },
                    {
                      "range": {"serialRangeInclusiveTo": {"gte": "F187V-6060D"}}
                    }
                  ]
                }
              },
              {
                "bool": {
                  "must_not": [
                    {
                      "exists": {"field": "serialRangeInclusiveFrom"}
                    },
                    {
                      "exists": {  "field": "serialRangeInclusiveTo"}
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

文档

注意:请勿删除 HTML 标记。
1个回答

2

使用重载运算符对 bool 查询进行操作时,无法表达 must 子句与 should 子句的组合,例如:

term1 && (term2 || term3 || term4)

变成

bool
|___must
   |___term1
   |___bool
       |___should
           |___term2
           |___term3
           |___term4

这是一个带有两个must子句的bool查询,其中第二个must子句是一个bool查询,至少要匹配一个should子句。NEST之所以这样组合查询,是因为它符合.NET中布尔逻辑的期望。

如果它变成了

bool
|___must
|   |___term1
|
|___should
   |___term2
   |___term3
   |___term4

如果一个文档只满足 must 条款,那么它将被视为匹配。在这种情况下,should 子句充当增强项,即如果文档除了满足 must 条件外还匹配一个或多个 should 子句,则其相关性得分会更高,假设 term2term3term4 是计算相关性得分的查询。

基于此,您想要生成的查询表达式是:对于一个文档来说,要被视为匹配,它必须匹配 must 条件中的所有 4 个查询。

"must": [
  {
    "term": { "truckOemName": { "value": "HYSTER" }}
  },
  {
    "term": {"truckModelName": { "value": "S40FT" }}
  },
  {
    "term": {"partCategoryCode": { "value": "RECO" }}
  },
  {
    "exists": { "field": "partID" }
  }
],

对于匹配 must 子句的文档,如果:

  1. 它的 serialRangeInclusiveFrom 小于或等于 "F187V-6785D"serialRangeInclusiveFrom 大于或等于 "F187V-6060D"

    或者

  2. serialRangeInclusiveFromserialRangeInclusiveTo

则提高该文档的相关性得分。关键点是:

如果一个文档匹配了 must 子句但没有匹配任何一个 should 子句,则仍然会被视为查询的匹配项(但具有较低的相关性得分)。

如果这是意图,请使用更长的 Bool 查询形式构建此查询,详情请参见此处


我已经添加了其余所需的布尔逻辑。明确指出,truckOemName、truckModelName、partCategoryCode、partId存在,并且(匹配的serialRange或null serialRange)始终是必需的。您能否添加一个NEST查询,使用较长形式的“Bool”查询,而不是与此匹配的重载?我将开始尝试重写以删除那些重载。 - w00ngy
暂时将此标记为答案,直到我有时间测试并编写没有运算符重载的NEST查询。这就是为什么它不起作用,但不是代码可以正常工作的原因。 - w00ngy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接