【问题标题】:ElasticSearch NEST combining AND with OR queriesElasticSearch NEST 结合 AND 和 OR 查询
【发布时间】:2018-06-03 12:33:24
【问题描述】:

问题

如何编写 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 = "" )
)

相关文档解读

Writing Bool Queries 中的“将查询与 || 或 should 子句组合” 提到了

bool 查询并不完全遵循您对编程语言所期望的布尔逻辑。 term1 &amp;&amp; (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"}
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

文档

【问题讨论】:

    标签: elasticsearch nest elasticsearch-5


    【解决方案1】:

    使用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 子句中,它仍然是查询的匹配项(但 相关性得分较低)。

    如果这是意图,则可以构造此查询using the longer form of the Bool query

    【讨论】:

    • 我已经添加了其余所需的布尔逻辑。需要明确的是,truckOemName、truckModelName、partCategoryCode、partId 存在 AND(匹配 serialRange 或 null serialRange)始终是必需的。您能否添加一个使用较长形式的 Bool 查询而没有与此匹配的重载的 NEST 查询?我将开始搞乱重写以删除这些重载。
    • 暂时将此标记为答案,直到我有时间在没有运算符重载的情况下测试和编写 NEST 查询。这就是为什么它不起作用但代码不起作用的原因。
    猜你喜欢
    • 1970-01-01
    • 2016-06-06
    • 2020-07-11
    • 2021-12-04
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 2012-11-03
    相关资源
    最近更新 更多