返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

全文检索与向量检索选哪个?

[复制链接]
链载Ai 显示全部楼层 发表于 昨天 10:03 |阅读模式 打印 上一主题 下一主题


ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">今天探讨的便是RAG开发关于全文搜索,以及将全文检索和向量检索整合在一起的混合搜索(Hybrid Search)。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1.2em;font-weight: bold;display: table;margin: 4em auto 2em;padding-right: 0.2em;padding-left: 0.2em;background: rgb(15, 76, 129);color: rgb(255, 255, 255);">全文搜索(BM25) 代码实现

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;margin: 10px 8px;">pipinstallllama-index-retrievers-bm25

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">为了便于在DuckDB里重现全文索引,这里使用DuckDB来存储

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;margin: 10px 8px;">fromllama_index.coreimportVectorStoreIndex,SimpleDirectoryReader,Settings
fromllama_index.llms.ollamaimportOllama
fromllama_index.core.node_parserimportSentenceSplitter
fromllama_index.retrievers.bm25importBM25Retriever


#这里仍然使用Ollama,你可以根据自己的情况,选择合适的LLM和embeddingmodel
Settings.llm=Ollama(model="wizardlm2:7b-q5_K_M",request_timeout=300.0)

fromllama_index.embeddings.ollamaimportOllamaEmbedding
Settings.embed_model=OllamaEmbedding(model_name="snowflake-arctic-embed:latest")
embed_dim=len(Settings.embed_model.get_query_embedding('hello'))

#索引
documents=SimpleDirectoryReader("./data/paul_graham").load_data()
splitter=SentenceSplitter(chunk_size=1024)#为了bm25需要,可以适当改小该值
nodes=splitter.get_nodes_from_documents(documents)

vector_store=DuckDBVectorStore(embed_dim=embed_dim,
database_name="paul.duck",
persist_dir="duckdb")
storage_context=StorageContext.from_defaults(vector_store=vector_store)
storage_context.docstore.add_documents(nodes)

#vectorretriever
vector_retriever=index.as_retriever(similarity_top_k=5)

#BM25Retriever
bm25_retriever=BM25Retriever.from_defaults(nodes=nodes,similarity_top_k=5)

query="WhathappenedatViawebandInterleaf?"

fromllama_index.core.response.notebook_utilsimportdisplay_source_node

#willretrievecontextfromspecificcompanies
nodes_bm25=bm25_retriever.retrieve(query)
fornodeinnodes_bm25:
display_source_node(node)

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1.2em;font-weight: bold;display: table;margin: 4em auto 2em;padding-right: 0.2em;padding-left: 0.2em;background: rgb(15, 76, 129);color: rgb(255, 255, 255);">使用DuckDB的全文索引来重现BM25Retriever

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;margin: 10px 8px;">
importduckdb
conn=duckdb.connect('duckdb/paul.duck')
conn.sql('select*fromdocumentslimit5').df()

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;margin: 10px 8px;">conn.sql('installfts')#第一次需要安装全文索引插件
conn.sql('loadfts')#加载全文索引插件

#创建全文索引

conn.sql("RAGMAcreate_fts_index('documents','node_id','text');")
#重现bm25_retriever.retrieve(query)
conn.sql(f"""
SELECT
fts_main_documents.match_bm25(node_id,'{query}')ASscore,
node_id,text
FROMdocuments
WHEREscoreISNOTNULL
ORDERBYscoreDESC
LIMIT5
""").df()

对比bm25_retriever.retrieve(query)的实现, 结果略有不同, 因为使用的bm25引擎不同, bm25_retriever 使用的是rank_bm25[1]

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">关于DuckDB 全文索引插件的使用,详见,https://duckdb.org/docs/extensions/full_text_search

混合搜索(Hybrid Search)

接下来重现全文检索与向量检索选哪个?提到的混合搜索

相对得分融合

relativeScoreFusion 通过分别归一化向量搜索和关键词搜索输出的指标来确定每个对象的得分。最高值设为1,最低值设为0,其他值根据这个尺度介于两者之间。因此,总得分是通过归一化的向量相似度和归一化的BM25得分的加权和来计算的。

fromllama_index.core.retrieversimportQueryFusionRetriever

retriever_relative_score=QueryFusionRetriever(
[vector_retriever,bm25_retriever],
retriever_weights=[0.6,0.4],
similarity_top_k=10,
num_queries=1,#setthisto1todisablequerygeneration
mode="relative_score",
use_async=True,
verbose=True,
)
nodes_with_scores=retriever.retrieve(
"WhathappenedatInterleafeandViaweb?"
)
fornodeinnodes_with_scores:
print(f"Score:{node.score:.2f}-{node.text[:100]}...\n-----")


fromllama_index.core.query_engineimportRetrieverQueryEngine

query_engine=RetrieverQueryEngine.from_args(retriever_relative_score)
response=query_engine.query("WhathappenedatInterleafeandViaweb?")
display_response(response)

分布的得分融合

相对得分融合(Relative Score Fusion)的一个变体,基于分布的得分融合(Distribution-Based Score Fusion)以稍微不同的方式对得分进行缩放——基于每个结果集的得分的平均值和标准差。

fromllama_index.core.retrieversimportQueryFusionRetriever

retriever=QueryFusionRetriever(
[vector_retriever,bm25_retriever],
retriever_weights=[0.6,0.4],
similarity_top_k=10,
num_queries=1,#setthisto1todisablequerygeneration
mode="dist_based_score",
use_async=True,
verbose=True,
)

nodes_with_scores=retriever.retrieve(
"WhathappenedatInterleafeandViaweb?"
)

fornodeinnodes_with_scores:
print(f"Score:{node.score:.2f}-{node.text[:100]}...\n-----")

fromllama_index.core.query_engineimportRetrieverQueryEngine

query_engine=RetrieverQueryEngine.from_args(retriever_relative_score)
response=query_engine.query("WhathappenedatInterleafeandViaweb?")
display_response(response)

结论

到现在,我们不仅仅可以进行向量搜索,可以进行全文搜索,还可以使用两种方法进行混合搜索了。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ