如何在弹性搜索查询中组合和

Posted

技术标签:

【中文标题】如何在弹性搜索查询中组合和【英文标题】:how to combine and with or in an elastic search query 【发布时间】:2019-11-25 06:17:10 【问题描述】:

我正在使用 elasticsearch 开发产品搜索功能,但无法弄清楚如何在嵌套查询中表示以下逻辑:

(A 或 B)&&(C 或 D)

我希望它像传统的编程语言一样工作,它必须匹配每组 or 条件中的一个才能使产品匹配(例如,我不希望 or 条件仅仅提高我的分数不满足至少一个条件的产品不被选中)。

在我的特殊情况下,A、B、C、D 都是针对嵌套属性(类别记录列表)的测试。

这里有两个示例索引记录来说明:


  "ProductId":1111,
  "Name":"First Product",
  "AllCategories":[
    "CatId":15,"CatName":"Some Tag Name", "ParentCatId":99, "ParentCatName":"Tags",
    "CatId":352,"CatName":"Some child menu", "ParentCatId":88, "ParentCatName":"Some parent menu"
        ]
,


  "ProductId":2222,
  "Name":"Second Product",
  "AllCategories":[
    "CatId":20,"CatName":"Some Tag Name2", "ParentCatId":99, "ParentCatName":"Tags",
    "CatId":352,"CatName":"Some child menu", "ParentCatId":88, "ParentCatName":"Some parent menu"
        ]

我已经尝试了很多不同的查询变体,但一直无法找到一种可以按照我想要的方式工作的变体。这张票问的是同样的基本问题,但唯一提供的答案对我不起作用(我下面的代码是根据这张票的答案建模的:Elastic search combine two must with OR



   "query":
      "bool":
         "must":[
         
            "nested":
               "path":"AllCategories",
               "query":
                  "bool": 
                     "must": [
                        
                           "bool":
                              "minimum_should_match": 1,
                              "should":[
                             "term":"AllCategories.CatId":"value":352  ,
                        "term":"AllCategories.ParentCatId":"value":352  
                              ]
                           
                        ,
                        
                           "bool":
                              "minimum_should_match": 1,
                              "should":[
                             "term":"AllCategories.CatId":"value":15  ,
                             "term":"AllCategories.CatId":"value":8   
                              ]
                           
                        
                     ]
                  
               
            
         ]
      
   



更新: 根据发布的答案,我将查询重新格式化如下,但它仍然不适合我。这是导致问题的嵌套查询中的第二个布尔值。我想知道在两种条件下测试嵌套子查询中的同一字段是否可能是一个问题(AllCategories.CatId):

    
     "query":
        "bool":
         "must":[
         
            "nested":
                 "path":"AllCategories",
                 "query":
                    "bool": 
                     "minimum_should_match": 2,
                     "should": [
                        
                             "bool":
                                "minimum_should_match": 1,
                                "should":[
                                  "term":"AllCategories.CatId":"value":352  ,
                             "term":"AllCategories.ParentCatId":"value":352  
                                ]
                             
                        ,
                        
                             "bool":
                                "minimum_should_match": 1,
                                "should":[
                                 "term":"AllCategories.CatId":"value":15  ,
                                 "term":"AllCategories.CatId":"value":8   
                                ]
                             
                        
                     ]
                    
                 
            
         ]
        
     
    

这是相关索引的映射


  "mappings": 
    "properties": 
        "ProductId":  "type": "integer" ,
        "Name":  "type": "text" ,
        "AllCategories":  
            "type": "nested",
            "properties":  
                "CatId":  "type": "integer"  ,
                "ParentCatId":  "type": "integer" ,
                "CatName":  "type": "text" ,
                "ParentCatName":  "type": "text" 
            
        
        "SalesRank":  "type": "integer" 
        
    
   


使用示例产品,我希望搜索返回产品 1111 但不返回产品 2222(产品 1111 确实包含 cat 15 和 cat8 之一。产品 2222 至少不包含两者之一. 两个产品都满足第一个布尔条件,因为它们都链接到 cat 352)。在我当前的测试中,第二个 bool/should 条件会导致搜索不返回任何结果。如果我删除那个,我会得到匹配项。

【问题讨论】:

可以分享索引映射吗? 当然是抢。我刚刚用属性映射更新了帖子。 CatId 和 ParentCatId 都是整数。我目前的理论是这两个子条件需要分解为两个不同的 NestedQueries,但我还没有机会尝试看看它是否有效。 @Travis,你看到 .NET 客户端了吗bool 查询文档:elastic.co/guide/en/elasticsearch/client/net-api/current/… 【参考方案1】:

这是我为我的一个 api 运行的简化版本。

外部布尔包含一个should 和一个minimum_should_match 2(这是你的AND 子句) 里面应该有 2 个 bool 语句,每个语句都包含一个 OR 子句 每个 OR 子句都是一个 should,其中 minimum_should_match 为 1 注意:fieldA 和 fieldB 是两个不同的字段,值 A-D 是您要测试的各种值
//GET /index/type/_search

  "from": 0,
  "size": 1000,
  "query": 
    "bool": 
      "minimum_should_match": 2,
      "should": [
        
          "bool": 
            "minimum_should_match": 1,
            "should": [
              
                "term": 
                  "fieldA": "value a"
                
              ,
              
                "term": 
                  "fieldA": "value b"
                
              
            ]
          
        ,
        
          "bool": 
            "minimum_should_match": 1,
            "should": [
              
                "term": 
                  "fieldB": "value c"
                
              ,
              
                "term": 
                  "fieldB": "value d"
                
              
            ]
          
        
      ]
    
  


【讨论】:

感谢弗朗西斯。我尝试了这种方法,但它对我不起作用。我将此版本的查询添加到我的帖子中,以防您看到我误解的内容。我的条件在嵌套查询中,所以可能与它有关。我还在可能会影响事物的两个 bool 操作中针对同一属性测试值。

以上是关于如何在弹性搜索查询中组合和的主要内容,如果未能解决你的问题,请参考以下文章

如何在弹性搜索查询中传递特定字段的值列表

如何记录所有已执行的弹性搜索查询

在弹性搜索中使用 GET/POST 时结果不同

如何仅查询一种类型的记录的弹性搜索?

如何在弹性搜索的过滤器聚合中引用多个嵌套级别?

如何在弹性搜索中使用纬度经度搜索位置附近的区域