欢迎光临
我们一直在努力

Milvus文本检索四种方法对比与实践

Milvus文本检索四种方法对比与实践

    • 一、文本检索概述
      • 1.1 文本检索 vs 向量搜索
      • 1.2 为什么需要全文检索?向量搜索不够吗?
        • 稠密向量搜索(Dense Vector Search)
        • 稀疏向量搜索(Sparse Vector Search / BM25)
        • 实际应用场景对比
        • 为什么 Milvus 同时支持两种?
      • 1.3 四种文本检索方法对比
    • 二、LIKE 操作符:字符模式匹配
      • 2.1 核心特点
      • 2.2 通配符说明
      • 2.3 代码示例
      • 2.4 适用场景
      • 2.5 局限性
    • 三、TEXT_MATCH:关键词匹配
      • 3.1 核心特点
      • 3.2 基础用法
      • 3.3 逻辑组合
      • 3.4 适用场景
    • 四、PHRASE_MATCH:短语匹配
      • 4.1 核心特点
      • 4.2 slop 参数详解
      • 4.3 代码示例
      • 4.4 适用场景
    • 五、全文检索(BM25)
      • 5.1 核心特点
      • 5.2 BM25 算法简介
      • 5.3 你需要做什么?Milvus 会做什么?
        • 数据准备工作分工
        • 实际工作流程示例
        • 关键要点总结
      • 5.4 完整配置流程
        • 步骤 1:创建支持全文搜索的 Schema
        • 步骤 2:定义 BM25 函数
        • 步骤 3:配置稀疏向量索引
        • 步骤 4:创建集合
        • 步骤 5:插入文本数据
        • 步骤 6:执行全文搜索
      • 5.5 完整示例
      • 5.6 适用场景
      • 5.7 与 TEXT_MATCH 的区别
    • 六、方法选择指南
      • 6.1 决策树
      • 6.2 场景对照表
    • 七、实践建议
      • 7.1 性能优化
      • 7.2 字段配置
      • 7.3 常见组合模式
    • 八、常见问题
      • 8.1 TEXT_MATCH 报错
      • 8.2 LIKE 匹配不到中文
      • 8.3 PHRASE_MATCH 匹配不到结果
    • 九、本节知识点总结
    • 十、与其他查询方法的关系

覆盖内容:LIKE、TEXT_MATCH、PHRASE_MATCH、全文检索(BM25)四种文本匹配方法 官方文档:Text Match | Full Text Search


一、文本检索概述

1.1 文本检索 vs 向量搜索

对比项文本检索向量搜索
匹配方式 基于文本内容的字符/词汇匹配 基于向量相似度计算
查询输入 文本字符串或关键词 向量(embedding)
是否涉及向量计算 否(除全文检索可选)
返回结果排序 按主键或相关性评分 按相似度从高到低
典型场景 关键词搜索、精确匹配 语义搜索、推荐系统

1.2 为什么需要全文检索?向量搜索不够吗?

通俗解释:稠密向量 vs 稀疏向量

你的理解是对的:全文检索(BM25)确实使用稀疏向量。让我们用例子说明两者的区别:

稠密向量搜索(Dense Vector Search)

使用:BERT、OpenAI embeddings 等模型生成的向量
特点:每个维度都有值,向量"稠密"

例子:搜索 "苹果手机"
✅ 能匹配到:"iPhone 13"、"iOS 设备"(理解语义)
❌ 但可能匹配到:"Python 3.11 教程"(如果搜索 "Python 3.11")
因为它理解"编程语言"的语义,但对版本号不敏感

优势:理解语义,“苹果手机” = “iPhone” 劣势:对精确关键词(如版本号、型号)不敏感

稀疏向量搜索(Sparse Vector Search / BM25)

使用:基于词频统计的 BM25 算法
特点:只有出现的词对应的维度有值,向量"稀疏"

例子:搜索 "Python 3.11 新特性"
✅ 精确匹配包含 "3.11" 的文档
✅ 对关键词 "Python"、"3.11"、"新特性" 精确匹配
❌ 但不理解 "iPhone" 和 "苹果手机" 是同一个意思

优势:精确关键词匹配,对版本号、型号、专有名词敏感 劣势:不理解语义,“苹果手机” ≠ “iPhone”

实际应用场景对比
场景推荐方法原因
搜索 “机器学习入门教程” 稠密向量 需要理解"入门"、"教程"的语义
搜索 “Python 3.11.5 bug” 稀疏向量(BM25) 版本号必须精确匹配
搜索 “iPhone 14 Pro Max” 稀疏向量(BM25) 型号必须精确
搜索 “如何提高代码质量” 稠密向量 需要理解意图,匹配相关内容
搜索 “ISBN: 978-7-115-12345-6” 稀疏向量(BM25) 精确匹配编号
为什么 Milvus 同时支持两种?

最佳实践:混合搜索(Hybrid Search)

# 同时使用稠密向量和稀疏向量
# 稠密向量:理解语义
# 稀疏向量:精确匹配关键词
# 结果融合:既有语义理解,又有关键词精确度

典型 RAG 应用场景:

  • 用户问:“Python 3.11 有哪些新特性?”
  • 稠密向量:找到语义相关的"Python 新版本介绍"文档
  • 稀疏向量:精确匹配包含 “3.11” 的段落
  • 融合结果:既相关又精确

总结:

  • 全文检索(BM25)不是替代向量搜索,而是互补
  • 稠密向量擅长语义理解,稀疏向量擅长精确匹配
  • 实际应用中常常混合使用,发挥各自优势

1.3 四种文本检索方法对比

方法LIKETEXT_MATCHPHRASE_MATCH全文检索(BM25)
核心特点 字符模式匹配 关键词精确匹配 顺序敏感短语匹配 相关性搜索
匹配逻辑 字符级匹配 OR逻辑(默认) 严格顺序 BM25评分排序
分词处理 无分词 智能分词 智能分词 智能分词
评分机制 无评分 无评分 无评分 BM25评分
配置复杂度
性能 最快
字段要求 无特殊要求 需要 enable_match=True 需要 enable_match=True 需要特殊配置

二、LIKE 操作符:字符模式匹配

2.1 核心特点

  • 最简单的文本匹配方式:基于字符级的模式匹配
  • 无需分词处理:直接进行字符串匹配
  • 性能最好:不涉及复杂的文本分析
  • 无特殊配置要求:任何 VARCHAR 字段都支持

2.2 通配符说明

通配符含义示例匹配结果
% 匹配任意长度字符(包括0个) "Python%" Python、Python编程、Python3
% 匹配任意长度字符 "%编程" Python编程、Java编程
% 匹配任意长度字符 "%机器学习%" 深度学习与机器学习、机器学习实战

2.3 代码示例

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# 1. 前缀匹配
result = client.query(
collection_name="book_collection",
filter='title LIKE "Python%"',
output_fields=["book_id", "title"],
limit=5
)

# 2. 后缀匹配
result = client.query(
collection_name="book_collection",
filter='title LIKE "%编程"',
output_fields=["book_id", "title"],
limit=5
)

# 3. 中缀匹配(包含)
result = client.query(
collection_name="book_collection",
filter='title LIKE "%机器学习%"',
output_fields=["book_id", "title"],
limit=5
)

2.4 适用场景

  • 简单的前缀、后缀、中缀匹配
  • 不需要分词的精确字符串查找
  • 对性能要求高的场景
  • 英文单词或固定格式的匹配

2.5 局限性

  • 不支持智能分词
  • 无法处理同义词
  • 对中文分词不友好
  • 无相关性评分

三、TEXT_MATCH:关键词匹配

3.1 核心特点

  • 智能分词:自动对查询文本进行分词处理
  • OR 逻辑:默认使用 OR 逻辑匹配多个关键词
  • 支持逻辑组合:可与 AND、OR、NOT 组合使用
  • 需要字段配置:字段必须启用 enable_match=True

3.2 基础用法

# 单关键词匹配
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python')",
output_fields=["book_id", "title"],
limit=5
)

# 多关键词匹配(OR逻辑)
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python 机器学习')",
output_fields=["book_id", "title"],
limit=5
)
# 匹配包含 "Python" 或 "机器学习" 的记录

3.3 逻辑组合

# AND 逻辑:同时包含多个关键词
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python') AND TEXT_MATCH(title, '编程')",
output_fields=["book_id", "title"],
limit=5
)

# NOT 逻辑:排除特定关键词
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python') AND NOT TEXT_MATCH(title, 'Web')",
output_fields=["book_id", "title"],
limit=5
)

# 与标量过滤组合
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python') AND rating >= 4.5",
output_fields=["book_id", "title", "rating"],
limit=5
)

3.4 适用场景

  • 关键词检索
  • 需要逻辑组合的复杂查询
  • 中文分词场景
  • 需要与标量过滤结合的查询

四、PHRASE_MATCH:短语匹配

4.1 核心特点

  • 顺序敏感:严格匹配词汇的顺序
  • 精确短语匹配:适合查找特定短语
  • 支持 slop 参数:允许词汇间的灵活性
  • 需要字段配置:字段必须启用 enable_match=True

4.2 slop 参数详解

slop 值含义示例查询匹配结果
0(默认) 完全匹配,词序和位置完全一致 “machine learning” ✓ “machine learning”✗ “machine boosts learning”
1 允许一个词的间隔或位置调整 “machine learning” ✓ “machine learning”✓ “machine boosts learning”
2 允许两个词的间隔或词序颠倒 “machine learning” ✓ “learning machine”✓ “machine quickly boosts learning”

4.3 代码示例

# 精确短语匹配(slop=0,默认)
result = client.query(
collection_name="book_collection",
filter="PHRASE_MATCH(title, 'Python编程')",
output_fields=["book_id", "title"],
limit=5
)

# 带 slop 参数的模糊匹配
result = client.query(
collection_name="book_collection",
filter="PHRASE_MATCH(title, '机器学习', 2)",
output_fields=["book_id", "title"],
limit=5
)

# 与标量过滤组合
result = client.query(
collection_name="book_collection",
filter="PHRASE_MATCH(title, 'Python') AND is_available == True",
output_fields=["book_id", "title", "is_available"],
limit=5
)

4.4 适用场景

  • 需要精确短语匹配的场景
  • 词序重要的查询(如专有名词、固定搭配)
  • 需要控制词汇间距的模糊匹配
  • 引用或特定表达的查找

五、全文检索(BM25)

5.1 核心特点

  • BM25 算法:基于概率检索模型的相关性评分
  • 自动向量化:文本自动转换为稀疏向量,无需手动生成
  • 相关性排序:返回结果按 BM25 评分排序
  • 适合 RAG 场景:特别适用于检索增强生成(RAG)应用

5.2 BM25 算法简介

BM25(Best Matching 25)是一种用于信息检索的排序函数,考虑以下因素:

  • 词频(TF):关键词在文档中出现的频率
  • 逆文档频率(IDF):关键词在整个集合中的稀有程度
  • 文档长度归一化:避免长文档的偏向

5.3 你需要做什么?Milvus 会做什么?

重要说明:稀疏向量是自动生成的!

很多人误以为需要同时手动生成稠密向量和稀疏向量,实际上:

数据准备工作分工
数据类型是否需要你生成说明
原始文本 ✅ 需要 存储文件内容,用于返回结果和生成稀疏向量
稠密向量 ✅ 需要 用 OpenAI/BERT 等模型生成,用于语义搜索
稀疏向量(BM25) ❌ 不需要 Milvus 根据原始文本自动生成(配置 BM25 函数)
实际工作流程示例

# ========== 第一步:读取文件内容 ==========
file_content = "Python 3.11 引入了新的异常组功能,提升了错误处理能力…"

# ========== 第二步:生成稠密向量(你需要做) ==========
import openai

dense_vector = openai.Embedding.create(
input=file_content,
model="text-embedding-ada-002"
)['data'][0]['embedding']

# ========== 第三步:插入 Milvus ==========
# 只需要提供:原始文本 + 稠密向量
# 稀疏向量会自动生成!
client.insert('my_collection', [{
"text": file_content, # 原始文本
"dense_vector": dense_vector, # 你生成的稠密向量
# sparse_vector 不需要提供,Milvus 自动生成!
}])

# ========== 第四步:混合搜索 ==========
query = "Python 3.11 新特性"

# 生成查询的稠密向量(你需要做)
query_dense = openai.Embedding.create(
input=query,
model="text-embedding-ada-002"
)['data'][0]['embedding']

# 稠密向量搜索请求
dense_req = AnnSearchRequest(
data=[query_dense],
anns_field="dense_vector",
param={"metric_type": "COSINE"},
limit=5
)

# 稀疏向量搜索请求
# 注意:直接传文本,Milvus 自动转换为稀疏向量!
sparse_req = AnnSearchRequest(
data=[query], # 直接传查询文本
anns_field="sparse_vector",
param={"metric_type": "BM25"},
limit=5
)

# 执行混合搜索
result = client.hybrid_search(
collection_name='my_collection',
reqs=[dense_req, sparse_req],
ranker=rrf_ranker,
limit=10
)

关键要点总结

✅ 你只需要关心稠密向量的生成(使用 OpenAI、BERT、sentence-transformers 等)

✅ 稀疏向量完全由 Milvus 内部处理(配置 BM25 函数后自动生成)

✅ 搜索时也不需要手动生成稀疏向量(直接传文本,Milvus 自动转换)

❌ 不需要自己实现 BM25 算法

❌ 不需要手动计算词频和 IDF

这就是为什么 Milvus 的全文检索很强大:它把复杂的 BM25 计算封装起来,你只需要提供原始文本即可!

5.4 完整配置流程

步骤 1:创建支持全文搜索的 Schema

需要定义三个必需字段:主键、文本字段、稀疏向量字段

from pymilvus import MilvusClient, DataType, Function, FunctionType

client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)

# 创建 Schema
schema = client.create_schema()

# 1. 主键字段
schema.add_field(
field_name="id",
datatype=DataType.INT64,
is_primary=True,
auto_id=True
)

# 2. 文本字段(启用分词器)
schema.add_field(
field_name="text",
datatype=DataType.VARCHAR,
max_length=1000,
enable_analyzer=True # 必须启用分词器
)

# 3. 稀疏向量字段(存储 BM25 向量)
schema.add_field(
field_name="sparse",
datatype=DataType.SPARSE_FLOAT_VECTOR
)

步骤 2:定义 BM25 函数

BM25 函数将文本自动转换为稀疏向量:

# 定义 BM25 函数
bm25_function = Function(
name="text_bm25_emb", # 函数名称
input_field_names=["text"], # 输入:文本字段
output_field_names=["sparse"], # 输出:稀疏向量字段
function_type=FunctionType.BM25, # 函数类型:BM25
)

# 将函数添加到 Schema
schema.add_function(bm25_function)

步骤 3:配置稀疏向量索引

# 准备索引参数
index_params = client.prepare_index_params()

# 为稀疏向量字段添加索引
index_params.add_index(
field_name="sparse",
index_type="SPARSE_INVERTED_INDEX", # 稀疏倒排索引
metric_type="BM25", # 度量类型:BM25
params={
"inverted_index_algo": "DAAT_MAXSCORE", # 倒排索引算法
"bm25_k1": 1.2, # BM25 参数 k1(词频饱和度)
"bm25_b": 0.75 # BM25 参数 b(长度归一化)
}
)

BM25 参数说明:

  • bm25_k1(默认 1.2):控制词频的饱和度,值越大词频影响越大
  • bm25_b(默认 0.75):控制文档长度归一化程度,0 表示不归一化,1 表示完全归一化
步骤 4:创建集合

# 创建集合
client.create_collection(
collection_name='my_collection',
schema=schema,
index_params=index_params
)

步骤 5:插入文本数据

直接插入原始文本即可,BM25 函数会自动生成稀疏向量:

# 插入文本数据(无需手动生成向量)
client.insert('my_collection', [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
])

步骤 6:执行全文搜索

# 执行全文搜索
search_params = {
"metric_type": "BM25",
"params": {}
}

results = client.search(
collection_name="my_collection",
data=["What is information retrieval?"], # 查询文本
anns_field="sparse", # 搜索稀疏向量字段
search_params=search_params,
limit=5,
output_fields=["text"]
)

# 输出结果
for i, hit in enumerate(results[0]):
print(f"{i+1}. 文本: {hit['entity']['text']}")
print(f" 相关性评分: {hit['distance']:.4f}\\n")

5.5 完整示例

from pymilvus import MilvusClient, DataType, Function, FunctionType

# 1. 连接 Milvus
client = MilvusClient(uri="http://localhost:19530")

# 2. 创建 Schema
schema = client.create_schema()
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)

# 3. 添加 BM25 函数
bm25_function = Function(
name="text_bm25_emb",
input_field_names=["text"],
output_field_names=["sparse"],
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)

# 4. 配置索引
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={"bm25_k1": 1.2, "bm25_b": 0.75}
)

# 5. 创建集合
client.create_collection(
collection_name='full_text_demo',
schema=schema,
index_params=index_params
)

# 6. 插入数据
client.insert('full_text_demo', [
{'text': 'Artificial intelligence is transforming the world.'},
{'text': 'Machine learning is a subset of artificial intelligence.'},
{'text': 'Deep learning uses neural networks for complex tasks.'},
])

# 7. 执行搜索
results = client.search(
collection_name="full_text_demo",
data=["What is artificial intelligence?"],
anns_field="sparse",
search_params={"metric_type": "BM25"},
limit=3,
output_fields=["text"]
)

# 8. 输出结果
for i, hit in enumerate(results[0]):
print(f"{i+1}. {hit['entity']['text']} (评分: {hit['distance']:.4f})")

5.6 适用场景

  • 复杂的文本内容搜索
  • 需要相关性排序的场景
  • 大规模文档检索
  • 检索增强生成(RAG)应用
  • 搜索引擎类应用

5.7 与 TEXT_MATCH 的区别

对比项TEXT_MATCH全文检索(BM25)
返回结果 无评分排序 按 BM25 评分排序
向量化 不涉及 自动生成稀疏向量
配置复杂度
相关性评分 有(BM25)
适用场景 简单关键词匹配 复杂文本检索、RAG

六、方法选择指南

6.1 决策树

需要文本检索?
├── 简单字符匹配?
│ └── 是 → 使用 LIKE(性能最好)
└── 否 → 需要分词
├── 精确短语匹配?
│ └── 是 → 使用 PHRASE_MATCH
├── 关键词检索?
│ └── 是 → 使用 TEXT_MATCH
└── 需要相关性排序?
└── 是 → 使用全文检索(BM25)

6.2 场景对照表

场景推荐方法理由
搜索以"Python"开头的书名 LIKE 简单前缀匹配,性能最好
搜索包含"机器学习"的书名 TEXT_MATCH 支持中文分词
搜索"深度学习实战"这个短语 PHRASE_MATCH 词序敏感
搜索与"AI技术"最相关的文章 全文检索 需要相关性评分
搜索包含"Python"但不含"Web"的书 TEXT_MATCH 支持逻辑组合

七、实践建议

7.1 性能优化

# 1. 优先使用 LIKE(性能最好)
# 适合:简单的前缀/后缀匹配
filter='title LIKE "Python%"'

# 2. TEXT_MATCH 适合大多数场景
# 适合:关键词检索,支持逻辑组合
filter="TEXT_MATCH(title, 'Python') AND rating >= 4.0"

# 3. PHRASE_MATCH 用于精确匹配
# 适合:需要保持词序的场景
filter="PHRASE_MATCH(title, 'Python编程')"

# 4. 全文检索用于复杂场景
# 适合:需要相关性排序的大规模文本搜索

7.2 字段配置

使用 TEXT_MATCH 或 PHRASE_MATCH 前,需要配置字段:

from pymilvus import MilvusClient, DataType

schema = client.create_schema()

# 添加支持文本匹配的字段
schema.add_field(
field_name="title",
datatype=DataType.VARCHAR,
max_length=500,
enable_match=True, # 启用文本匹配
enable_analyzer=True # 启用分词器(可选)
)

7.3 常见组合模式

# 模式1:文本匹配 + 标量过滤
filter="TEXT_MATCH(title, 'Python') AND rating >= 4.5 AND is_available == True"

# 模式2:多字段文本匹配
filter="TEXT_MATCH(title, 'Python') OR TEXT_MATCH(description, 'Python')"

# 模式3:短语匹配 + 排除
filter="PHRASE_MATCH(title, '机器学习') AND NOT TEXT_MATCH(title, '入门')"


八、常见问题

8.1 TEXT_MATCH 报错

错误信息: field 'title' doesn't support text match

原因: 字段未启用 enable_match=True

解决方法:

# 创建集合时配置字段
schema.add_field(
field_name="title",
datatype=DataType.VARCHAR,
max_length=500,
enable_analyzer=True, # 启用分词器
enable_match=True # 必须启用
)

8.2 LIKE 匹配不到中文

原因: LIKE 是字符级匹配,中文分词可能导致匹配失败

解决方法:

# 方案1:使用 TEXT_MATCH(推荐)
filter="TEXT_MATCH(title, '机器学习')"

# 方案2:使用完整字符串
filter='title LIKE "%机器学习%"'

# 方案3:配置分词器方法
analyzer_params = {
"type": "english"
}
schema.add_field(
field_name="title",
datatype=DataType.VARCHAR,
max_length=500,
enable_analyzer=True, # 启用分词器
analyzer_params = analyzer_params,
enable_match=True # 必须启用
)

8.3 PHRASE_MATCH 匹配不到结果

原因: 词序严格,可能因为分词或词序问题

解决方法:

# 增加 slop 参数,允许词汇间隔
filter="PHRASE_MATCH(title, '机器学习', 2)"

# 或改用 TEXT_MATCH
filter="TEXT_MATCH(title, '机器学习')"


九、本节知识点总结

方法关键参数适用场景
LIKE % 通配符 简单字符模式匹配
TEXT_MATCH 关键词字符串 关键词检索,逻辑组合
PHRASE_MATCH 短语字符串,slop 精确短语匹配
全文检索 BM25 配置 复杂文本搜索,相关性排序

核心要点:

  • LIKE 最简单,性能最好,但功能有限
  • TEXT_MATCH 支持分词和逻辑组合,适合大多数场景
  • PHRASE_MATCH 适合需要保持词序的精确匹配
  • 全文检索功能最强,但配置复杂

十、与其他查询方法的关系

文本检索方法可以与之前学习的查询方法结合使用:

# 与 Query 结合
result = client.query(
collection_name="book_collection",
filter="TEXT_MATCH(title, 'Python') AND rating >= 4.5",
output_fields=["book_id", "title", "rating"],
limit=10
)

# 与 Search 结合(混合搜索)
result = client.search(
collection_name="book_collection",
data=[query_vector],
anns_field="content_vector",
filter="TEXT_MATCH(title, 'Python')", # 文本过滤
limit=5
)

赞(0)
未经允许不得转载:171主机测评 » Milvus文本检索四种方法对比与实践
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址