智能搜索系统的升级复盘——从 Elasticsearch 到混合检索的检索质量提升

智能搜索系统的升级复盘------从 Elasticsearch 到混合检索的检索质量提升

一、搜索系统的核心指标:不是结果有多快,而是用户有没有找到

公司在 2021 年上线了基于 Elasticsearch 的全文搜索,初期表现不错。但随着知识库文档量从 10 万增长到 300 万,搜索质量开始下滑。运营反馈用户搜索"活动报名截止日期"时前十名里只有两条相关,用户不得不点好几次"下一页"。技术排查发现两个问题:一是关键词匹配的局限性------用户输入"怎么修改密码"和文档标题"密码重置操作指引"之间缺乏语义关联;二是相关性排序的退化------热门文档在 TF-IDF 模型下持续获得高排名,新发布的精准文档被淹没。

单纯调优 ES 的 analyzer、同义词词典和 function_score 权重,召回率从 62% 提升到了 71%,但仍达不到业务对"前十名中至少 8 条相关"的期望。结合当时向量检索技术的成熟度,我们决定引入混合检索的方案。

二、混合检索架构:关键词 + 语义,各取所长

混合检索的架构并不复杂,核心有三个阶段。第一阶段是查询理解:对用户的输入做分词、实体识别和意图分类,对于明确的关键词查询(如文档编号、错误码)倾向关键词通路,对于长文本描述性查询(如"怎么解决登录超时")倾向语义通路。第二阶段是并行检索:ES 做 BM25 全文检索,向量数据库做 dense embedding 的近似最近邻搜索,两者各自返回 Top 50。第三阶段是融合排序:先用 RRF(Reciprocal Rank Fusion)算法对两路结果做加权融合,再通过 LLM 做最终的精准重排。

向量编码模型我们选的是 BGE-large-zh-v1.5,在 MTEB 中文测评集上表现稳定。文档的 Chunk 策略也做了调整:原来按 512 字切分,发现很多技术文档的核心原理介绍前后横跨了好几个 chunk,语义信息被截断。后来改成了按章节标题切分加 128 字 overlap 的策略,但每个 chunk 的长度上限仍保持在 1024 token 以内以保证编码质量,超出部分按段落做软切割。

三、融合排序的 Java 实现:RRF 算法的多路召回融合

下面展示 RRF 融合算法的核心实现。RRF 是一种简单的多路排序融合方法,不需要知道每路的原始分数,只根据候选文档在各路中的排名位置来重新打总分。

java 复制代码
public class RrfFusion {

    private static final int K = 60; // RRF 常量,控制排名衰减速率

    /**
     * 融合多路召回结果
     * @param recallChannels 各路召回结果,key 为通路名称,value 为按排序排列的文档 ID 列表
     * @return 融合后的文档 ID 排序列表
     */
    public List<String> fuse(Map<String, List<String>> recallChannels) {
        Map<String, Double> fusionScores = new HashMap<>();

        for (Map.Entry<String, List<String>> channel : recallChannels.entrySet()) {
            List<String> docIds = channel.getValue();
            for (int rank = 0; rank < docIds.size(); rank++) {
                String docId = docIds.get(rank);
                double score = 1.0 / (K + rank + 1);
                fusionScores.merge(docId, score, Double::sum);
            }
        }

        // 按融合分数降序排列
        return fusionScores.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
}

在实际落地中,统一的交通管制逻辑在融合阶段也做了工程优化。当两路召回结果重叠度很低时(Jaccard 相似度 < 0.1),说明用户描述可能与任一单路都不太匹配,这时触发 LLM 改写查询,将原始 query 拆解为 2-3 个子查询后重新检索。当某一路召回结果为空时,只依赖另一路结果,不做融合。

重排序阶段通过 LLM 做精细排序,但不是对每条候选都送进模型。我们是取融合结果的 Top 20 候选,以三元组形式(query + document title + key sentences)送入 LLM,要求 LLM 给出 0-10 分相关性评价,然后按分数重新排序。这里的关键是用摘要代替全文来降低 token 消耗------对每条文档预先用规则或小模型提取 3 条关键句,供重排序使用。

四、效果衡量与持续调优

混合检索上线后,核心指标提升显著:Top 10 的相关文档命中率从 71% 提升到 93%,平均首次点击位置从第 7 位提前到第 3 位,搜索的无结果率从 8% 降到 1.2%。但技术的改进不能只看上线当天------我们建立了离线评估集,包含 500 条真实用户搜索及其标注的相关文档,每次索引策略或编码模型变更前都在评估集上跑一遍,确保新策略在所有大类上的表现至少不低于基线。

索引更新策略也做了优化。原来每天凌晨全量重建向量索引,耗时要 4 小时。后来改为增量更新加周期重建:新增文档实时编码进向量库;修改的文档标记为过期,同时生成新向量后替换;删除的文档直接移除。每周末做一次全量索引验证,检查向量一致性和覆盖率。

五、总结

从纯 ES 到混合检索的升级,本质上是把搜索从"关键词匹配"扩展为"关键词 + 语义理解"。RFF 融合算法简单有效,向量编码质量和 Chunk 策略决定了语义检索的上限,LLM 重排序是提升精准度的最后一环。搜索系统的持续改进不能靠直觉,必须建立离线评估基准,用数据说话。

相关推荐
边境悍匪14 小时前
蜗牛学苑 Java 智能体学习 Day39|SpringAI 会话存储、Function‑Call 工具调用、MCP 思维导图复盘
java·开发语言·spring boot·学习·阿里云
letisgo514 小时前
JAVA 高级进阶02篇《并发编程三板斧:JMM、CAS与AQS的源码级拆解》
java·面试·并发编程·aqs·jmm
胡写代码15 小时前
若依 + MyBatis-Plus,分页为什么悄悄失效了?
java·后端
yxlalm15 小时前
4.java秒杀项目第四课-后端商品后台接口
java·开发语言
宁之明起(B服)15 小时前
vulhub靶场(tomcat三件套:PUT写马、Ghostcat与manager弱口令)
java·tomcat
君顾115 小时前
家政派单小程序源码开发实战:从零搭建到上线全流程指南
java·开发语言·家政派单
流烟默15 小时前
HTTP 连接管理技术梳理:JDK KeepAliveCache 机制与池化选型
java·网络协议·http
阿酷tony15 小时前
视频专栏列表的防录屏水印和跑马灯效果(也可网站调用)
java·前端·音视频
洋不写bug16 小时前
排序(一)基础排序,插入|希尔|冒泡|直接选择排序详解
java·算法·排序算法·插入排序·冒泡排序·希尔排序·直接选择排序
xcl092516 小时前
全民健身智慧管理系统实战指南:从架构设计到部署落地
java·spring boot