前言
在網上購物時,首先是需要輸入關鍵字檢索商品,當進入搜索頁時,一般奪會有一個篩選,方便用戶進一步縮小商品范圍,例如某寶、某東,其上面的商品都是億萬級別的體量,從下圖可以得出,篩選條件中包括價格、品牌、商品規格屬性(功效、凈含量...)等,並且不同的搜索條件展示出來的篩選內容也是截然不同的,在這里介紹如何基於 Elasticsearch 的聚合搜索實現此功能
篩選條件
實現篩選過濾功能,首先得對 dsl 語句有一定的了解(小伙伴自行補課~)
- 創建索引
在這里有一點要注意的是其中 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"
}
}
}
}
}
}
- 創建數據
# 創建數據
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":"青少年"}]}
- 根據搜索內容找出全部可篩選條件
模擬場景:輸入“短袖”進行搜索,找到可篩選的 品牌(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
}
]
}
}
]
}
}
得到了以上結果即可通過服務端組裝數據(這里就不在深入了~)
篩選查詢
經過以上步驟可以得到搜索時的全部篩選條件,那么下一步就是帶入篩選條件進行查詢商品了,話不多說咱們開始
- 條件搜索
模擬場景:搜索關鍵詞:“短袖”,品牌為“優衣庫”,適用季節為“春季”的商品
根據模擬場景可得出以下參數
- keyword (關鍵詞)
- brandId (品牌id)
- attrKeyId (屬性id)
- 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聚合實現電商篩選搜索的思路,如果老哥們有好的建議或是意見的話歡迎在評論區留言哦~