在線上商店中,分面看似簡單,但一旦選取第一個篩選條件,情況就變得複雜。
在商品目錄中,分面是導覽的一部分。已選取的顏色不應從清單中消失,其他顏色應保持可用:使用者可能想要切換顏色,或擴大選擇範圍。沒有相符產品的選項顯示為不可用會更有用。在單一分面內,通常適用 OR:紅色或藍色。在不同分面之間,則適用 AND:同時依品牌、顏色與尺寸篩選。
難點始於第一次選取之後。想像一個使用者已選取品牌、顏色與尺寸的商品目錄。主要結果集必須保持精確,只顯示符合這三個條件的產品。但篩選面板遵循不同的規則。它需要保留已選取的顏色,同時顯示使用者在相同品牌與尺寸下可以切換的顏色。
如果每個分面都繼承主要查詢的所有篩選條件,很快就會收縮到已選取的值。如果必須手動重建每個分面的篩選條件,最終會產生針對顏色、尺寸、品牌、庫存狀態、賣家以及其他屬性的獨立查詢分支。
Manticore Search 25.12.0 引入了 facet_filter_mode,將此行為移入分面 API。查詢現在可以描述商店篩選面板應有的行為,而不需要應用程式為每個分面手動建立幾乎相同的查詢。
電子商務分面需要什麼
對於篩選面板而言,僅回答「有多少產品具有此值?」是不夠的。它需要介面可直接使用的狀態:
- 已選取的值保持可見,且可快速清除;
- 同一分面中的其他值保持可用,因為它們可透過
IN (...)擴大篩選範圍; - 其他分面中的值可指出選取它們是否會傳回至少一項產品;
- 計數保持可預測:介面知道數字是指目前的結果集還是更廣泛的選擇;
- 在冗長的品牌清單、類別、價格範圍、SEO 規則與查詢分析中進行搜尋仍然重要;它們是搜尋設計的另一部分。
facet_filter_mode 處理此問題最常見的部分:在使用者已選取多個篩選條件後重新計算分面。
變更內容
分面現在有三種篩選繼承模式:
| 模式 | 行為 |
|---|---|
strict |
將主要查詢的所有篩選條件套用至分面。這是先前的行為,維持為預設值。 |
auto |
套用除分面本身篩選條件外的所有篩選條件,並新增 status:已選取的值為 selected,其他值為 available。 |
max |
在廣泛的基本結果集上計算儲存貯體,並新增 status 以區分已選取、可用與不可用的值。 |
您也可以手動控制:
-
ALL FILTERS- 將所有篩選條件套用至分面; -
FILTERS color_id, size_id- 僅套用列出的篩選條件; -
EXCLUDE FILTERS color_id- 套用除列出項目外的所有篩選條件; -
ZEROES- 自 Manticore Search 27.3.0 起,即使目前分面的count(*)為0,仍保留廣泛max範圍中的儲存貯體(適用於 SQLmax模式)。
相同的選項也可透過 JSON API 的 facet_filter_mode、mode、filters、exclude_filters 與 zeroes: true 取得。
簡而言之,strict 回答「目前結果集中有哪些?」,auto 回答「如果變更此特定篩選條件會發生什麼事?」,max 則顯示廣泛的儲存貯體清單,並包含 status 欄位:selected、available 或 unavailable。
最小範例
考慮一個包含品牌、顏色、尺寸與 SKU 的小型目錄:
CREATE TABLE products(
title text,
brand_id int,
color_id int,
color_name string,
size_id int,
size_name string,
sku string
);
INSERT INTO products(id,title,brand_id,color_id,color_name,size_id,size_name,sku) VALUES
(1,'p1',7,1,'red',10,'small','sku1'),
(2,'p2',7,1,'red',20,'large','sku2'),
(3,'p3',7,2,'blue',10,'small','sku3'),
(4,'p4',7,3,'green',30,'xlarge','sku4'),
(5,'p5',8,1,'red',10,'small','sku5'),
(6,'p6',8,4,'black',20,'large','sku6'),
(7,'p7',9,5,'white',10,'small','sku7');
Enter fullscreen mode Exit fullscreen mode
使用者已選取:
brand_id=7 AND color_id=1 AND size_id=10
Enter fullscreen mode Exit fullscreen mode
在此條件下,結果集包含一項產品:p1。讓我們看看分面會發生什麼變化。
strict:先前的行為
若無額外選項,Manticore Search 會使用 strict:每個分面都會接收主要查詢的所有篩選條件。
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
FACET color_id ORDER BY color_id ASC
FACET size_id ORDER BY size_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+----------+----------+
| color_id | count(*) |
+----------+----------+
| 1 | 1 |
+----------+----------+
+---------+----------+
| size_id | count(*) |
+---------+----------+
| 10 | 1 |
+---------+----------+
Enter fullscreen mode Exit fullscreen mode
這是準確的 SQL 回應,但對於線上商店而言通常過於狹隘。使用者只會看到已選取的 color_id=1 與 size_id=10。看起來似乎沒有其他選項,儘管資料包含具有相同品牌與尺寸但不同顏色的產品(color_id=2),以及具有相同品牌與顏色但不同尺寸的產品(size_id=20)。
auto:分面忽略自身篩選條件
auto 模式會保留除目前計算分面的篩選條件外的所有篩選條件。
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
OPTION facet_filter_mode='auto'
FACET color_id ORDER BY color_id ASC
FACET size_id ORDER BY size_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+----------+----------+-----------+
| color_id | count(*) | status |
+----------+----------+-----------+
| 1 | 1 | selected |
| 2 | 1 | available |
+----------+----------+-----------+
+---------+----------+-----------+
| size_id | count(*) | status |
+---------+----------+-----------+
| 10 | 1 | selected |
| 20 | 1 | available |
+---------+----------+-----------+
Enter fullscreen mode Exit fullscreen mode
發生了什麼事:
-
FACET color_id套用了brand_id=7 AND size_id=10,但未套用color_id=1; -
FACET size_id套用了brand_id=7 AND color_id=1,但未套用size_id=10。
這讓介面在不為每個分面建立獨立查詢的情況下取得替代值。已選取的儲存貯體標記為 selected,而同一分面中的其他值則標記為 available:它們可以透過 IN (...) 加入目前篩選條件,作為更廣泛的選擇。
max:具有狀態的廣泛儲存貯體清單
auto 僅顯示特定分面目前篩選範圍內的值。max 更進一步:它在基本結果集上計算儲存貯體,並為介面分別標記其狀態。
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
OPTION facet_filter_mode='max'
FACET color_id ORDER BY color_id ASC
FACET size_id ORDER BY size_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+----------+----------+-----------+
| color_id | count(*) | status |
+----------+----------+-----------+
| 1 | 3 | selected |
| 2 | 1 | available |
| 3 | 1 | available |
| 4 | 1 | available |
| 5 | 1 | available |
+----------+----------+-----------+
+---------+----------+-----------+
| size_id | count(*) | status |
+---------+----------+-----------+
| 10 | 4 | selected |
| 20 | 2 | available |
| 30 | 1 | available |
+---------+----------+-----------+
Enter fullscreen mode Exit fullscreen mode
status 直接來自 Manticore Search:
-
selected- 此值已存在於此分面的篩選條件中; -
available- 此值可以選取;對於同一分面中的另一個值,這會透過IN (...)擴大篩選範圍; -
unavailable- 此值存在於分面的廣泛結果集中,但選取它在目前篩選條件下不會傳回任何文件。
在此範例中,color_id=1 出現在目錄中的三項產品中,因此其在 max 中的計數為 3。它被標記為 selected,因為它已參與篩選。其他顏色被標記為 available:如果使用者選取其中一個,顏色篩選條件會變得更廣泛,例如 color_id IN (1,2)。當廣泛結果集中的儲存貯體在目前篩選條件下無法傳回文件時,就會出現不可用的值;下面的 sku 範例展示了這種情況。
手動設定篩選範圍
全域 facet_filter_mode 涵蓋大多數常見情況,但有時不同分面需要不同的行為。例如,顏色可以保持嚴格受所有篩選條件限制,尺寸可以使用 max,SKU 可以僅使用顏色與尺寸計算,而品牌可以在沒有顏色篩選條件的情況下計算。
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
OPTION facet_filter_mode='max'
FACET color_id ALL FILTERS ORDER BY color_id ASC
FACET size_id ORDER BY size_id ASC
FACET sku FILTERS color_id, size_id ORDER BY sku ASC
FACET brand_id EXCLUDE FILTERS color_id ORDER BY brand_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+----------+----------+-----------+
| color_id | count(*) | status |
+----------+----------+-----------+
| 1 | 1 | selected |
+----------+----------+-----------+
+---------+----------+-----------+
| size_id | count(*) | status |
+---------+----------+-----------+
| 10 | 4 | selected |
| 20 | 2 | available |
| 30 | 1 | available |
+---------+----------+-----------+
+------+----------+-------------+
| sku | count(*) | status |
+------+----------+-------------+
| sku1 | 1 | available |
| sku5 | 1 | unavailable |
+------+----------+-------------+
+----------+----------+----------+
| brand_id | count(*) | status |
+----------+----------+----------+
| 7 | 2 | selected |
+----------+----------+----------+
Enter fullscreen mode Exit fullscreen mode
如何閱讀此查詢:
-
FACET color_id ALL FILTERS套用所有篩選條件並僅傳回已選取的顏色; -
FACET size_id繼承查詢層級的max模式; -
FACET sku FILTERS color_id, size_id僅套用顏色與尺寸篩選條件; -
FACET brand_id EXCLUDE FILTERS color_id套用除顏色外的所有篩選條件。
當篩選面板包含一般與技術分面,且某些值需要根據特殊規則計算時,此模式很有用。
ZEROES:max 中的零計數儲存貯體
當需要保持嚴格的計數,但又需要保持廣泛的值清單時,ZEROES 很有用。它可與 max 搭配使用,無論是透過 OPTION facet_filter_mode='max',還是透過個別分面的 MODE max。
若無 ZEROES,具有 ALL FILTERS 的分面僅顯示通過所有篩選條件的儲存貯體:
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
OPTION facet_filter_mode='max'
FACET size_id ALL FILTERS ORDER BY size_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+---------+----------+----------+
| size_id | count(*) | status |
+---------+----------+----------+
| 10 | 1 | selected |
+---------+----------+----------+
Enter fullscreen mode Exit fullscreen mode
使用 ZEROES 時,Manticore Search 會保持相同的可見計數,但會傳回來自廣泛 max 範圍的其餘儲存貯體,並將計數設為零:
SELECT count(*)
FROM products
WHERE brand_id=7 AND color_id=1 AND size_id=10
LIMIT 0
OPTION facet_filter_mode='max'
FACET size_id ALL FILTERS ZEROES ORDER BY size_id ASC;
Enter fullscreen mode Exit fullscreen mode
回應:
+---------+----------+-----------+
| size_id | count(*) | status |
+---------+----------+-----------+
| 10 | 1 | selected |
| 20 | 0 | available |
| 30 | 0 | available |
+---------+----------+-----------+
Enter fullscreen mode Exit fullscreen mode
介面隨後可以在已選取的 small 旁邊顯示 large 與 xlarge:數字是指目前的嚴格結果集,而 status 則顯示這些值仍然可以選取以擴大篩選範圍。
透過 JSON API 的相同查詢
SQL 在此處較短,且更清楚地顯示機制,但 JSON API 支援相同的方法:
POST /search
{
"table": "products",
"limit": 0,
"query": {
"bool": {
"must": [
{ "equals": { "brand_id": 7 } },
{ "equals": { "color_id": 1 } },
{ "equals": { "size_id": 10 } }
]
}
},
"facet_filter_mode": "max",
"aggs": {
"colors": {
"terms": { "field": "color_id", "size": 10 },
"sort": [ { "color_id": { "order": "asc" } } ]
},
"sizes": {
"terms": { "field": "size_id", "size": 10 },
"sort": [ { "size_id": { "order": "asc" } } ]
}
}
}
Enter fullscreen mode Exit fullscreen mode
回應:
{
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"total_relation": "eq",
"hits": []
},
"aggregations": {
"colors": {
"buckets": [
{ "key": 1, "doc_count": 3, "status": "selected" },
{ "key": 2, "doc_count": 1, "status": "available" },
{ "key": 3, "doc_count": 1, "status": "available" },
{ "key": 4, "doc_count": 1, "status": "available" },
{ "key": 5, "doc_count": 1, "status": "available" }
]
},
"sizes": {
"buckets": [
{ "key": 10, "doc_count": 4, "status": "selected" },
{ "key": 20, "doc_count": 2, "status": "available" },
{ "key": 30, "doc_count": 1, "status": "available" }
]
}
}
}
Enter fullscreen mode Exit fullscreen mode
在 JSON 聚合中,mode、filters、exclude_filters 與 zeroes 也可以針對每個個別聚合進行設定。
與 Meilisearch、Elasticsearch 與 OpenSearch 的差異
我們在 Manticore Search、Meilisearch、Elasticsearch 與 OpenSearch 中測試了相同的場景:brand_id=7、color_id=1 與 size_id=10 篩選條件處於作用中;結果集保持嚴格,而分面需要顯示排除自身篩選條件時出現的選項。
| 引擎 | 在單一查詢中排除自身篩選條件 | 原生儲存貯體狀態 | 應用程式仍需處理的事項 |
|---|---|---|---|
| Manticore Search | 是,透過 auto/max
|
是,在 auto/max 中;unavailable 僅在 max 中 |
呈現介面、SEO、分析與自訂規則。 |
| Meilisearch | 非此形式 | 否 | 執行額外查詢並在應用程式中組裝分面。 |
| OpenSearch | 是,但需透過 global + filter 聚合手動操作 |
否 | 複製篩選分支並在應用程式中計算 status。 |
| Elasticsearch | 是,但需透過 global + filter 聚合手動操作 |
否 | 相同:維護獨立的聚合分支與用戶端邏輯。 |
在 Meilisearch 中使用基本分面很容易,但像這樣的查詢:
{
"filter": ["brand_id = 7", "color_id = 1", "size_id = 10"],
"facets": ["color_id", "size_id"]
}
Enter fullscreen mode Exit fullscreen mode
傳回已篩選結果集的計數。在我們的資料集中,這意味著只有 color_id=1 與 size_id=10。替代的 color_id=2 與 size_id=20 值不會出現在此回應中。如果介面需要它們,應用程式必須發出額外查詢並合併結果。
在 Elasticsearch 與 OpenSearch 中,類似的行為可以在單一查詢中建立,但每個分面都需要自己的明確聚合分支。對於 color,您保留 brand_id 與 size_id;對於 size,您保留 brand_id 與 color_id;以此類推。這可行,但查詢會快速成長,且儲存貯體狀態仍需在應用程式中計算。
主要差異在於此邏輯存在的位置。在 Manticore Search 中,它直接在分面 API 中設定;在其他系統中,它通常由多個相似的篩選樹組裝而成。
效能與限制
strict 維持為預設值,並保留先前的行為。如果您只需要目前結果集內的分面,則無需進行任何變更。
auto 通常更適合電子商務篩選條件:它顯示每個分面中的替代值,將已選取的值標記為 selected,並將其他值標記為 available。
當介面需要比目前結果集更廣泛的值清單,並需要顯示不可用選項時,請使用 max。此模式成本較高:Manticore Search 會在廣泛範圍上計算儲存貯體,然後分別判斷其 status。在大型資料集與許多分面的情況下,值得考慮。
還有一些限制:
- 分面的本機篩選條件重寫僅支援與
AND結合的屬性篩選條件; - 複雜的
AND/OR樹不會自動為個別分面重寫; - 目前僅能可靠地比對明確值篩選條件(如
=與IN)的已選取值; - 尚未自動計算價格等範圍的狀態。
對於價格、折扣與評分,最好明確定義獨立的範圍。例如,保留用於排序與滑桿的數值欄位,並為分面新增 price_band 或 discount_band。這讓介面可以為預定義範圍顯示明確的狀態。
分面 URL 的 SEO、A/B 測試、銷售規劃規則與查詢分析仍然是搜尋周圍應用程式或平台的責任。
實際上,當您需要替代值時,請從 auto 開始;當介面需要具有 selected、available 與 unavailable 狀態的廣泛儲存貯體清單時,請改用 max。
進一步閱讀
若要介紹 Manticore Search 中的分面搜尋,請從較早的 Faceted search 文章開始。它涵蓋基本的 FACET 查詢、排序、限制與運算式的分面。
請參閱 FACET 文件 以取得詳細資訊。
若要以互動方式介紹分面,請參加 Manticore Faceting 課程。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.