使用多重过滤器搜索

时间:2014-01-13 03:30:48

标签: elasticsearch

我在这里有一个问题。在常见的购物车网站中,功能搜索具有多个过滤器的产品。例如,我正在寻找带有这样一些过滤器的运动装备:

  • 制造商

    • [ x ] Nike
    • 阿迪达斯
    • 茵宝
  • 选项

    • 尺寸
      • [ x ] S
      • [ x ] M
    • 颜色
      • [ x ]白色
      • 黄色
      • 红色
      • [ x ]蓝色

这是我的映射

PUT test/product/_mapping
{
    "product":{
        "properties" : {
            "name" : {"type" : "string", "store":"yes"},
            "manufacturer" {"type": "string}
            "options" : {
                "type": "nested"
            }
        }
    }
}

一些测试数据

POST test/product/1
{
    "name": "Shirt 1",
    "manufacturer": "Adidas",
    "options":[
            {
                "Color" : ["Red", "Green"]
            },
            {
                "Size" : ["S","M","L"]
            }
        ],
    "price":250000
}

POST test/product/2
{
    "name": "Shirt 2",
    "manufacturer": "Nike",
    "options":[
            {
                "Color" : ["Blue", "Green", "White"]
            },
            {
                "Size" : ["S", "L", "XL"]
            }
        ],
    "price":100000
}

POST test/product/3
{
    "name": "Shirt 3",
    "manufacturer": "Umbro",
    "options": [
            {
                "Color" : ["Red"]
            },
            {
                "Size" : ["S","XXL"]
            }
        ],
    "price": 300000
}

有了这个查询,一切都很好

POST test/product/_search
{
    "query": {
        "filtered": {
           "query": {
                "match_all": {}
           },
           "filter": {
               "bool": {
                    "must": [
                       {
                           "nested": {
                              "path": "options",
                              "filter": {
                                  "bool": {
                                      "must": [ 
                                         {
                                            "terms": {
                                               "options.Color": [
                                                  "white"
                                               ]
                                            }
                                         }
                                      ]
                                  }
                              }
                           }
                       },
                       {
                           "term": {
                              "manufacturer": "nike"
                           }
                       }
                    ]
               }
           }
        }
    }
}

但是,如果我在选项过滤器中添加更多条件,则无法获得结果

POST test/product/_search
{
    "query": {
        "filtered": {
           "query": {
                "match_all": {}
           },
           "filter": {
               "bool": {
                    "must": [
                       {
                           "nested": {
                              "path": "options",
                              "filter": {
                                  "bool": {
                                      "must": [ 
                                         {
                                            "terms": {
                                               "options.Color": [
                                                  "white"
                                               ]
                                            }
                                         },

                                         {
                                            "terms": {
                                               "options.Size": [
                                                  "s"
                                               ]
                                            }
                                         }
                                      ]
                                  }
                              }
                           }
                       },
                       {
                           "term": {
                              "manufacturer": "nike"
                           }
                       }
                    ]
               }
           }
        }
    }
}

我不知道我在映射或查询中是否错了,或者您能告诉我在这种情况下创建映射的最佳方法是什么。谢谢你的帮助。

1 个答案:

答案 0 :(得分:1)

这里的问题是nested类型的使用。您的nested过滤器不会对所有孩子进行评估,而是针对每个孩子进行单独评估。由于您没有单个嵌套对象,因此满足您的过滤器(同时具有ColorSize),您无法获得任何结果。您有两种选择:

  1. 将这些单独的嵌套对象合并在一起

    POST test/product/1
    {
        "name": "Shirt 1",
        "manufacturer": "Adidas",
        "options":[
            {
                "Color" : ["Red", "Green"],
                "Size" : ["S","M","L"]
            }
        ],
        "price":250000
    }
    

    您的地图和查询保持不变。

  2. 请勿使用nested类型,而应使用简单的object类型。您必须更改options的映射:

    PUT test/product/_mapping
    {
        "product":{
            "properties" : {
                "options" : {
                    "type": "object"
                }
            }
        }
    }
    

    然后删除nested过滤器:

    POST test/product/_search
    {
       "query": {
          "filtered": {
             "query": {
                "match_all": {}
             },
             "filter": {
                "bool": {
                   "must": [
                      {
                         "terms": {
                            "options.Color": [
                               "white"
                            ]
                         }
                      },
                      {
                         "terms": {
                            "options.Size": [
                               "s"
                            ]
                         }
                      },
                      {
                         "term": {
                            "manufacturer": "nike"
                         }
                      }
                   ]
                }
             }
          }
       }
    }
    

    但您的数据可以保持不变。

  3. 嵌套对象实际上适用于不同的结构化数据。如果你有像

    这样的东西
    "options":[
        {
            "Color" : "Blue",
            "Size": "S"
        },
        {
            "Color": "Red",
            "Size" : "L"
        }
    ]
    

    并且您希望过滤项目, Blue S ,然后您必须使用嵌套过滤器。