BM25 算法与关键词提取在向量数据库中的实践优化

news2025/5/17 10:31:15

BM25 算法与关键词提取在向量数据库中的实践优化

在实际构建问答系统或语义检索场景中,向量数据库(如 Weaviate)提供了基于语义匹配的检索能力,然而我们发现 BM25 关键词检索效果不理想,甚至出现了召回率过低、查询必须精确匹配等问题。
深入排查后,发现问题根源有三:
● 使用 BM25 时,语料库未经过有效分词处理;
● 缺少显式的关键词字段;
● 用户 query 与语料库不一致,导致匹配失败。

💡 问题背景

在构建知识库检索系统过程中,使用了 Weaviate + BM25 作为关键字召回方案,但出现了以下问题:
● 查询内容若与问题文本不完全一致,无法匹配;
● BM25 检索字段未分词(tokenization);
● 用户输入 query 未标准化(如:未分词);

🚧 解决思路与每一步分析

1. 使用 dify 的 keyword 提取方法,在检索和插入时统一处理关键词(pass)

core/rag/datasource/retrieval_service.py

class RetrievalService:
    @classmethod
    def retrieve(
        cls,
        retrieval_method: str,
        dataset_id: str,
        query: str,
        top_k: int,
        score_threshold: Optional[float] = 0.0,
        reranking_model: Optional[dict] = None,
        reranking_mode: Optional[str] = "reranking_model",
        weights: Optional[dict] = None,
    ):
        # ....这部分代码省略了
        if retrieval_method == "keyword_search":
            keyword_thread = threading.Thread(
                target=RetrievalService.keyword_search,
                kwargs={
                    "flask_app": current_app._get_current_object(),
                    "dataset_id": dataset_id,
                    "query": query,
                    "top_k": top_k,
                    "all_documents": all_documents,
                    "exceptions": exceptions,
                },
            )
            threads.append(keyword_thread)
            keyword_thread.start()

● 实现方式
将retrieval_method == "keyword_search"中的代码应用到全文索引中,然后根据默认权重配置keyword_search的返回结果与BM25的搜索结果进行整合返回。
● 为什么这么做?
保证检索时对用户 query 的处理方式与语料构建时一致,避免因分词策略不同导致的召回不一致。
● 好处:
○ 一致性高:插入、检索使用同一套 keyword 提取逻辑;
○ 实现简单:封装函数、按权重检索;
○ 具备可控性:可调节关键词提取策略。
● 缺点:
○ 需修改检索逻辑;
○ 测试的时候对程序运行性能影响较高,造成卡顿现象

2. 在 Weaviate 中为 BM25 检索添加 tokenized_content 字段

核心代码

# 插入数据,附带分词字段
for q, a in qa_data:
    segmented_q = " ".join(jieba.lcut(q+a))
    client.data_object.create(
        data_object={
            "question": q,
            "segmentedQuestion": segmented_q,
            "answer": a
        },
        class_name="QAPair"
    )

    result = client.query.get("QAPair", ["question", "answer"]) \
            .with_bm25(query=query_text, properties=["segmentedQuestion"]) \
            .with_limit(3) \
            .do()

● 为什么这么做?
将语料中的内容预先分词,并按空格分隔成字符串,存储在新字段中,供 BM25 使用。
● 好处:
○ 充分利用 BM25 的词频特征;
○ 可扩展为对任意内容的分词检索;
○ 配合 with_bm25 可轻松启用多字段召回。
● 缺点:
○ 数据迁移成本高;
○ 增加字段后需兼容现有逻辑;
○ 用户输入未标准化,召回结果任然不理想

3. 对用户输入的 Query 做分词预处理

核心代码

segmented_queries = " ".join(jieba.lcut(query))

● 为什么这么做?
与语料中的 tokenized_content 对齐,避免中文 query 无法匹配 token。
● 好处:
○ 显著提升召回率;
○ 查询语义更清晰;
○ 保证检索一致性。
● 缺点:
○ 用户体验上难以感知;
○ 仍受限于关键词提取准确性。

🔬 效果测试与对比分析

我分别测试了以下两种场景:测试代码参考 github连接

📌 未分词的 Query + 原始语料

● 查询 “人工智能是什么”
● 结果为空或错误,必须输入 “什么是人工智能?” 才能命中

✅ 分词后的 Query + 分词语料字段 (segmentedQuestion)

● 查询:“人工智能是什么”
● 命中效果大幅提升,多个语料均被正确匹配

对比项 原始方式(未分词) 优化方式(分词+keyword)
召回率 较低 明显提升
用户容错性 差 好
系统复杂度 简单 增加字段、代码稍复杂
开发适应性 高 需同步维护关键词提取逻辑
查询效率 快 PostgreSQL 存储场景略卡顿

⚠️ PostgreSQL keyword 权重查询方案存在的问题

虽然我们尝试结合 BM25 + keyword 搜索 + 权重配置的方式,在 PostgreSQL 中实现 fulltext 搜索方案,但最终:
● 查询效果非常好;
● 查询速度严重卡顿;
● 不适合高并发线上环境。
因此该方案被标记为高风险。

✅ 最终推荐方案:结合 BM25 + 分词字段

综合考虑效果与性能:

  1. 为语料增加 tokenized_content 字段;
  2. 插入语料时进行分词填入该字段;
  3. 查询时对 query 分词,与该字段对齐;
  4. 使用 Weaviate 的 with_bm25 指定使用该字段检索。
    该方式在准确性、性能、维护成本之间取得了良好平衡。

🧠 总结

本次针对向量数据库中 BM25 匹配效果差的问题,从关键词缺失、分词不一致、语料结构单一等多个角度进行优化,主要提升措施包括:
● 增加分词字段 segmentedQuestion / tokenized_content;
● 插入和查询统一使用 jieba 分词;
● 尝试结合 keyword 库 + PostgreSQL,但因性能问题暂时搁置;
● 最终实现了一种高效、稳定的 hybrid 检索方案。
📌 关键词召回 + 向量语义检索,将是构建强大问答系统的未来主流方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2377577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python版本管理工具-pyenv轻松切换多个Python版本

在使用python环境开发时,相信肯定被使用版本所烦恼,在用第三方库时依赖兼容的python版本不一样,有没有一个能同时安装多个python并能自由切换的工具呢,那就是pyenv,让你可以轻松切换多个Python 版本。 pyenv是什么 p…

elementUI 循环出来的表单,怎么做表单校验?

数据结构如下&#xff1a; diversionParamList: [ { length: null, positionNumber: null, value: null, } ] 思路&#xff1a;可根据 index 动态绑定 :props 属性值&#xff0c;校验规则写在:rules <div class"config-item" v-for"(item, index) in form.…

Leetcode76覆盖最小子串

覆盖最小子串 代码来自b站左程云 class Solution {public String minWindow(String str, String tar) {char[] s str.toCharArray();char[] t tar.toCharArray();int[] cnt new int[256];for (char cha : t) { cnt[cha]--;}int len Integer.MAX_VALUE;int debt t.length…

电力杆塔安全监测解决方案

一、方案背景 在台风、滑坡等自然灾害出现时&#xff0c;极易产生倒杆、断杆、杆塔倾斜、塔基滑动等致使杆塔失稳的状况&#xff0c;进而引发导线断线、线路跳闸等事故&#xff0c;给电网的安全稳定运行造成影响。可借助在铁塔上装设的传感器&#xff0c;能够感知铁塔的工作状态…

AD 常用系统快捷键

(1) L: 打开层设置开关选项(在元件移动状态下&#xff0c;按下“L”键换层) (2) S: 打开选择&#xff0c;如SL(线选)、SI(框选)、SE(滑动选择) (3) J: 跳转&#xff0c;如JC(跳转到元件)、JN(跳转到网络) (4) CtrlQ: 英寸和毫米相互切换。 (5) Delete: 删除已被选择的对象 E…

今日行情明日机会——20250516

上证缩量收阴线&#xff0c;小盘股表现相对更好&#xff0c;上涨的个股大于下跌的&#xff0c;日线已到前期压力位附近&#xff0c;注意风险。 深证缩量收假阳线&#xff0c;临近日线周期上涨末端&#xff0c;注意风险。 2025年5月16日涨停股行业方向分析 机器人概念&#x…

AlphaEvolve:LLM驱动的算法进化革命与科学发现新范式

AlphaEvolve&#xff1a;LLM驱动的算法进化革命与科学发现新范式 本文聚焦Google DeepMind最新发布的AlphaEvolve&#xff0c;探讨其如何通过LLM与进化算法的结合&#xff0c;在数学难题突破、计算基础设施优化等领域实现革命性进展。从48次乘法优化44矩阵相乘到数据中心资源利…

多尺度对比度调整

一、背景介绍 受到了前面锐化算法实现的启发&#xff0c;对高频层做增强是锐化&#xff0c;那么对中低频一起做增强&#xff0c;就应该能有局域对比度增强效果。 直接暴力实现了个基本版本&#xff0c;确实有对比度增强效果。然后搜了下关键字&#xff0c;还真找到了已经有人这…

解决IDEA Maven编译时@spring.profiles.active@没有替换成具体环境变量的问题

如果不加filtering true&#xff0c;编译后的文件还是 spring.profiles.active 编译前的application.yml 编译后的application.yml【环境变量没有改变】 解决方案 找到 SpringBoot 启动类所在的pom.xml&#xff0c;在 resources 增加 filtering true&#xff0c;然后重新…

记参加一次数学建模

题目请到全国大学生数学建模竞赛下载查看。 注&#xff1a;过程更新了很多文件&#xff0c;所有这里贴上的有些内容不是最新的&#xff08;而是草稿&#xff09;。 注&#xff1a;我们队伍并没有获奖&#xff0c;文章内容仅供一乐。 从这次比赛&#xff0c;给出以下赛前建议 …

Maven使用详解:Maven的概述(二)

一、核心定义与功能 Maven是由Apache软件基金会开发的开源项目管理工具&#xff0c;专为Java项目设计&#xff0c;主要用于自动化构建、依赖管理和项目标准化。其核心功能包括&#xff1a; 依赖管理&#xff1a;通过pom.xml文件声明依赖库&#xff0c;自动从中央仓库下载并管…

新型智慧园区技术架构深度解析:数字孪生与零碳科技的融合实践

&#x1f3ed;在杭州亚运村零碳园区&#xff0c;光伏板与氢燃料大巴构成的能源网络&#xff0c;正通过数字孪生技术实现智能调度。这不仅是格力电器与龙源电力在新能源领域的创新实践&#xff0c;更是智慧园区4.0时代的标杆案例。当AI算法开始接管能源调度&#xff0c;当BIM建模…

Linux基础开发工具大全

目录 软件包管理器 1>软件包 2>软件生态 3>yum操作 a.查看软件包 b.安装软件 c.卸载软件 4>知识点 vim编辑器 1>基本概念 2>基本操作 3>正常模式命令集 a.模式切换 b.移动光标 c.删除 d.复制 e.替换 f.撤销 g.更改 4>底行模式命令…

网页工具-OTU/ASV表格物种分类汇总工具

AI辅助下开发了个工具&#xff0c;功能如下&#xff0c;分享给大家&#xff1a; 基于Shiny开发的用户友好型网页应用&#xff0c;专为微生物组数据分析设计。该工具能够自动处理OTU/ASV_taxa表格&#xff08;支持XLS/XLSX/TSV/CSV格式&#xff09;&#xff0c;通过调用QIIME1&a…

2025第三届盘古初赛(计算机部分)

前言 比赛的时候时间不对&#xff0c;打一会干一会&#xff0c;导致比赛时候思路都跟不上&#xff0c;赛后简单复现一下&#xff0c;希望大家批批一下 计算机取证 1、分析贾韦码计算机检材&#xff0c;计算机系统Build版本为&#xff1f;【标准格式&#xff1a;19000】 183…

【源码级开发】Qwen3接入MCP,企业级智能体开发实战!

Qwen3接入MCP智能体开发实战&#xff08;上&#xff09; 一、MCP技术与Qwen3原生MCP能力介绍 1.智能体开发核心技术—MCP 1.1 Function calling技术回顾 如何快速开发一款智能体应用&#xff0c;最关键的技术难点就在于如何让大模型高效稳定的接入一些外部工具。而在MCP技术…

基于EFISH-SCB-RK3576/SAIL-RK3576的消防机器人控制器技术方案‌

&#xff08;国产化替代J1900的应急救援智能化解决方案&#xff09; 一、硬件架构设计‌ ‌极端环境防护系统‌ ‌防爆耐高温设计‌&#xff1a; 采用陶瓷纤维复合装甲&#xff08;耐温1200℃持续1小时&#xff09;&#xff0c;通过GB 26784-2023消防设备防爆认证IP68防护等级…

微信小程序:封装request请求、解决请求路径问题

一、创建文件 1、创建请求文件 创建工具类文件request.js,目的是用于发送请求 二、js接口封装 1、写入接口路径 创建一个变量BASE_URL专门存储api请求地址 2、获取全局的token变量 从缓存中取出token的数据 3、执行请求 (1)方法中接收传递的参数 function request(url,…

【技术原理】ELK技术栈的历史沿革与技术演进

一、起源与早期发展&#xff08;2010-2015&#xff09; ELK技术栈的诞生源于互联网时代对海量日志处理的迫切需求。2010年&#xff0c;Elasticsearch作为基于Apache Lucene的分布式搜索引擎问世&#xff0c;其核心能力包括实时全文检索、倒排索引和分片存储机制&#xff0c;填补…

记录算法笔记(2025.5.15)将有序数组转换为二叉搜索树

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确…