百度相关搜索是搜索引擎结果页底部给出的一组推荐查询词,其本质是对用户搜索意图的二次理解与延伸。从系统内部看,它并不是在用户敲下回车后才临时计算,而是依托离线挖掘与在线召回两套流水线协同完成。离线部分每天对数十亿条查询日志做清洗和聚类,在线部分则根据当前query实时补全候选。这种混合架构既保证了词语热度足够真实,也避免了完全静态词表带来的滞后问题。

用户行为日志如何驱动相关词挖掘
百度相关搜索最核心的数据源是海量用户查询日志。每一条日志都记录了用户输入的原始词、后续是否改写、点击了哪个结果以及停留时长。当大量用户在搜过“ Python 教程”之后紧接着搜“ Python 爬虫框架”,系统就会在共现图上把这两个节点连一条边,边的权重随人数增加而变粗。这种基于会话(session)的序列挖掘,比单纯看两个词在同一篇网页里出现的频率更贴近真实意图。
在工程实现上,百度通常采用基于时间窗口的会话切分。如果一个用户两次搜索间隔超过三十分钟,或者中间跳到了完全不相关的站点,就会被切成两个独立会话,防止噪声污染。随后利用类似 word2vec 的 skip-gram 模型把查询词映射到向量空间,语义相近的词在向量距离上自然靠拢。下面是一段简化的日志共现统计伪代码,展示了如何从原始日志生成词对权重:
import collections
# 原始会话列表,每个会话是查询词组成的列表
sessions = [
["Python 教程", "Python 爬虫框架"],
["Python 教程", "Python 数据分析"],
["Java 基础", "Java 多线程"]
]
pair_weight = collections.defaultdict(int)
window = 2 # 同一个会话内向前向后看两个词
for sess in sessions:
for i in range(len(sess)):
for j in range(max(0, i - window), min(len(sess), i + window + 1)):
if i != j:
pair_weight[(sess[i], sess[j])] += 1
for pair, w in pair_weight.items():
print(pair, w)
上述代码只是最小演示,真实系统还要处理拼写纠错、繁简转换以及敏感词过滤。比如“python 教程”和“PYTHON 教程”会被归并,而涉及违规内容的词对会在入库前直接丢弃。经过这层加工,相关搜索的词库就有了扎实的行为基础,而不是编辑人工拍脑袋列出来的。
语义模型与实时上下文的融合机制
仅靠历史共现会遇到冷启动问题:一个新出现的事件词几乎没有共现记录,这时就要靠语义模型补位。百度内部会训练大规模中文预训练语言模型,把查询词切成字、词、实体多粒度特征,再结合知识图谱判断“显卡缺货”和“GPU 价格上涨”属于同一事件簇。在线服务接收到 query 后,除了拉取离线挖出的高频共现词,还会用模型生成一批语义扩展候选,两者按置信度打分融合。
实时上下文则体现在地理位置、设备类型和搜索时间上。同一个“滑雪”在北方冬季和南方用户眼里相关词完全不同,系统会动态把“崇礼滑雪场”或“室内滑雪模拟机”往前排。这种融合不是简单拼接,而是用轻量排序模型(如 LambdaMART)对候选词做最终截断。下面的表对比了纯共现与融合模型在准确率上的差异:
| 方案 | 冷启动词覆盖率 | 用户点击率提升 |
|---|---|---|
| 纯日志共现 | 41% | 基准 |
| 共现+语义模型 | 78% | +12.5% |
| 共现+语义+实时上下文 | 86% | +19.3% |
从表中可以看出,引入语义与上下文后,相关搜索不再局限于“大家之前搜过什么”,而能猜到“你现在可能还想搜什么”。这也是为什么你在手机端和电脑端看到的相关词偶尔不一样,背后正是设备与场景特征在起作用。
反作弊与质量控制的落地策略
相关搜索词如果能被随意操纵,就会变成灰产引流工具。百度因此布置了多层反作弊防线。第一层是查询日志本身的异常检测,突然暴增的詞对若来源 IP 集中、点击立刻跳出,会被判定为机器刷词。第二层是内容一致性校验,相关词点进去的结果页必须确实包含对应实体,否则词会被降权。第三层是人工巡检与投诉闭环,普通用户举报的垃圾相关词会在数小时内进入审核队列。
在代码层面,反作弊模块常以流式计算呈现。例如用 Flink 统计每分钟词对出现次数,超过动态阈值就拦截。下面是一段简化版的流式过滤逻辑:
public class RelatedSearchFilter extends KeyedProcessFunction<String, QueryPair, QueryPair> {
private transient ValueState<Integer> countState;
@Override
public void open(Configuration parameters) {
countState = getRuntimeContext().getState(
new ValueStateDescriptor<>("cnt", Integer.class));
}
@Override
public void processElement(QueryPair pair, Context ctx, Collector<QueryPair> out) throws Exception {
Integer cnt = countState.value();
if (cnt == null) cnt = 0;
cnt += 1;
countState.update(cnt);
// 同一词对每分钟超过 500 次视为异常
if (cnt <= 500) {
out.collect(pair);
}
}
}
除了技术拦截,百度也会对违规站点做降级处理。一旦某个域名反复通过相关搜索导流到低质页面,该域名的权重会被调低,连带它贡献的词对也失去展示机会。正是这种“行为—内容—反馈”的闭环,让相关搜索整体维持在可用且相对干净的状态,而不是沦为 SEO 作弊的战场。