2273 字
约 7 分钟
16
S20-A25 · 分面检索:为什么"筛选五个条件"就把结果筛没了

一个商品搜索支持五个筛选项(品牌、价格、颜色、尺寸、库存)。用户勾了三个,结果只剩 2 条——而"只勾两个"时有 200 条。而分面设计的问题在于:每个分面的可选值,是"在当前结果集上"统计的——于是"勾得越多,可选值越少",直到"全部变灰".

分面(facet)的核心是"统计的口径":按"当前已选条件"统计(联动),还是"按全部数据"统计(不联动)。而这两种口径的体验差别,比"筛选项多少"大得多.

"排除自身"的写法在 DSL 里很直观,而它常被"一把 must 全加上"破坏:

// 统计"品牌"分面时:其它条件在 filter,品牌条件"不在"
{"size": 0, "query": {"bool": {"filter": [{"term": {"color": "red"}}]}},
 "aggs": {"brands": {"terms": {"field": "brand.keyword", "size": 20}}}}
// 判据:品牌条件"不进 filter",才能"看到换品牌还有多少"

1. 两种"分面口径"

口径 效果
联动(含自身条件) 勾选后"自己的其它值"变灰
只含"其它分面" 自己那一栏的选项保持可见
两种混用 最容易出错

第二项是"电商常用"的正解:统计"品牌"这一栏时,排除"品牌"自己的勾选,但保留其它分面的条件第二项的"名字"叫"post-filter 分面":先按"其它分面"过滤,再对"本分面"做聚合(不带它自己的条件)——**于是"每个分面都显示'换成别的值有多少'".
——**于是"你能看到'换成另一个品牌还有多少'".

2. "筛没了"的三种成因

成因 表现
口径错(含自身) 勾了 A 品牌,其它品牌全灰
数据稀(长尾组合) 三条件交集为空
语义重叠(颜色 vs 款式) 勾两个互相排斥

第一项是"设计问题",第二项是"数据问题",第三项是"建模问题"——而它们的"修法完全不同".

"0 条"要"区分"是"真没有"还是"被其它条件挤掉":

// 两步判定(一条查询 + 一次对照)
1 去掉"本分面"条件后,该值仍有 0 条 → 数据里真没有
2 去掉"其它分面"后,该值有 N 条 → 是"当前条件组合"挤掉的
// 判据:第 1 种"置灰并折叠",第 2 种"显示并提示'当前条件下为 0'"

3. "分面为 0"的三种处理

处理 体验
隐藏为 0 的选项 干净,但"看不到还能选什么"
显示但置灰(带 0) 最透明(推荐)
显示 + "点它会发生什么" 最好(如"放宽到 2 个条件")

第二项是"最少争议"的:**用户看到"这个选项 0 条",就知道"是数据没有,不是我漏点了".

"建议放宽哪个"要"算",而算法只有三步:

// 三步"放宽建议"
1 当前条件集 S → 命中 0
2 对每个分面 f:S \ {f} → 命中 c(f)
3 取 c(f) 最大的 f → "放宽 f 后有 c 条"
// 判据:给"一条具体建议",而不是"请减少筛选条件"

4. "长尾组合为空"的三种应对

应对 说明
提示"当前条件过严" 一句话(成本最低)
提供"最接近的条件组合" 需要"放宽计算"
允许"部分匹配"排序 复杂(相关性下降)

第一项的"实现"要用"分面计数":"把每个分面的条件依次去掉,算一次命中数"——取"命中数增加最多"的那个,作为"建议放宽的维度".
第一项是"最实用"的:
"当前 5 个条件下没有结果,放宽'颜色'后有 12 条"**——而"放宽哪一个"要用"分面计数"算出来.

"预计算"要"能更新",否则"数字越来越旧":

// 三种"更新"策略
1 定时全量重算(每小时)→ 简单,但"新上架"不出现
2 增量更新(按变更文档)→ 复杂,但"准"
3 混合:单分面预计算 + 0 条时"实时确认" → 推荐
// 判据:数字"旧 1 小时"能否接受——能,就用 1

5. "分面统计"的性能代价

口径 成本
每次请求实时算 高(多一次聚合)
预计算(按组合) 组合爆炸
预计算(按单分面) 中(近似)

第三项是"常见折中":"每个分面单独预计算",统计时"忽略其它分面"第三项的"数字偏差"方向是"偏高":"忽略其它条件"会让"计数 ≥ 实际"——**于是"置灰判断"不能只看它,还要"用精确计数确认 0 条".
——于是"数字不准"(略高),但"性能可控";而"不准"通常"不影响决策".

6. 排错:五种"分面问题"

现象 成因 处理方向
勾选后自己变灰 口径含自身 排除自身条件
数字与实际不符 预计算近似 标注"约"
某分面永远 0 字段未索引/映射错 查 mapping
组合一多就没结果 长尾 提示放宽
分面慢 实时聚合 预计算/缓存

"分面数量"也有上限,太多会让"选择成本"超过"帮助":

// 三个"够用"的经验值
1 分面 3–6 个(超过 8 个,用户"看不过来")
2 每个分面"默认显示前 10–20 个有值项"(其余折叠)
3 默认"收起"低频分面(如"材质"),点击展开
// 判据:首屏"筛选项"不超过"一屏"

7. 边界:什么情况"不必做分面"

场景 为什么 做法
结果集很小(< 50) 用户能翻完 不必
只有一个筛选维度 无"分面"可言 下拉即可
数据量小、更新频繁 预计算不划算 简单筛选
用户目标明确(按 ID 查) 不需要浏览 不必

最后一条与"数据"有关的边界:"分面依赖字段可聚合":"文本字段若没开 fielddata/keyword 子字段,就无法聚合"——于是"分面全 0"的第一嫌疑,是"mapping 没给可聚合类型",而不是"没数据".
判断口径一句话:
"用户会不会"在结果里"逐步收窄""**。会(电商、文档库、招聘),分面是"必需";不会(精确查找、单一入口),它只是"多一层复杂度".

再补一个"体验"细节:"分面数字"要"能对上结果数"——"品牌 A 显示 12 条",而"点进去只剩 9 条",会让用户"觉得系统不准"。而它的成因通常是"预计算口径"与"实际查询"不一致:一个"忽略了其它分面",另一个"包含全部条件"。修法有两种:要么"点进去时用同一口径"(改查询),要么"显示时标注'约 12 条'(改文案)——而"两处口径不同还不标注",是分面最容易被投诉的地方。

还有一个"多选"的坑:"同分面多选"的语义是"或"还是"且"——"品牌选 A 和 B"通常是"或"(A 或 B),而"颜色选红和蓝"也是"或",但"同一分面里'且'是不可能的"——于是"多选"必须"每个分面内用 should、分面间用 must"。而"写错一处",用户就会看到"勾了两个品牌,结果反而更少"。这类 bug 在"筛选项超过 3 个分面"之后极易出现,而"测试用例"通常只覆盖"单选"。

而"分面内 should、分面间 must"这一条,值得写成"一条测试":"勾两个品牌"的结果数,应当 ≥ "勾一个品牌"的结果数——**小于,就说明"分面内用了 must".

而这条测试,只需要"两条查询 + 一个断言"。

它比"人工点十个组合"可靠得多。

而"可靠"这件事,是分面能被长期使用的底线。

8. 自测

  1. 两种"分面口径"的差别是什么?为什么"排除自身"是电商的正解?
  2. "筛没了"的三种成因分别属于"设计/数据/建模"哪一类?
  3. "显示但置灰(带 0)"为什么"最少争议"?
  4. "长尾组合为空"时,怎么知道"放宽哪一个"最有效?
  5. "按单分面预计算"的代价是什么?为什么"数字略高"通常可接受?
  6. 判断"是否需要分面"的那个问题是什么?
S20-A25 · 分面检索:为什么"筛选五个条件"就把结果筛没了
https://www.clxhxhhr.top/posts/6690/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。