multi_select_faceting.md
8.98 KB
Multi-Select Faceting 功能说明
概述
Multi-Select Faceting(多选分面)是业界标准的 Faceted Search 功能,允许用户在选中某个分面筛选项后,仍然能看到该分面的其他可选项,提供更好的探索式搜索体验。
功能特性
1. 两种 Faceting 模式
标准模式(Conjunctive Faceting)
- 设置:
multi_select: false(默认) - 行为: 选中某个分面值后,该分面只显示选中的值
- 适用场景: 层级下钻、逐步精炼
- ES 实现: 过滤器应用在
query.bool.filter
Multi-Select 模式(Disjunctive Faceting)
- 设置:
multi_select: true - 行为: 选中某个分面值后,该分面仍显示所有可选项
- 适用场景: 颜色、品牌、尺码等可切换属性
- ES 实现: 过滤器应用在
post_filter
2. Selected 状态标记
所有 facet 值都包含 selected 字段,标记当前是否被选中:
selected: true- 当前筛选项已被选中selected: false- 当前筛选项未被选中
使用示例
示例 1: 标准 Category Faceting
{
"query": "T恤",
"filters": {
"category1_name": "服装"
},
"facets": [
{
"field": "category1_name",
"size": 10,
"type": "terms",
"multi_select": false
}
]
}
响应:
{
"results": [...],
"facets": [
{
"field": "category1_name",
"values": [
{"value": "服装", "count": 150, "selected": true}
]
}
]
}
示例 2: Multi-Select Brand Faceting
{
"query": "手机",
"filters": {
"brand_name": "苹果"
},
"facets": [
{
"field": "brand_name",
"size": 10,
"type": "terms",
"multi_select": true
}
]
}
响应:
{
"results": [...只包含苹果手机...],
"facets": [
{
"field": "brand_name",
"values": [
{"value": "苹果", "count": 150, "selected": true},
{"value": "华为", "count": 120, "selected": false},
{"value": "小米", "count": 98, "selected": false}
]
}
]
}
示例 3: Specifications Multi-Select
{
"query": "衬衫",
"filters": {
"specifications": {
"name": "颜色",
"value": "白色"
}
},
"facets": [
{
"field": "specifications.颜色",
"size": 10,
"type": "terms",
"multi_select": true
},
{
"field": "specifications.尺码",
"size": 10,
"type": "terms",
"multi_select": false
}
]
}
响应:
{
"results": [...只包含白色衬衫...],
"facets": [
{
"field": "specifications.颜色",
"label": "颜色",
"values": [
{"value": "白色", "count": 50, "selected": true},
{"value": "蓝色", "count": 35, "selected": false},
{"value": "黑色", "count": 28, "selected": false}
]
},
{
"field": "specifications.尺码",
"label": "尺码",
"values": [
{"value": "M", "count": 20, "selected": false},
{"value": "L", "count": 18, "selected": false},
{"value": "XL", "count": 12, "selected": false}
]
}
]
}
注意:尺码分面(multi_select: false)的统计是基于白色衬衫的。
示例 4: 混合多个 Multi-Select Facets
{
"query": "*",
"filters": {
"category1_name": "玩具",
"specifications": [
{"name": "颜色", "value": "红色"},
{"name": "材质", "value": "塑料"}
]
},
"facets": [
{
"field": "category1_name",
"size": 10,
"multi_select": true
},
{
"field": "specifications.颜色",
"size": 10,
"multi_select": true
},
{
"field": "specifications.材质",
"size": 10,
"multi_select": true
},
{
"field": "specifications.年龄段",
"size": 10,
"multi_select": false
}
]
}
行为说明:
category1_name: 显示所有类目选项(玩具被标记为 selected)specifications.颜色: 显示所有颜色选项(红色被标记为 selected)specifications.材质: 显示所有材质选项(塑料被标记为 selected)specifications.年龄段: 只显示符合当前过滤条件的年龄段选项
前端集成建议
React 示例
function FacetComponent({ facet }) {
return (
<div className="facet">
<h3>{facet.label}</h3>
{facet.values.map(value => (
<label key={value.value} className={value.selected ? 'active' : ''}>
<input
type="checkbox"
checked={value.selected}
onChange={() => toggleFilter(facet.field, value.value)}
/>
{value.value} ({value.count})
</label>
))}
</div>
);
}
Vue 示例
<template>
<div class="facet">
<h3>{{ facet.label }}</h3>
<label
v-for="value in facet.values"
:key="value.value"
:class="{ active: value.selected }"
>
<input
type="checkbox"
:checked="value.selected"
@change="toggleFilter(facet.field, value.value)"
/>
{{ value.value }} ({{ value.count }})
</label>
</div>
</template>
技术实现细节
Elasticsearch Query 结构
Multi-Select Faceting 使用 post_filter 实现:
{
"query": {
"bool": {
"must": [...],
"filter": [
// 只包含 multi_select=false 的过滤器
{"term": {"category2_name": "短袖T恤"}}
]
}
},
"post_filter": {
"bool": {
"filter": [
// 包含 multi_select=true 的过滤器
{"term": {"brand_name": "苹果"}},
{
"nested": {
"path": "specifications",
"query": {
"bool": {
"must": [
{"term": {"specifications.name": "颜色"}},
{"term": {"specifications.value": "白色"}}
]
}
}
}
}
]
}
},
"aggs": {
// 所有聚合都基于 query 的结果(不受 post_filter 影响)
"brand_name_facet": {...},
"specifications_颜色_facet": {...}
}
}
关键点:
query.bool.filter: 影响结果和聚合post_filter: 只影响结果,不影响聚合- 聚合统计基于
query的结果,因此 multi-select facet 可以显示多个选项
最佳实践
1. 何时使用 Multi-Select
| Facet 类型 | 推荐模式 | 原因 |
|---|---|---|
| 颜色 | multi_select: true |
用户需要切换颜色 |
| 品牌 | multi_select: true |
用户需要比较不同品牌 |
| 尺码 | multi_select: true |
用户需要查看其他尺码 |
| 类目 | multi_select: false |
层级下钻 |
| 价格区间 | multi_select: false |
互斥选择 |
| 是否有货 | multi_select: false |
布尔值筛选 |
2. 性能考虑
- 过多 Multi-Select: 会增加 ES 查询复杂度
- 建议: 最多 3-5 个 multi-select facets
- 优化: 对于不常用的属性使用标准模式
3. UI 设计建议
- Multi-Select Facets: 使用复选框(Checkbox)
- Standard Facets: 使用单选框(Radio)或链接
- Selected 状态: 使用不同颜色或图标标识
API 变更说明
新增字段
FacetConfig:
{
"field": "brand_name",
"size": 10,
"type": "terms",
"multi_select": true // 新增字段
}
FacetValue:
{
"value": "苹果",
"count": 150,
"selected": true // 现在由后端返回真实状态
}
兼容性
multi_select默认为false,保持向后兼容- 旧版 API 调用仍然有效(使用标准模式)
测试验证
运行测试脚本:
python test_multi_select_facet.py
测试覆盖:
- ✓ 标准 Faceting (multi_select=false)
- ✓ Multi-Select Faceting (multi_select=true)
- ✓ Specifications Multi-Select
- ✓ ES Query 结构验证
故障排查
问题 1: Multi-Select 不生效
症状: 设置了 multi_select: true,但仍然只返回一个值
检查:
- 确认
multi_select字段在请求中正确设置 - 检查 ES query 是否包含
post_filter(开启debug: true) - 验证 Elasticsearch 版本支持
post_filter
问题 2: Selected 标记不正确
症状: selected 字段没有正确标记
检查:
- 确认
filters中的字段名与 facet 字段名一致 - 对于 specifications,检查
name和value是否匹配 - 检查
filters的值类型(字符串、数组等)
问题 3: 性能问题
症状: 启用 Multi-Select 后查询变慢
优化:
- 减少 multi-select facets 数量
- 降低 facet
size参数 - 考虑使用缓存
- 为常用字段建立索引