在 Elasticsearch 5.x 有一個字段摺疊(Field Collapsing)的功能非常有用,在這裏分享一下
前言
在電商商品中有分SKU和SPU
sku是和商品的庫存相關的一個概念。比如air max90、藍色、40碼的nike跑鞋,就是一個sku。你可以設置這個sku的價格、庫存。
spu是標類商品的一個概念。所謂標類簡單理解就是有型號的商品,比如
- air max90、藍色、40碼的NIKE跑鞋
- air max90、藍色、41碼的NIKE跑鞋
- air max90、白色、40碼的NIKE跑鞋
- air max90、白色、41碼的NIKE跑鞋
賣家發佈商品時候,只要選到spu,和這個商品有關的屬性會自動附加到商品上。
So,什麼是字段摺疊,可以理解就是按特定字段進行合併去重,比如我們有一個商品搜索,我希望按商品的“SPU”字段進行摺疊,即返回結果每個SPU的商品都只返回一個結果,也就是按SPU去重,我搜索關鍵字“NIKE跑鞋”,要去返回的結果裏面各種NIKE跑鞋都有,有air max90 NIKE跑鞋,有Nike Free RN 5.0 NIKE跑鞋,有Nike Flex Contact 3 NIKE跑鞋,有Nike Zoom Winflo 6 NIKE跑鞋,別全是air max90 NIKE跑鞋,不需要展示把所有的air max90 NIKE跑鞋都展示出來,只需要展示一個就可以了,這個時候摺疊的功能就很有用了。,通過按特定字段摺疊之後,來豐富搜索結果的多樣性,而不是看到的頁面上大部分都是重複的商品。
使用
//查詢數據
var response = _esClient.Search<Product>(selector => selector
.Index(Indices.Index<Product>())
.Source(fields)
.Query(query)
.Collapse(x => x.Field(f => f.CorrelationId)) //摺疊的字段
.Aggregations(ag => ag.Terms("CorrelationId_group", t => t.Field(fd => fd.CorrelationId).Size(100000)))
.From(Offset)
.Size(PageSize)
.Sort(sort)
);
//數據解析
var model = new SearchProductModel()
{
Page = StartIndex,
Size = PageSize,
Total = (int)response.Total,
TookTime = (int)response.Took,
Items = BuildProduct(response.Hits)
};
//摺疊關聯產品後 查詢出來的Total數量不對,這裏使用分組重新統計摺疊關聯產品後的產品數量
var total = response.Aggregations.Terms("CorrelationId_group")?.Buckets.Count;
if (total.HasValue)
{
model.Total = total.Value;
}
return model;
問題
摺疊只會影響搜索結果Hits的數量,但不影響聚合Total 總數,搜索結果的 Total 依舊是所有的命中紀錄數,去重的結果數無法取到。
換一種思路,根據摺疊的字段再分組一下,總數Total用aggregations中的value,結果列表用hits,這樣就可以準確提交摺疊後的數量了。(這裏的分組的size一定要設置,大小爲搜索結果總數的最大值,當然你可以直接設置爲Int.MaxValue)