周末朋友聚餐,你负责从菜单里点菜。你很清楚朋友爱吃辣,于是专挑水煮鱼、毛血旺、麻辣香锅,结果桌上红油一片,朋友吃了几口就喊腻,抱怨“怎么全是辣菜”。推荐系统也有同样的毛病:它只根据你点过的内容推相似内容,你越点,它越推,你的世界越窄。这就是“信息茧房”。 今天要讲的 MMR(最大边缘相关性),像一位懂事的点菜管家:它既知道你爱吃辣,又会在每上一道菜前看一眼桌面——如果这道菜和桌上已有的太像,就往后排。这套策略在“想吃的”和“没重复的”之间寻找平衡,让搜索结果既相关又多样。接下来,我们用“点菜”这条故事线,把 MMR 的目标函数、贪心策略、λ 参数调优和工程落地一次讲透。
掌握 MMR,你就掌握了在相关性与多样性之间做权衡的实用武器;搜索、推荐、内容分发岗位的面试和项目里,它都是高频考点。
目录
可视化演示
展示MMR最大边缘相关性的贪心选择过程、λ参数对相关性与多样性平衡的影响以及与DPP行列式点过程的算法对比,帮助理解推荐系统中多样性建模的经典方法。
本节配有交互动效(进入视口后自动加载,约 3KB)。
'+captions.select+'
1. 信息茧房成因:越吃越窄的菜单
同桌吃饭时,如果每个人都只点自己最爱的菜,结果往往是满桌相似口味。推荐系统也一样:用户点击过某类内容,算法就认为用户只爱这类内容,于是越推越窄。用户再点,再推,形成“点击反馈循环”。久而久之,用户看到的推荐列表越来越同质化,视野不断收窄。这不是用户真的只爱一种口味,而是系统没有主动打破重复。
要把“重复”变成可计算的问题,我们需要一个相似度度量。比如两个视频、两件商品、两篇文章,都可以用向量表示。向量越接近,内容越像。
正是因为“重复”可以被量化,点菜管家才有机会登场:它不追求每道菜都最合口味,而是追求整桌菜既有人爱吃,又不互相撞车。
- 向量内积分子的
d_i \cdot d_j计算两个内容向量在同一方向上的重合程度。 - 模长归一化分母的
\lVert d_i\rVert\,\lVert d_j\rVert消除向量长度差异,让分数落在可比较的范围内。 - 相似度含义Sim 接近 1 表示两个内容高度相似,接近 0 表示差异很大。
2. 目标函数定义:想吃度与撞菜度的天平
点菜管家心里有两本账:一本是“想吃度”,衡量候选菜符不符合朋友的口味;另一本是“撞菜度”,衡量候选菜和已经上桌的菜有多像。MMR 的目标,就是把这两本账合并成一个分数,每轮选出综合分最高的那道菜。
形式化地说,D 是候选菜集合,R 是已经上桌的菜集合,q 是用户或查询的“口味画像”。Sim1 是相关度,Sim2 是相似度。MMR 的每一轮选择是这样的:
“边缘相关性”中的“边缘”,指的就是这一道新菜相对于当前桌面带来的新增价值。它和桌上已有的菜越像,边际价值就越低。
- 候选范围
d_i\in D\setminus R表示只考虑还没上桌的菜。 - 相关项
\lambda\, \operatorname{Sim}_1(d_i,q)是候选菜对口味偏好的满足程度。 - 冗余惩罚
(1-\lambda)\max_{d_j\in R}\operatorname{Sim}_2(d_i,d_j)找出候选菜与已上桌菜最像的那道,像得越多,惩罚越重。 - 选择规则
\mathop{\arg\max}表示把边际得分最高的菜端上桌。
3. 贪心选择策略:一盘一盘定菜
点菜管家不会一上来就想明白整桌 20 道菜的最优排列,它只做一件事:当前桌上有哪些菜,下一道选谁能让边际价值最大。选完就上桌,不再回头。这就是贪心策略。
形式化地,第 t 轮从尚未选择的候选集中选出一道菜:
贪心的好处是快:朴素实现下,跑完 k 轮的时间复杂度大约为 O(k²n),候选集合几百条时完全可接受。但它只是近似最优,不是全局最优解。
- 上一轮桌面
R_{t-1}是已经选好的菜集合,当前候选要拿它和这桌菜比较。 - 本轮最佳菜
d_t^*=\mathop{\arg\max}表示本轮选边际得分最大的候选。 - 更新桌面
R_t=R_{t-1}\cup\{d_t^*\}把选中的菜加入已选集合,下一轮从剩余候选里继续选。
4. 参数调优方法:旋转咸淡旋钮
同一道菜,有人觉得咸,有人觉得淡。λ 就是点菜管家的咸淡旋钮:λ 越接近 1,越重视口味相关;λ 越接近 0,越重视桌面多样。默认从 0.5 开始,不代表 0.5 永远最好。
实际调参时,我们会准备一组候选值,比如 0.1、0.3、0.5、0.7、0.9,对每个 λ 跑一遍离线评估,再用线上 A/B 验证。评估指标通常分为相关性和多样性两类:
调参不是一次性的。搜索结果页可能 λ 要更高,因为用户有明确目标;信息流推荐 λ 可以低一点,因为用户愿意探索。就像做菜一样,最终以“上桌后的反馈”为准。
- 候选 λ 集合
\lambda\in\Lambda表示我们只在预先准备的几个旋钮档位里找。 - 业务加权
\alpha\cdot \operatorname{Rel}(\lambda)+\beta\cdot \operatorname{Div}(\lambda)把两个指标加权成一个总分。 - 选择最优
\mathop{\arg\max}找到让总分最高的 λ。
5. 工程实现路径:从菜单到线上推荐
线上系统通常不会让 MMR 处理百万级候选,它更适合放在“重排层”:先用召回和精排筛出最相关的几百条候选,再用 MMR 对这些候选做多样性重排。这就像点菜管家只从 50 道备选菜里挑 10 道,而不是翻遍整个菜市场。
为了控制延迟,相似度矩阵可以离线预计算并缓存;线上只需要做查表和贪心选择。候选越多,计算量增长越快,所以常见做法是“头部截断”——只对精排 Top-N 做 MMR。
冷启动场景也很适合 MMR:新用户没有历史行为,系统先用热门内容做候选,再用类目、标签、内容向量计算相似度,保证第一屏什么类型都有,给用户更多探索机会。
- 候选规模
n=|D|表示进入 MMR 的候选数量,通常控制在几百。 - 目标规模
k=|R|表示最终要输出的结果数量,比如 10 条或 20 条。 - 复杂度含义
O(k^2 n)表示轮数越多、候选越多,耗时按二次关系增长。
6. MMR对比DPP:点菜管家与宴会设计师
MMR 像一位手脚麻利的点菜管家,一道一道地加菜,每次只看局部。另一种思路叫 DPP(行列式点过程),它更像宴会设计师:不只看下一道菜,而是直接评价“整桌菜摆在一起好不好”。
DPP 用一个核矩阵描述候选集合之间的关系,矩阵元素由质量分和相似度共同构成。对某个候选子集 Y,它的“好菜程度”用行列式来衡量:
DPP 能更好地建模全局多样性,但求解更复杂。实际中,如果候选少、多样性强需求高,可以选 DPP;如果线上延迟敏感、希望快速落地,MMR 通常更实用。
- 核矩阵元素
L_{ij}=q_i q_j S_{ij}由两个物品各自的质量分和相似度相乘得到。 - 子矩阵
L_Y是只保留 Y 中元素的行和列形成的子矩阵。 - 行列式
\det(L_Y)衡量这个集合的“体积”,越相似的行越会压缩体积,导致得分下降。
AI 应用场景
搜索结果重排:同义结果打散
阶段:召回与精排之后的“重排层”
解决的问题:传统搜索只按相关度排序,搜“华为”时前十条可能全是手机资讯,品牌旗舰店、售后、耳机、鸿蒙系统等内容被淹没。MMR 在精排分数之上减去与已选结果的最大相似度,让同义内容分散,提高信息覆盖率。
具体案例:电商搜索“连衣裙”,精排前十个结果可能款式高度相似。MMR 用“风格、价格、面料”等维度构造相似度,重排后前十条覆盖法式、通勤、碎花、纯色等不同方向,同时保持基本相关。
信息流推荐:别让信息茧房越收越紧
阶段:个性化推荐的后处理与多样性重排
解决的问题:推荐系统偏向点击高、与用户历史高度相似的内容,用户点得越多,推荐越窄。MMR 在 CTR 预估分数上加入类目、话题、作者的多样性惩罚,让喜欢科技的用户也能看到生活、财经等泛内容。
具体案例:短视频 App 识别出用户有“宠物”强兴趣,但仍会在每 10 条推荐中插入 1~2 条泛知识内容。MMR 从候选里选择与已展示视频最不重复、同时保留一定相关度的视频,观察次留与人均时长。
新用户冷启动:没有历史也避开千篇一律
阶段:冷启动阶段的候选多样性控制
解决的问题:新用户没有行为日志,如果直接上热门榜,前几屏可能全是同质爆款。MMR 用物品内容相似度对冷启动候选重排,让第一屏类目足够宽,便于探索用户真正兴趣。
具体案例:音乐 App 新用户注册后,用“语种、曲风、年代”构造相似度,从热门曲库中选 20 首,保证流行、民谣、说唱、古典都有代表,而不是前十首全是同一歌手的伤感情歌。
Python 演示
# -*- coding: utf-8 -*- def mmr_select(relevance, similarity, lam=0.5, k=3): selected = [] candidates = list(range(len(relevance))) while len(selected) < k and candidates: best_score = float("-inf") best_idx = None for i in candidates: redundancy = 0.0 for j in selected: if similarity[i][j] > redundancy: redundancy = similarity[i][j] score = lam * relevance[i] - (1 - lam) * redundancy if score > best_score: best_score = score best_idx = i selected.append(best_idx) candidates.remove(best_idx) return selected if __name__ == "__main__": dishes = ["红烧肉", "糖醋里脊", "清炒时蔬", "剁椒鱼头", "麻婆豆腐", "蒜蓉西兰花"] relevance = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4] similarity = [ [0.0, 0.8, 0.3, 0.9, 0.4, 0.2], [0.8, 0.0, 0.6, 0.7, 0.5, 0.3], [0.3, 0.6, 0.0, 0.2, 0.8, 0.7], [0.9, 0.7, 0.2, 0.0, 0.3, 0.1], [0.4, 0.5, 0.8, 0.3, 0.0, 0.9], [0.2, 0.3, 0.7, 0.1, 0.9, 0.0], ] for lam in [0.1, 0.5, 0.9]: order = mmr_select(relevance, similarity, lam, 3) names = [dishes[i] for i in order] print("lambda=%.1f -> %s" % (lam, "、".join(names)))
def mmr_select(relevance, similarity, lam=0.5, k=3):定义点菜管家接口:输入相关度、相似度矩阵、λ 和菜数量。for j in selected:遍历已选中的菜,找当前候选菜与它们的最大相似度。if similarity[i][j] > redundancy:用打擂台方式更新“撞菜度”。score = lam * relevance[i] - (1 - lam) * redundancyMMR 核心打分公式。selected.append(best_idx)把本轮得分最高的菜端上桌。candidates.remove(best_idx)从候选菜单里划掉这道菜,避免重复上桌。for lam in [0.1, 0.5, 0.9]:对比三个 λ 档位,直观感受参数变化。
常见误区
误区我把 λ 设为 0.5,相关性和多样性就刚好平衡,模型不用再调了。
正解0.5 只是中性起点,不是普适最优。不同业务中,用户对重复的容忍度完全不同:搜索精确意图时 λ 要高,信息流探索场景 λ 可以低。必须用离线指标和线上实验调,不能拍脑袋。
为何常见:公式里两项权重看起来对称,很多人误以为对半就是“平衡”。
误区MMR 中的相似度就是文本余弦相似度,其他信息用不上。
正解实际工程里,相似度可以由类目、标签、embedding、协同过滤、甚至用户行为共现共同构成。视频推荐会用封面、导演、演员相似;冷启动时用物品内容属性。相似度定义直接决定“多样性”的语义。
为何常见:很多教程用文本检索举例,容易让人以为 MMR 只服务于文本场景。
误区我训练好 CTR 模型后,用 MMR 再排一遍,就不需要 Learning to Rank 了。
正解MMR 是重排层,不是主排序模型。它拿精排模型给出的相关度分数作为输入,再叠加多样性惩罚。如果候选本身相关度很差,MMR 也只能在差列表里挑差异。它不能学习特征,也不能替代精排。
为何常见:因为 MMR 改变了最终顺序,看起来像在学习排序,实际只是后处理。
误区每一轮选边际得分最大的菜,最终整桌菜一定是最优组合。
正解贪心只保证当前步骤最优,不保证全局最优。MMR 对应的组合优化问题是 NP 难的;贪心是高效近似。DPP 之类方法通过行列式建模全局多样性,但计算更重。
为何常见:每一步看起来都很合理,缺少全局反例的直觉。
面试题
Q1. 在 MMR 公式中,λ 控制的是什么?
- A.相关性和多样性的权重← 正确答案
- B.候选集合的样本数量
- C.用户点击概率阈值
- D.物品向量空间维度
答案:A。λ 是 MMR 目标函数里相关项和多样性惩罚项之间的权重。λ 越大越重视相关,越小越重视多样;它不控制候选数量、点击阈值或向量维度。
Q2. MMR 的第二项为什么对已选集取“最大相似度”?
- A.找出与候选最撞菜的一道← 正确答案
- B.找出与候选最相关的一道
- C.找出候选里相似度最小的
- D.找出已选集合的平均值
答案:A。MMR 要惩罚“和桌上已有的哪道菜最像”的重复感,所以先找到相似度最大的那个已选项,再用它代表冗余程度。平均值会稀释“最撞菜”的风险。
Q3. λ=0.8 时,MMR 会更偏向下列哪种结果?
- A.相关性更高的结果← 正确答案
- B.多样性更高的结果
- C.点击率更高的结果
- D.随机性更高的结果
答案:A。λ=0.8 时,相关项权重为 0.8,而多样性惩罚权重只有 0.2,所以整体更偏向相关。点击率是排序模型的输出,不是 MMR 的权重语义。
Q4. MMR 每轮选择的依据是什么?
- A.当前边际得分最高← 正确答案
- B.全桌组合得分最高
- C.单独相关度最高
- D.单独差异度最高
答案:A。MMR 是贪心算法,只选“当前桌面状态下”边际得分最高的候选。它不是全局组合最优,也不是只按相关度或只按差异度排序。
Q5. MMR 最适合放在推荐系统的哪个流程?
- A.召回后的重排阶段← 正确答案
- B.日志采集与清洗
- C.用户画像存储
- D.特征离线训练
答案:A。MMR 需要精排给出的相关度分数和候选物品,适合在召回和精排之后做重排。日志、画像和特征训练都不是它的直接场景。
Q6. 朴素实现 k 轮 MMR 的复杂度约为多少?
- A.O(k×n),约线性
- B.O(k²×n),约二次← 正确答案
- C.O(n²),只随候选增长
- D.O(k×n²),轮数线性
答案:B。每一轮要为每个候选遍历已选集合,第 t 轮约 n×t 次比较,k 轮累计约 n×k²。因此朴素实现的复杂度是 O(k²n)。
Q7. DPP 选择子集时,打分函数通常由什么表示?
- A.子集对应行列式的值← 正确答案
- B.子集元素数量总和
- C.子集元素最大相关度
- D.子集元素采样顺序
答案:A。DPP 用核矩阵的行列式衡量子集的多样性和质量。相似的物品会让矩阵行向量靠近,行列式变小,组合得分降低。DPP 由此建模全局多样性。
Q8. 下列哪些做法能降低 MMR 线上开销?
- A.预计算物品相似度← 正确答案
- B.只重排头部候选← 正确答案
- C.对全量候选穷举
- D.使用近似最近邻← 正确答案
答案:ABD。预计算相似度可以避免线上重复计算;只重排头部候选能把 n 从百万降到几百;近似最近邻可以加快相似物品检索。对全量候选穷举反而会增加开销。
Q9. 哪些属于信息茧房的典型成因?
- A.推荐列表单一同质← 正确答案
- B.点击反馈放大偏好← 正确答案
- C.用户视野不断收窄← 正确答案
- D.服务器资源不足
答案:ABC。信息茧房来自推荐列表同质化、点击反馈循环、用户视野收窄三者的互相强化。服务器资源不足是工程问题,不是信息茧房的成因。
Q10. 调优 MMR 的 λ 时,可以观察哪些信号?
- A.离线相关性指标← 正确答案
- B.用户平均停留时长← 正确答案
- C.推荐结果覆盖率← 正确答案
- D.用户设备型号
答案:ABC。离线相关性衡量相关不塌方,覆盖率衡量多样性提升,平均停留时长反映线上真实体验。设备型号与 λ 调优没有直接关系。