基於 Elasticsearch 聚合搜索實現電商篩選查詢功能


前言

在網上購物時,首先是需要輸入關鍵字檢索商品,當進入搜索頁時,一般奪會有一個篩選,方便用戶進一步縮小商品范圍,例如某寶、某東,其上面的商品都是億萬級別的體量,從下圖可以得出,篩選條件中包括價格、品牌、商品規格屬性(功效、凈含量...)等,並且不同的搜索條件展示出來的篩選內容也是截然不同的,在這里介紹如何基於 Elasticsearch 的聚合搜索實現此功能

某東

某寶

篩選條件

實現篩選過濾功能,首先得對 dsl 語句有一定的了解(小伙伴自行補課~)

  1. 創建索引

在這里有一點要注意的是其中 attributes 是用了 nested 類型
不了解的小伙伴請看這位大佬的文章 干貨 | Elasticsearch Nested類型深入詳解

# 創建索引
PUT product_index
{
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0
    },
    "mappings": {
        "properties": {
            "id": {
                "type": "long"
            },
            "name": {
                "type": "text"
            },
            "brandId": {
                "type": "keyword"
            },
            "brand": {
                "type": "keyword"
            },
            "price": {
                "type": "double"
            },
            "attributes": {
                "type": "nested",
                "properties": {
                    "attrKeyId": {
                        "type": "keyword"
                    },
                    "attrKeyName": {
                        "type": "keyword"
                    },
                    "attrValueName": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}
  1. 創建數據
# 創建數據
PUT /product_index/_bulk
{"index": {}}
{"id ":1,"name":"日系短袖","brandId":"10","brand":"優衣庫","price":99.99,"attributes":[{"attrKeyId":"1","attrKeyName":"適用季節","attrValueName":"春季"},{"attrKeyId":"2","attrKeyName":"風格","attrValueName":"日系"},{"attrKeyId":"3","attrKeyName":"人群","attrValueName":"青年"}]}
{"index": {}}
{"id ":2,"name":"韓版短袖","brandId":"20","brand":"Kirsh","price":199.99,"attributes":[{"attrKeyId":"1","attrKeyName":"適用季節","attrValueName":"夏季"},{"attrKeyId":"2","attrKeyName":"風格","attrValueName":"韓系"},{"attrKeyId":"3","attrKeyName":"人群","attrValueName":"少年"}]}
{"index": {}}
{"id ":3,"name":"美系短袖","brandId":"30","brand":"Nike","price":299.99,"attributes":[{"attrKeyId":"1","attrKeyName":"適用季節","attrValueName":"秋季"},{"attrKeyId":"2","attrKeyName":"風格","attrValueName":"美系"},{"attrKeyId":"3","attrKeyName":"人群","attrValueName":"中年"}]}
{"index": {}}
{"id ":4,"name":"國產短袖","brandId":"40","brand":"安踏","price":399.99,"attributes":[{"attrKeyId":"1","attrKeyName":"適用季節","attrValueName":"冬季"},{"attrKeyId":"2","attrKeyName":"風格","attrValueName":"國潮"},{"attrKeyId":"3","attrKeyName":"人群","attrValueName":"青少年"}]}
{"index": {}}
{"id ":5,"name":"中國短袖","brandId":"40","brand":"安踏","price":499.99,"attributes":[{"attrKeyId":"1","attrKeyName":"適用季節","attrValueName":"夏季"},{"attrKeyId":"2","attrKeyName":"風格","attrValueName":"國潮"},{"attrKeyId":"3","attrKeyName":"人群","attrValueName":"青少年"}]}
  1. 根據搜索內容找出全部可篩選條件

模擬場景:輸入“短袖”進行搜索,找到可篩選的 品牌(brand)&商品規格屬性(attributes) 條件

# 根據搜索內容找出全部可篩選條件
GET /product_index/_search
{
  "query": {
    "match": {
      "name": "短袖"
    }
  }, 
  "size": 0, 
  "aggs": {
      "brandId": {
        "terms": {
          "field": "brandId"
        },
        "aggs": {
          "brand": {
            "terms": {
              "field": "brand"
            }
          }
        }
      },
      "attra": {
        "nested": {
          "path": "attributes"
        },
        "aggs": {
          "attrKeyId": {
            "terms": {
            "field": "attributes.attrKeyId"
          },
          "aggs": {
            "attrKeyName": {
              "terms": {
                "field": "attributes.attrKeyName"
              }
            },
            "attrValueName": {
              "terms": {
                "field": "attributes.attrValueName"
              }
            }
          }
        }
      }
    }
  }
}

品牌聚合結果:

"brandId" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "40",
          "doc_count" : 2,
          "brand" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "安踏",
                "doc_count" : 2
              }
            ]
          }
        },
        {
          "key" : "10",
          "doc_count" : 1,
          "brand" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "優衣庫",
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "20",
          "doc_count" : 1,
          "brand" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Kirsh",
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "30",
          "doc_count" : 1,
          "brand" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Nike",
                "doc_count" : 1
              }
            ]
          }
        }
      ]
    }

商品規格屬性聚合結果:

"attr" : {
      "doc_count" : 15,
      "attrKeyId" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 0,
        "buckets" : [
          {
            "key" : "1",
            "doc_count" : 5,
            "attrKeyName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "適用季節",
                  "doc_count" : 5
                }
              ]
            },
            "attrValueName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "夏季",
                  "doc_count" : 2
                },
                {
                  "key" : "冬季",
                  "doc_count" : 1
                },
                {
                  "key" : "春季",
                  "doc_count" : 1
                },
                {
                  "key" : "秋季",
                  "doc_count" : 1
                }
              ]
            }
          },
          {
            "key" : "2",
            "doc_count" : 5,
            "attrKeyName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "風格",
                  "doc_count" : 5
                }
              ]
            },
            "attrValueName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "國潮",
                  "doc_count" : 2
                },
                {
                  "key" : "日系",
                  "doc_count" : 1
                },
                {
                  "key" : "美系",
                  "doc_count" : 1
                },
                {
                  "key" : "韓系",
                  "doc_count" : 1
                }
              ]
            }
          },
          {
            "key" : "3",
            "doc_count" : 5,
            "attrKeyName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "人群",
                  "doc_count" : 5
                }
              ]
            },
            "attrValueName" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "青少年",
                  "doc_count" : 2
                },
                {
                  "key" : "中年",
                  "doc_count" : 1
                },
                {
                  "key" : "少年",
                  "doc_count" : 1
                },
                {
                  "key" : "青年",
                  "doc_count" : 1
                }
              ]
            }
          }
        ]
      }
    }

得到了以上結果即可通過服務端組裝數據(這里就不在深入了~)

篩選查詢

經過以上步驟可以得到搜索時的全部篩選條件,那么下一步就是帶入篩選條件進行查詢商品了,話不多說咱們開始

  1. 條件搜索

模擬場景:搜索關鍵詞:“短袖”,品牌為“優衣庫”,適用季節為“春季”的商品
根據模擬場景可得出以下參數

  1. keyword (關鍵詞)
  2. brandId (品牌id)
  3. attrKeyId (屬性id)
  4. attrValueName (屬性值)

其中 attr 可能會選擇很多,若是業務場景中每個屬性是單選的情況下,推薦使用 k,v 的形式接收規格屬性參數

# 根據篩選條件查詢商品
GET /product_index/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "name": "短袖"
                    }
                }
            ],
            "filter": [
                {
                    "bool": {
                        "must": [
                            {
                                "term": {
                                    "brandId": {
                                        "value": "10"
                                    }
                                }
                            },
                            {
                                "nested": {
                                    "path": "attributes",
                                    "query": {
                                        "bool": {
                                            "must": [
                                                {
                                                    "term": {
                                                        "attributes.attrKeyId": {
                                                            "value": "1"
                                                        }
                                                    }
                                                },
                                                {
                                                    "term": {
                                                        "attributes.attrValueName": {
                                                            "value": "春季"
                                                        }
                                                    }
                                                }
                                            ]
                                        }
                                    }
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

搜索結果:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.17402273,
    "hits" : [
      {
        "_index" : "product_index",
        "_type" : "_doc",
        "_id" : "_GtUzXoBSEC8FU4FyZf0",
        "_score" : 0.17402273,
        "_source" : {
          "id " : 1,
          "name" : "日系短袖",
          "brandId" : "10",
          "brand" : "優衣庫",
          "price" : 99.99,
          "attributes" : [
            {
              "attrKeyId" : "1",
              "attrKeyName" : "適用季節",
              "attrValueName" : "春季"
            },
            {
              "attrKeyId" : "2",
              "attrKeyName" : "風格",
              "attrValueName" : "日系"
            },
            {
              "attrKeyId" : "3",
              "attrKeyName" : "人群",
              "attrValueName" : "青年"
            }
          ]
        }
      }
    ]
  }
}

若將brandId替換成 20(或是替換任意參數),結果為:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

由此可得出篩選過濾查詢以實現啦~

總結

這是基於Es聚合實現電商篩選搜索的思路,如果老哥們有好的建議或是意見的話歡迎在評論區留言哦~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM