混合检索
更新时间:2025-01-07
什么是混合检索
混合检索是一种结合了全文检索、向量检索优势的技术,实现了精确匹配与语义理解的互补,旨在提升信息检索的准确性和全面性。
混合检索的基本原理
向量检索能够捕捉文本深层的语义,对模糊查询与近义表达具有很强的容错性,同时适用于多模态检索场景,如文搜图、图搜图等,向量检索技术在当今数据检索和信息处理领域占据核心地位,特别是在大规模非结构化数据和多模态数据检索中,已成为不可或缺的关键技术。而向量检索仍存在其局限性,其往往在需精确检索的场景下,表现不佳,如检索一个特定的ID、一个人的名字,同时向量往往都是高维浮点数字,其透明性及可解释性对人类有天然的障碍,检索效果不佳时,开发人员往往难以调优。
全文检索非常适合精确匹配的场景,其核心往往是倒排索引结构,能快速从海量文档中检索包含特定关键字或短语的文档,同时其检索结果具有更强的可解释性,用户可直接看到匹配的关键词和文档片段。
混合检索的优势
- 更高的检索召回精度:通过多路召回,既保证基于语义的查询结果,也能保证企业场景必备的精确检索,是支撑企业级RAG的关键技术。
- 更丰富的适用场景,处理多样化查询: 混合检索在处理多样化的查询方面表现出色,提供与用户意图一致的全面和适应性结果
- 灵活、可自定义: 用户可自定义全文检索召回结果、向量检索召回结果在最终结果的权重,为变化的检索场景选择更合适的检索手段
混合检索使用示例
下面我们通过例子展示如何使用百度VectorDB的混合检索功能。
1、创建带倒排索引与向量索引的表
import time
import json
import random
import pymochow
import logging
from pymochow.configuration import Configuration
from pymochow.auth.bce_credentials import BceCredentials
from pymochow.exception import ClientError, ServerError
from pymochow.model.schema import (
Schema,
Field,
SecondaryIndex,
FilteringIndex,
VectorIndex,
InvertedIndex,
InvertedIndexParams,
HNSWParams
)
from pymochow.model.enum import (
FieldType, ElementType, IndexType, InvertedIndexAnalyzer, InvertedIndexParseMode, MetricType, ServerErrCode,
InvertedIndexFieldAttribute
)
from pymochow.model.enum import TableState, IndexState
from pymochow.model.table import (
Partition,
Row,
FloatVector,
BM25SearchRequest,
HybridSearchRequest,
VectorSearchConfig,
VectorTopkSearchRequest
)
logging.basicConfig(filename='demo.log', level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
if __name__ == "__main__":
account = 'root'
api_key = 'xxxxxxxx'
endpoint = 'http://xx.xx.xxx.xxx:5287' # endpoint from Baidu VectoDB console
config = Configuration(credentials=BceCredentials(account, api_key),
endpoint=endpoint)
client = pymochow.MochowClient(config)
"""create database"""
database = 'test_db'
table_name = 'test_hybrid_search_table'
db = client.create_database(database)
"""create table"""
fields = []
fields.append(Field("docID", FieldType.STRING, primary_key=True,
partition_key=True, auto_increment=False, not_null=True))
fields.append(Field("chunkID", FieldType.STRING, primary_key=True, not_null=True))
fields.append(Field("title", FieldType.TEXT, not_null=True))
fields.append(Field("content", FieldType.TEXT, not_null=True))
fields.append(Field("size", FieldType.UINT64, not_null=True))
fields.append(Field("meta", FieldType.STRING, not_null=True))
fields.append(Field("vector", FieldType.FLOAT_VECTOR, not_null=True, dimension=1024))
indexes = []
indexes.append(InvertedIndex(index_name="title_content_inverted_index",
fields=["title", "content"],
field_attributes=[InvertedIndexFieldAttribute.NOT_ANALYZED, InvertedIndexFieldAttribute.ANALYZED],
params=InvertedIndexParams(analyzer=InvertedIndexAnalyzer.CHINESE_ANALYZER,
parse_mode=InvertedIndexParseMode.COARSE_MODE)))
indexes.append(VectorIndex(index_name="vector_idx", index_type=IndexType.HNSW,
field="vector", metric_type=MetricType.L2,
params=HNSWParams(m=32, efconstruction=200)))
db.create_table(
table_name=table_name,
replication=3,
partition=Partition(partition_num=3),
schema=Schema(fields=fields, indexes=indexes)
)
while True:
time.sleep(2)
table = db.describe_table(table_name)
if table.state == TableState.NORMAL:
break
table = db.table(table_name)
通过上述代码,例子新建了一张test_hybrid_search_table表,同时为表新建了2个索引: 基于title、content这2列的倒排索引、基于vector列的HNSW向量索引。
2、灌入数据
"""insert some rows into table"""
rows = [
Row(docID='doc_589412-897452-536331',
chunkID='chunk_0000',
title='科比.布莱恩特',
content='科比·布莱恩特(Kobe Bryant),绰号“黑曼巴”,是NBA历史上最伟大的球员之一。他于1978年出生于美国宾夕法尼亚州,1996年直接从高中进入NBA,
加入洛杉矶湖人队,开启了传奇的20年职业生涯',
size=100,
meta='{"createAt" : "2024-12-25"}',
vector=[-0.0410689041018486, 0.004214739892631769, -0.024814443662762642, 0.009914507158100605, -0.01707501709461212, 0.01465007197111845,...........]),
Row(docID='doc_589412-897452-536331',
chunkID='chunk_0001',
title='科比.布莱恩特',
content='科比以极强的得分能力和坚韧的意志著称,职业生涯五次夺得NBA总冠军,两次荣膺总决赛MVP,并18次入选全明星赛。他职业生涯总得分超过33000分>,位列历史前列',
size=100,
meta='{"createAt" : "2024-12-25"}',
vector=[...........]),
Row(docID='doc_589412-897452-536331',
chunkID='chunk_0002',
title='科比.布莱恩特',
content='科比的“曼巴精神”象征着永不放弃和持续精进,不仅影响着篮球界,也激励着全球无数人。2016年退役后,他在商业和文化领域继续创造价值',
size=80,
meta='{"createAt" : "2024-12-25"}',
vector=[...........]),
Row(docID='doc_589412-897452-536331',
chunkID='chunk_0003',
title='科比.布莱恩特',
content='2020年,科比在直升机事故中不幸去世,震惊世界。他的精神与影响力仍在延续,激励着新一代球员和球迷',
size=70,
meta='{"createAt" : "2024-12-25"}',
vector=[...........]),
Row(docID='doc_589412-897452-536332',
chunkID='chunk_0000',
title='洛杉矶.湖人队',
content='洛杉矶湖人队(Los Angeles Lakers)是NBA最具传奇色彩的球队之一,成立于1947年,总部位于加利福尼亚州洛杉矶。湖人队历史悠久,共赢得17次NBA总冠军,与波士顿凯尔特人并列联盟第一',
size=120,
meta='{"createAt" : "2024-12-26"}',
vector=[.......]),
Row(docID='doc_589412-897452-536332',
chunkID='chunk_0001',
title='洛杉矶.湖人队',
content='湖人队以明星球员云集著称,埃尔文·约翰逊(魔术师)、卡里姆·阿卜杜尔-贾巴尔、科比·布莱恩特和勒布朗·詹姆斯等都是队史代表人物。湖人队的“Showtime”时代凭借快速攻防和华丽球风席卷联盟,而科比时代的五冠成就进一步巩固了球队的地位',
size=200,
meta='{"createAt" : "2024-12-26"}',
vector=[.......]),
Row(docID='doc_589412-897452-536332',
chunkID='chunk_0002',
title='洛杉矶.湖人队',
content='作为NBA最受欢迎的球队之一,湖人队不仅在竞技层面表现出色,也在全球拥有庞大的粉丝群体。湖人队象征着辉煌和荣耀,持续书写着属于自己的篮>球传奇。',
size=160,
meta='{"createAt" : "2024-12-26"}',
vector=[........])
]
table.upsert(rows=rows)
3、重建向量索引
"""rebuild vector index"""
table.rebuild_index("vector_idx")
while True:
time.sleep(2)
index = table.describe_index("vector_idx")
if index.state == IndexState.NORMAL:
break
4、执行混合检索
4.1 不带过滤条件的混合检索
config = VectorSearchConfig(ef=200)
vector_request = VectorTopkSearchRequest(vector_field="vector",
vector=FloatVector([0.011137483641505241, -0.02655072696506977, -0.015822893008589745, -0.00819395761936903, -0.024098902940750122, -0.021009085699915886, .........]),
limit=None,
config=config)
bm25_request = BM25SearchRequest(index_name="title_content_inverted_index",
search_text="title:科比.布莱恩特")
hybrid_request = HybridSearchRequest(vector_request=vector_request,
vector_weight=0.2,
bm25_request=bm25_request,
bm25_weight=0.8,
limit=5)
res = table.hybrid_search(request=hybrid_request)
logger.debug("hybrid search res: {}".format(res))
这个例子中,我们在Table中检索与"科比.布莱恩特"相关的数据,因检索的是特定关键字,因此分别设置全文检索、向量检索的权重为0.8和0.2,检索输出如下:
{metadata:{content__length:u'2141',content__type:u'application/json',request_id:u'5b4db957-0f3f-4783-aa99-ecfc082375bf'},
rows:[
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0000', 'title': '科比.布莱恩特', 'content': '科比·布莱恩特(Kobe Bryant),绰号“黑曼巴”,是NBA历史上最伟大的球员之一。他于1978年出生于美国宾夕法尼亚州,1996年直接从高中进入NBA,加入洛杉矶湖人队,开启了传奇的20年职业生涯', 'size': 100, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.8500000238418579, 'distance': 0.00540169607847929},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0001', 'title': '科比.布莱恩特', 'content': '科比以极强的得分能力和坚韧的意志著称,职业生涯五次夺得NBA总冠军,两次荣膺总决赛MVP,并18次入选全明星赛。他职业生涯总得分超过33000分,位列历史前列', 'size': 100, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.6000000238418579, 'distance': 0.0036995408590883017},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0002', 'title': '科比.布莱恩特', 'content': '科比的“曼巴精神”象征着永不放弃和持续精进,不仅影响着篮球界,也激励着全球无数人。2016年退役后,他在商业和文化领域继续创造价值', 'size': 80, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.36666667461395264, 'distance': 0.004318084102123976},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0003', 'title': '科比.布莱恩特', 'content': '2020年,科比在直升机事故中不幸去世,震惊世界。他的精神与影响力仍在延续,激励着新一代球员和球迷', 'size': 70, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.2666666805744171, 'distance': 0.005043650511652231},
{'row': {'docID': 'doc_589412-897452-536332', 'chunkID': 'chunk_0002', 'title': '洛杉矶.湖人队', 'content': '作为NBA最受欢迎的球队之一,湖人队不仅在竞技层面表现出色,也在全球拥有庞大的粉丝群体。湖人队象征着辉煌和荣耀,持续书写着属于自己的篮球传奇。', 'size': 160, 'meta': '{"createAt" : "2024-12-26"}'}, 'score': 0.20000000298023224, 'distance': 0.0020693386904895306}],
code:0,msg:u'Success'}
4.2 带过滤条件的混合检索
config = VectorSearchConfig(ef=200)
vector_request = VectorTopkSearchRequest(vector_field="vector",
vector=FloatVector([0.010952972806990147, -0.01763264834880829, -0.007045084144920111, -0.017448166385293007, -0.0012776943622156978, -0.002704191952943802, ........]),
limit=None,
config=config)
bm25_request = BM25SearchRequest(index_name="title_content_inverted_index",
search_text="content:科比.布莱恩特和他所效忠的洛杉矶湖人队")
hybrid_request = HybridSearchRequest(vector_request=vector_request,
vector_weight=0.6,
bm25_request=bm25_request,
bm25_weight=0.4,
filter="size <= 160",
limit=5)
res = table.hybrid_search(request=hybrid_request)
logger.debug("hybrid search res: {}".format(res))
在这个例子里,适当提高了向量检索结果在最终结果的权重,同时兼顾关键词的精确匹配,最终检索结果输出如下:
{metadata:{content__length:u'2242',content__type:u'application/json',request_id:u'dc541bc9-ce41-46ac-9c8a-1b0c74d6ad8a'},
rows:[
{'row': {'docID': 'doc_589412-897452-536332', 'chunkID': 'chunk_0002', 'title': '洛杉矶.湖人队', 'content': '作为NBA最受欢迎的球队之一,湖人队不仅在竞技层面表现出色,也在全球拥有庞大的粉丝群体。湖人队象征着辉煌和荣耀,持续书写着属于自己的篮球传奇。', 'size': 160, 'meta': '{"createAt" : "2024-12-26"}'}, 'score': 0.800000011920929, 'distance': 0.0007152445032261312},
{'row': {'docID': 'doc_589412-897452-536332', 'chunkID': 'chunk_0000', 'title': '洛杉矶.湖人队', 'content': '洛杉矶湖人队(Los Angeles Lakers)是NBA最具传奇色彩的球队之一,成立于1947年,总部位于加利福尼亚州洛杉矶。湖人队历史悠久,共赢得17次NBA总冠军,与波士顿凯尔特人并列联盟第一', 'size': 120, 'meta': '{"createAt" : "2024-12-26"}'}, 'score': 0.7000000476837158, 'distance': 0.0008071861229836941},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0001', 'title': '科比.布莱恩特', 'content': '科比以极强的得分能力和坚韧的意志著称,职业生涯五次夺得NBA总冠军,两次荣膺总决赛MVP,并18次入选全明星赛。他职业生涯总得分超过33000分,位列历史前列', 'size': 100, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.7000000476837158, 'distance': 0.0011578099802136421},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0000', 'title': '科比.布莱恩特', 'content': '科比·布莱恩特(Kobe Bryant),绰号“黑曼巴”,是NBA历史上最伟大的球员之一。他于1978年出生于美国宾夕法尼亚州,1996年直接从高中进入NBA,加入洛杉矶湖人队,开启了传奇的20年职业生涯', 'size': 100, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.550000011920929, 'distance': 0.004798776004463434},
{'row': {'docID': 'doc_589412-897452-536331', 'chunkID': 'chunk_0002', 'title': '科比.布莱恩特', 'content': '科比的“曼巴精神”象征着永不放弃和持续精进,不仅影响着篮球界,也激励着全球无数人。2016年退役后,他在商业和文化领域继续创造价值', 'size': 80, 'meta': '{"createAt" : "2024-12-25"}'}, 'score': 0.4333333373069763, 'distance': 0.0018439505947753787}],
code:0,msg:u'Success'}