【原创】使用ElasticSearch存储向量实现大模型RAG

一、概述

检索增强生成(Retrieval-Augmented Generation,RAG)已成为大型语言模型(LLM)应用的重要架构,通过结合外部知识库来增强模型的回答能力,特别是在处理专业领域知识、最新信息或企业私有数据时。本报告将系统梳理使用 Elasticsearch(ES)作为向量数据库实现 RAG 系统的优缺点,与传统向量数据库及其他存储解决方案的对比,以及基于 Deepseek V3 和 Qwen2.5 大模型的实现方案。

二、Elasticsearch 作为 RAG 向量数据库的优缺点分析

1. 优点

低门槛的独立技术栈
  • 一站式解决方案:ES 能够一站式完成向量生成、存储、索引和检索,通过配置即可实现大部分功能
  • 成熟的生态系统:作为成熟的搜索引擎,拥有丰富的文档、社区支持和工具集
  • 简化的部署和维护:相比需要部署多个组件的解决方案,ES 可以作为单一系统处理所有 RAG 相关任务
高性能和扩展性
  • 分布式架构:支持百万级 QPS 和千亿级数据量
  • 灵活的扩展能力:可以通过添加节点水平扩展,满足不断增长的数据需求
  • 高可用性:内置的分片和复制机制确保系统的可靠性
混合检索能力
  • 文本与向量的结合:同时支持传统的全文检索和向量相似性搜索
  • 提高检索精度:混合检索策略能够显著提升搜索结果的准确性和多样性
  • 处理短查询优势:对于短查询,传统关键词搜索可以弥补纯向量搜索的不足
丰富的数据处理能力
  • 强大的文本分析:内置多种语言分析器,支持分词、同义词、停用词等处理
  • 结构化和非结构化数据支持:可以同时处理结构化字段和非结构化文本
  • 聚合和分析功能:提供丰富的聚合功能,可用于数据分析和可视化
多种相似度计算算法支持
  • 余弦相似度(Cosine Similarity):适用于文本语义搜索,不受向量长度影响
  • 点积(Dot Product):适用于推荐系统,考虑向量长度和方向
  • 欧几里得距离(L2 Norm):适用于图像特征、地理位置等场景
  • 脚本评分(Script Score):支持自定义脚本实现更复杂的相似度计算
  • 函数评分(Function Score):允许结合衰减函数、字段值等因素调整相似度分数
与大模型的无缝集成
  • 简化的集成流程:提供 API 和工具,便于与各种大模型集成
  • 灵活的检索配置:可以根据不同大模型的特点调整检索策略

2. 不足

向量搜索性能限制
  • 非专用架构:ES 的架构不是专为向量搜索设计的,在大规模向量搜索时性能可能不如专用向量数据库
  • 延迟问题:在大规模向量集上,搜索延迟通常为毫秒级,而专用向量数据库可达微秒级
  • 资源消耗较高:向量操作可能需要更多的内存和计算资源
向量功能相对有限
  • 算法支持有限:支持的向量索引和搜索算法相对较少,主要是 HNSW
  • 缺乏专业优化:缺少针对向量操作的专门优化,如 GPU 加速
  • 向量维度限制:在处理超高维向量时可能存在效率问题
学习和配置复杂性
  • 配置复杂:需要正确配置索引映射、分片策略等
  • 调优难度:优化 ES 性能需要专业知识和经验
  • 维护成本:需要定期维护和监控集群状态
存储效率问题
  • 存储开销:存储向量数据可能需要更多空间
  • 索引大小:包含向量的索引通常比纯文本索引大得多

三、Elasticsearch 向量存储与检索原理

1. 向量数据存储原理

Elasticsearch 使用 dense_vector 字段类型来存储向量数据,其工作原理如下:

基本存储结构
  • 文档结构:向量被存储为文档的一个字段,与其他字段(如文本、数字等)一起构成完整的文档。
  • 向量表示:向量以浮点数数组的形式存储,每个数组元素对应向量的一个维度。
  • 索引映射:通过索引映射定义向量字段的属性,包括维度大小、索引方式和相似度计算方法。

存储过程简述
  1. 1. 向量生成:通过嵌入模型将文本、图像等内容转换为固定维度的向量。

  2. 2. 文档创建:创建包含向量字段的文档,将向量数据与其他元数据一起存储。

  3. 3. 分片分配:ES 将文档分配到不同的分片中,每个分片可以位于不同的节点上。

  4. 4. 磁盘存储:向量数据最终以 Lucene 索引格式存储在磁盘上,同时部分热数据会缓存在内存中。

2. 向量检索原理

Elasticsearch 主要使用 HNSW(Hierarchical Navigable Small World)算法进行向量检索,这是一种近似最近邻(ANN)搜索算法:

HNSW 算法简介
  • 多层图结构:HNSW 构建一个多层的图结构,顶层包含少量节点,底层包含所有节点。
  • 导航原理:搜索从顶层开始,通过"贪心"策略快速找到大致方向,然后在下层进行更精细的搜索。
  • 近似搜索:通过牺牲一定的精确度来换取显著的性能提升。

检索过程
  1. 1. 查询向量生成:将用户查询转换为向量表示。

  2. 2. 分片搜索:在每个相关分片上执行向量搜索。

  3. 3. 相似度计算:根据配置的相似度方法(余弦、点积或 L2 范数)计算查询向量与索引向量的相似度。

  4. 4. 结果合并:将各分片的搜索结果合并,并按相似度排序。

  5. 5. 返回结果:返回最相似的文档作为搜索结果。

性能优化参数
  • ef_construction:构建索引时的精度参数,值越大索引质量越高但构建越慢。
  • ef_search:搜索时的精度参数,值越大搜索结果越精确但速度越慢。
  • m:每个节点的最大连接数,影响图的连通性和搜索效率。

3. 多模态向量存储支持

Elasticsearch 不仅可以存储文本向量,还可以存储来自图片、音频和视频等多模态数据的向量表示:

图像向量存储
  • 实现原理:使用图像嵌入模型(如 ResNet、ViT 等)将图像转换为向量表示。
  • 存储方式:与文本向量相同,使用 dense_vector 字段存储图像向量。
  • 应用场景:图像相似度搜索、以图搜图、视觉内容检索。

音频向量存储
  • 实现原理:使用音频嵌入模型(如 Wav2Vec、CLAP 等)将音频转换为向量表示。
  • 存储方式:同样使用 dense_vector 字段,维度根据音频嵌入模型而定。
  • 应用场景:音乐推荐、语音搜索、音频内容分类。

视频向量存储
  • 实现原理:可以通过两种方式处理:
    1. 将视频分解为关键帧,然后使用图像嵌入模型处理每个关键帧。
    2. 使用专门的视频嵌入模型(如 Video Transformers)直接生成视频向量。
  • 存储方式:可以存储单个视频的整体向量,或者存储多个关键帧的向量序列。
  • 应用场景:视频内容搜索、相似视频推荐、视频分类。

多模态向量存储的简单示例
# 图像向量存储示例
from PIL import Image
from transformers import AutoFeatureExtractor, AutoModel
import torch# 加载图像嵌入模型
image_model = AutoModel.from_pretrained("openai/clip-vit-base-patch32")
feature_extractor = AutoFeatureExtractor.from_pretrained("openai/clip-vit-base-patch32")# 处理图像
image = Image.open("example.jpg")
inputs = feature_extractor(images=image, return_tensors="pt")
with torch.no_grad():image_features = image_model.get_image_features(**inputs)
image_vector = image_features[0].tolist()# 存储到Elasticsearch
doc = {"title": "示例图片","description": "这是一张示例图片","image_path": "example.jpg","image_vector": image_vector  # 使用dense_vector字段存储
}es.index(index="image-vectors", document=doc)

四、Elasticsearch 与其他向量存储解决方案的对比

1. 各向量存储解决方案综合对比

特性ElasticsearchPGVector (PostgreSQL)Redis VectorMongoDB AtlasFAISSMilvusPineconeQdrantChroma
架构类型分布式搜索引擎关系型数据库扩展内存数据库扩展文档数据库扩展库/嵌入式分布式向量数据库托管向量数据库向量数据库嵌入式向量数据库
部署模式自托管/云服务自托管/云服务自托管/云服务自托管/云服务嵌入式自托管/云服务仅云服务自托管/云服务嵌入式/自托管
向量索引算法HNSWHNSW, IVFHNSWHNSWHNSW, IVF, PQ 等多种HNSW, IVF, FLAT 等多种HNSW 变体HNSWHNSW
查询性能毫秒级毫秒级亚毫秒级毫秒级微秒-毫秒级微秒-毫秒级毫秒级毫秒级毫秒级
扩展性优秀有限有限优秀有限优秀优秀良好有限
混合查询原生支持支持 SQL+向量有限支持支持文档+向量不支持支持有限支持支持支持
元数据过滤强大强大(SQL)有限强大(文档查询)有限支持支持支持支持
GPU 加速不支持不支持不支持不支持支持支持内部支持不支持不支持
存储容量TB-PB 级TB 级GB-TB 级TB-PB 级受内存限制TB 级TB 级TB 级GB-TB 级
全文搜索优秀基础良好基础不支持有限不支持有限有限
相似度算法余弦、点积、L2 范数余弦、L2 范数余弦、L2 范数余弦、点积、欧几里得多种(余弦、内积、L2 等)多种(余弦、内积、L2 等)余弦、点积余弦、点积、欧几里得余弦
事务支持有限完整 ACID有限文档级事务不支持有限不支持不支持不支持
易用性中等高(SQL 熟悉度)高(MongoDB 用户)复杂中等简单简单简单
维护成本中等中等低(嵌入式)低(托管)
社区支持强大强大强大强大活跃活跃有限活跃活跃
成本开源,自托管开源,自托管开源+商业版开源+商业版开源,免费开源+商业版商业版,按量付费开源+商业版开源,免费
适用场景混合搜索结构化数据+向量高性能、低延迟半结构化数据+向量高性能向量搜索大规模向量管理简单部署、高可用中小规模应用快速原型开发

2. 不同相似度计算方法对比

相似度方法数学表达式值域适用场景特点支持的存储系统
余弦相似度cos(θ) = A·B / (‖A‖·‖B‖)[-1, 1]文本语义搜索不受向量长度影响,只考虑方向全部
点积A·B = ∑(A_i × B_i)无限制推荐系统考虑向量长度和方向,通常需要归一化ES, MongoDB, FAISS, Milvus, Pinecone, Qdrant
欧几里得距离‖A-B‖ = √(∑(A_i - B_i)²)[0, ∞)图像特征、地理位置值越小表示越相似,需要转换为相似度ES, PGVector, Redis, MongoDB, FAISS, Milvus, Qdrant
曼哈顿距离∑|A_i - B_i|[0, ∞)网格空间、特征差异计算简单,对异常值不敏感FAISS, Milvus
杰卡德相似度J(A,B) = |A∩B| / |A∪B|[0, 1]集合比较、文档相似度适用于二进制特征或集合ES(脚本), PGVector(SQL)
汉明距离H(A,B) = ∑(A_i ⊕ B_i)[0, dim]二进制特征、错误检测计算二进制向量中不同位的数量FAISS

3. 适用场景对比总结

解决方案最适合场景不适合场景
Elasticsearch需要混合搜索(文本+向量)、已有 ES 基础设施、需要复杂文本处理超大规模纯向量搜索、极低延迟要求、GPU 加速需求
PGVector已有 PostgreSQL 基础设施、需要事务支持、结构化数据+向量超大规模向量集、分布式部署需求
Redis Vector超低延迟需求、缓存层向量搜索、临时数据持久化要求高、复杂查询、大规模数据
MongoDB Atlas半结构化数据、文档+向量混合、MongoDB 用户复杂文本分析、极高性能要求
FAISS纯向量搜索、算法研究、GPU 加速、嵌入式应用需要持久化、分布式部署、元数据过滤
Milvus大规模向量管理、需要丰富索引算法、混合查询简单应用、资源受限环境
Pinecone快速部署、无运维需求、按需扩展自托管需求、成本敏感、复杂查询
Qdrant中小规模应用、需要良好元数据过滤、开源需求超大规模、GPU 加速需求
Chroma快速原型开发、简单应用、本地部署企业级应用、大规模数据、高并发

五、基于 Elasticsearch 的 RAG 实现方案

1. 系统架构设计

基于 Elasticsearch 实现 RAG 系统的整体架构如下:

  1. 1. 数据处理层:负责文档的收集、清洗、分块和向量化

  2. 2. 存储层:使用 Elasticsearch 存储文本内容和向量表示

  3. 3. 检索层:实现混合检索策略,结合文本和向量搜索

  4. 4. 生成层:集成 Deepseek V3 或 Qwen2.5 大模型,基于检索结果生成回答

  5. 5. 应用层:提供用户界面和 API 接口

2. 实现步骤详解

2.1 环境准备

首先,我们需要安装必要的依赖:

# 安装必要的库
pip install elasticsearch langchain langchain-elasticsearch langchain-community langchain-openai
pip install deepseek-ai qwen-api
2.2 Elasticsearch 配置

设置 Elasticsearch 集群并创建适合 RAG 的索引,展示不同相似度计算方法:

from elasticsearch import Elasticsearch# 连接到Elasticsearch
es = Elasticsearch(hosts=["http://localhost:9200"],basic_auth=("user", "password"),  # 如果有认证request_timeout=60
)# 创建索引映射,使用cosine相似度
cosine_index_mapping = {"mappings": {"properties": {"title": {"type": "text", "analyzer": "standard"},"content": {"type": "text", "analyzer": "standard"},"source": {"type": "keyword"},"content_vector": {"type": "dense_vector","dims": 1536,  # 根据嵌入模型调整维度"index": True,"similarity": "cosine"  # 余弦相似度}}},"settings": {"number_of_shards": 2,"number_of_replicas": 1}
}# 创建使用余弦相似度的索引
es.indices.create(index="rag-knowledge-cosine", body=cosine_index_mapping)# 创建索引映射,使用dot_product相似度
dot_product_index_mapping = {"mappings": {"properties": {"title": {"type": "text", "analyzer": "standard"},"content": {"type": "text", "analyzer": "standard"},"source": {"type": "keyword"},"content_vector": {"type": "dense_vector","dims": 1536,"index": True,"similarity": "dot_product"  # 点积相似度}}},"settings": {"number_of_shards": 2,"number_of_replicas": 1}
}# 创建使用点积相似度的索引
es.indices.create(index="rag-knowledge-dot-product", body=dot_product_index_mapping)# 创建索引映射,使用l2_norm相似度
l2_norm_index_mapping = {"mappings": {"properties": {"title": {"type": "text", "analyzer": "standard"},"content": {"type": "text", "analyzer": "standard"},"source": {"type": "keyword"},"content_vector": {"type": "dense_vector","dims": 1536,"index": True,"similarity": "l2_norm"  # 欧几里得距离(L2范数)}}},"settings": {"number_of_shards": 2,"number_of_replicas": 1}
}# 创建使用L2范数相似度的索引
es.indices.create(index="rag-knowledge-l2-norm", body=l2_norm_index_mapping)

2.3 文档处理与索引

实现文档的处理、分块和向量化,并分别存储到不同相似度计算方法的索引中:

import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings  # 也可以使用其他嵌入模型# 加载文档
loader = DirectoryLoader("./documents", glob="**/*.txt", loader_cls=TextLoader)
documents = loader.load()# 文档分块
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000,chunk_overlap=200,length_function=len,
)
chunks = text_splitter.split_documents(documents)# 初始化嵌入模型
embeddings = OpenAIEmbeddings()  # 可替换为其他嵌入模型# 处理文档并索引到不同的Elasticsearch索引
for i, chunk in enumerate(chunks):# 生成向量嵌入vector = embeddings.embed_query(chunk.page_content)# 准备索引文档doc = {"title": f"Chunk {i} from {chunk.metadata.get('source', 'unknown')}","content": chunk.page_content,"source": chunk.metadata.get("source", "unknown"),"content_vector": vector}# 索引文档到不同相似度计算方法的索引es.index(index="rag-knowledge-cosine", document=doc)# 对于dot_product,通常需要归一化向量es.index(index="rag-knowledge-dot-product", document=doc)# 对于l2_norm,直接使用原始向量es.index(index="rag-knowledge-l2-norm", document=doc)# 刷新索引
es.indices.refresh(index="rag-knowledge-cosine")
es.indices.refresh(index="rag-knowledge-dot-product")
es.indices.refresh(index="rag-knowledge-l2-norm")

2.4 使用 LangChain 与 Elasticsearch 实现 RAG

下面是使用 LangChain 与 Elasticsearch 结合实现 RAG 的代码,支持不同相似度计算方法:

from langchain_elasticsearch import ElasticsearchStore
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain.schema import Document# 初始化不同相似度计算方法的Elasticsearch向量存储
es_store_cosine = ElasticsearchStore(es_url="http://localhost:9200",index_name="rag-knowledge-cosine",embedding=embeddings,es_user="user",  # 如果有认证es_password="password"  # 如果有认证
)es_store_dot_product = ElasticsearchStore(es_url="http://localhost:9200",index_name="rag-knowledge-dot-product",embedding=embeddings,es_user="user",es_password="password"
)es_store_l2_norm = ElasticsearchStore(es_url="http://localhost:9200",index_name="rag-knowledge-l2-norm",embedding=embeddings,es_user="user",es_password="password"
)# 创建不同相似度计算方法的检索器
retriever_cosine = es_store_cosine.as_retriever(search_type="similarity",search_kwargs={"k": 5}
)retriever_dot_product = es_store_dot_product.as_retriever(search_type="similarity",search_kwargs={"k": 5}
)retriever_l2_norm = es_store_l2_norm.as_retriever(search_type="similarity",search_kwargs={"k": 5}
)# 创建多相似度混合检索器
def multi_similarity_retriever(query, top_k=5):# 从三种不同相似度方法获取结果cosine_docs = retriever_cosine.get_relevant_documents(query)dot_product_docs = retriever_dot_product.get_relevant_documents(query)l2_norm_docs = retriever_l2_norm.get_relevant_documents(query)# 合并结果all_docs = cosine_docs + dot_product_docs + l2_norm_docs# 去重unique_docs = list({doc.page_content: doc for doc in all_docs}.values())# 限制返回数量return unique_docs[:top_k]# 定义提示模板
template = """
你是一个专业的AI助手。请基于以下提供的上下文信息,回答用户的问题。
如果你无法从上下文中找到答案,请直接说"我无法从提供的信息中找到答案",不要编造信息。上下文信息:
{context}用户问题: {question}回答:
"""prompt = PromptTemplate(template=template,input_variables=["context", "question"]
)# 格式化文档函数
def format_docs(docs):return "\n\n".join([doc.page_content for doc in docs])

2.5 集成 Deepseek V3 模型

from langchain_deepseek import DeepseekChat# 初始化Deepseek模型
deepseek_llm = DeepseekChat(model_name="deepseek-ai/deepseek-v3",api_key="your_api_key",temperature=0.1
)# 构建RAG链(使用余弦相似度)
deepseek_rag_chain_cosine = ({"context": retriever_cosine | format_docs, "question": RunnablePassthrough()}| prompt| deepseek_llm| StrOutputParser()
)# 构建RAG链(使用点积相似度)
deepseek_rag_chain_dot_product = ({"context": retriever_dot_product | format_docs, "question": RunnablePassthrough()}| prompt| deepseek_llm| StrOutputParser()
)# 构建RAG链(使用L2范数相似度)
deepseek_rag_chain_l2_norm = ({"context": retriever_l2_norm | format_docs, "question": RunnablePassthrough()}| prompt| deepseek_llm| StrOutputParser()
)# 构建RAG链(使用多相似度混合检索)
def answer_with_deepseek_multi_similarity(question):# 获取多相似度混合检索结果docs = multi_similarity_retriever(question)context = format_docs(docs)# 构建RAG链chain = ({"context": RunnablePassthrough(), "question": RunnablePassthrough()}| prompt| deepseek_llm| StrOutputParser())# 生成回答return chain.invoke({"context": context, "question": question})# 示例
response = answer_with_deepseek_multi_similarity("什么是向量数据库?")
print(response)

2.6 集成 Qwen2.5 模型

from langchain_community.llms import QianfanLLMEndpoint# 初始化Qwen模型
qwen_llm = QianfanLLMEndpoint(model_name="qwen-2.5",api_key="your_api_key",secret_key="your_secret_key",temperature=0.1
)# 构建RAG链(使用余弦相似度)
qwen_rag_chain_cosine = ({"context": retriever_cosine | format_docs, "question": RunnablePassthrough()}| prompt| qwen_llm| StrOutputParser()
)# 构建RAG链(使用点积相似度)
qwen_rag_chain_dot_product = ({"context": retriever_dot_product | format_docs, "question": RunnablePassthrough()}| prompt| qwen_llm| StrOutputParser()
)# 构建RAG链(使用L2范数相似度)
qwen_rag_chain_l2_norm = ({"context": retriever_l2_norm | format_docs, "question": RunnablePassthrough()}| prompt| qwen_llm| StrOutputParser()
)# 构建RAG链(使用多相似度混合检索)
def answer_with_qwen_multi_similarity(question):# 获取多相似度混合检索结果docs = multi_similarity_retriever(question)context = format_docs(docs)# 构建RAG链chain = ({"context": RunnablePassthrough(), "question": RunnablePassthrough()}| prompt| qwen_llm| StrOutputParser())# 生成回答return chain.invoke({"context": context, "question": question})# 示例
response = answer_with_qwen_multi_similarity("Elasticsearch的主要优势是什么?")
print(response)

3. 高级功能实现

3.1 实现混合搜索策略
def enhanced_hybrid_search(query, es_client, index_name, embedding_model, similarity_type="cosine"):# 生成查询向量query_vector = embedding_model.embed_query(query)# 根据不同相似度类型构建脚本if similarity_type == "cosine":similarity_script = "cosineSimilarity(params.query_vector, 'content_vector') + 1.0"elif similarity_type == "dot_product":similarity_script = "dotProduct(params.query_vector, 'content_vector')"elif similarity_type == "l2_norm":# 对于L2范数,较小的值表示更相似,所以我们使用负值或倒数similarity_script = "1 / (1 + l2Norm(params.query_vector, 'content_vector'))"else:raise ValueError(f"不支持的相似度类型: {similarity_type}")# 构建混合查询hybrid_query = {"query": {"bool": {"should": [# 向量搜索部分{"script_score": {"query": {"match_all": {}},"script": {"source": similarity_script,"params": {"query_vector": query_vector}}}},# 文本搜索部分{"match": {"content": {"query": query,"boost": 0.5  # 调整文本搜索的权重}}}]}},"size": 5}# 执行搜索response = es_client.search(index=index_name, body=hybrid_query)# 处理结果results = []for hit in response["hits"]["hits"]:results.append({"score": hit["_score"],"title": hit["_source"]["title"],"content": hit["_source"]["content"],"source": hit["_source"]["source"]})return results

3.2 实现自适应相似度选择
def adaptive_similarity_search(query, es_client, embedding_model):# 分析查询特征,决定使用哪种相似度方法query_length = len(query.split())# 短查询(1-3个词)可能更适合关键词搜索if query_length <= 3:# 使用混合搜索,但给文本搜索更高权重results = enhanced_hybrid_search(query, es_client, "rag-knowledge-cosine", embedding_model,similarity_type="cosine")# 中等长度查询(4-10个词)elif query_length <= 10:# 使用余弦相似度,适合一般语义搜索results = enhanced_hybrid_search(query, es_client, "rag-knowledge-cosine", embedding_model,similarity_type="cosine")# 长查询(>10个词)else:# 对于长查询,点积可能更适合捕捉更多语义信息results = enhanced_hybrid_search(query, es_client, "rag-knowledge-dot-product", embedding_model,similarity_type="dot_product")return results

3.3 实现多步检索策略
def multi_step_retrieval(query, es_client, embedding_model):# 第一步:使用文本搜索获取初步结果text_query = {"query": {"match": {"content": query}},"size": 20}text_response = es_client.search(index="rag-knowledge-cosine", body=text_query)# 提取文档ID和内容candidate_docs = []for hit in text_response["hits"]["hits"]:candidate_docs.append({"id": hit["_id"],"content": hit["_source"]["content"]})# 如果文本搜索没有足够结果,添加向量搜索if len(candidate_docs) < 10:# 生成查询向量query_vector = embedding_model.embed_query(query)# 向量搜索vector_query = {"query": {"script_score": {"query": {"match_all": {}},"script": {"source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0","params": {"query_vector": query_vector}}}},"size": 20 - len(candidate_docs)}vector_response = es_client.search(index="rag-knowledge-cosine", body=vector_query)# 添加到候选文档for hit in vector_response["hits"]["hits"]:# 避免重复if not any(doc["id"] == hit["_id"] for doc in candidate_docs):candidate_docs.append({"id": hit["_id"],"content": hit["_source"]["content"]})# 第二步:对候选文档进行重新排序# 生成查询向量query_vector = embedding_model.embed_query(query)# 为每个候选文档计算相似度分数for doc in candidate_docs:# 生成文档向量doc_vector = embedding_model.embed_query(doc["content"])# 计算余弦相似度similarity = cosine_similarity([query_vector],[doc_vector])[0][0]doc["similarity_score"] = similarity# 按相似度排序ranked_docs = sorted(candidate_docs, key=lambda x: x["similarity_score"], reverse=True)# 返回前5个最相关文档return ranked_docs[:5]

3.4 实现查询扩展和改写
def query_expansion(original_query, llm):# 使用大模型扩展查询expansion_prompt = f"""请基于以下原始查询,生成3个不同的扩展查询,以便更全面地搜索相关信息。每个扩展查询应该保留原始查询的核心意图,但可以添加相关术语、同义词或上下文。原始查询: {original_query}扩展查询(每行一个):"""# 获取扩展查询response = llm.invoke(expansion_prompt)# 解析响应expanded_queries = [q.strip() for q in response.split("\n") if q.strip()]# 过滤掉可能的空行或无关行expanded_queries = [q for q in expanded_queries if len(q) > 5]# 确保至少有一个查询(原始查询)if not expanded_queries:expanded_queries = [original_query]else:# 添加原始查询expanded_queries.append(original_query)return expanded_queriesdef multi_query_retrieval(original_query, es_client, embedding_model, llm):# 扩展查询expanded_queries = query_expansion(original_query, llm)# 对每个扩展查询执行搜索all_results = []for query in expanded_queries:results = enhanced_hybrid_search(query, es_client, "rag-knowledge-cosine", embedding_model)all_results.extend(results)# 去重unique_results = []seen_contents = set()for result in all_results:if result["content"] not in seen_contents:unique_results.append(result)seen_contents.add(result["content"])# 重新排序(可以基于原始查询的相似度)query_vector = embedding_model.embed_query(original_query)# 为每个结果计算与原始查询的相似度for result in unique_results:# 假设我们可以从ES获取内容的向量content_vector_query = {"query": {"term": {"_id": result["id"]}},"_source": ["content_vector"]}vector_response = es_client.search(index="rag-knowledge-cosine", body=content_vector_query)content_vector = vector_response["hits"]["hits"][0]["_source"]["content_vector"]# 计算相似度similarity = cosine_similarity([query_vector],[content_vector])[0][0]result["final_score"] = similarity# 按最终分数排序ranked_results = sorted(unique_results, key=lambda x: x["final_score"], reverse=True)# 返回前5个最相关结果return ranked_results[:5]

六、总结与结论

1. Elasticsearch 作为 RAG 向量数据库的优势总结

  1. 1. 全栈解决方案:Elasticsearch 提供了从数据索引到检索的完整解决方案,无需集成多个系统。

  2. 2. 混合检索能力:结合传统文本搜索和向量搜索的能力是其最大优势,能够显著提高检索质量。

  3. 3. 成熟的生态系统:作为成熟的搜索引擎,拥有丰富的文档、工具和社区支持。

  4. 4. 多模态支持:能够存储和检索文本、图像、音频和视频的向量表示,支持多模态 RAG 应用。

  5. 5. 灵活的相似度计算:支持多种相似度计算方法(余弦、点积、L2 范数),适应不同应用场景。

2. 实施建议

  1. 1. 选择合适的相似度计算方法:

    • 文本语义搜索:优先使用余弦相似度
    • 推荐系统:考虑使用点积
    • 图像或地理位置搜索:考虑使用 L2 范数
  2. 2. 优化索引配置:

    • 根据数据量和查询频率调整分片数量
    • 为频繁查询的索引配置足够的副本
    • 合理设置 HNSW 参数,平衡搜索精度和性能
  3. 3. 实现混合检索策略:

    • 结合向量搜索和关键词搜索
    • 根据查询特征动态调整搜索策略
    • 考虑使用查询扩展和多步检索提高召回率
  4. 4. 性能优化:

    • 对于大规模部署,考虑使用专用节点
    • 监控和调整 JVM 堆大小
    • 定期优化索引

3. 未来发展方向

  1. 1. 与专用向量数据库的集成:

    • 考虑 Elasticsearch 与专用向量数据库(如 FAISS、Milvus)的混合架构
    • 利用 ES 的文本处理和混合查询能力,结合专用向量数据库的高性能向量搜索
  2. 2. 知识图谱增强:

    • 将向量搜索与知识图谱结合,实现 GraphRAG
    • 利用实体关系增强检索结果的相关性和可解释性
  3. 3. 多模态 RAG 应用:

    • 扩展到图像、音频和视频内容的检索增强生成
    • 实现跨模态检索,如以文搜图、以图搜文
  4. 4. 自适应检索策略:

    • 开发能够根据查询特征和上下文自动选择最佳检索策略的系统
    • 利用强化学习优化检索参数

4. 结论

Elasticsearch 作为 RAG 系统的向量数据库具有显著优势,特别是在需要混合检索、多模态支持和成熟生态系统的场景下。虽然在纯向量搜索性能上可能不如专用向量数据库,但其全面的功能和灵活性使其成为构建企业级 RAG 系统的有力选择。

通过合理配置和优化,结合本报告提供的实现方案,可以充分发挥 Elasticsearch 在 RAG 系统中的潜力,为大模型应用提供高质量的知识检索支持。

对于需要构建 RAG 系统的团队,建议根据具体需求和现有技术栈选择合适的向量存储解决方案,Elasticsearch 特别适合已有 ES 基础设施、需要混合检索能力以及处理多模态数据的场景。

 


【大模型介绍电子书】

快速揭秘DeepSeek背后的AI工作原理

要获取本书全文PDF内容,请在VX后台留言:“AI大模型基础” 或者 “大模型基础” 就会获得电子书的PDF。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

15:00面试,15:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

ORACLE 19.8版本数据库环境EXPDP导数据的报错处理

近期用户在做EXPDP导出时&#xff0c;报错异常termination终止;EXPDP本身是简单的功能并且这个环境也是经常做导出的&#xff0c;到底是什么原因导致了这个问题呢&#xff1f; 导出脚本报错&#xff1a; 分析导出日志&#xff0c;当时系统资源充足但是进程启动失败&#xff0c;…

【Editor】动态添加/移除宏定义

ProjectSetting中OtherSettings页签 执行工具指令 using UnityEditor; using UnityEngine; using System.Linq;public class Tools : Editor {//在菜单栏中点击自动添加[MenuItem("Tools/AddScriptingSymbols")]private static void AddScriptingSymbols(){//获取当…

Web-Machine-N7靶机实战攻略

1.安装并开启靶机 下载VirtualBox&#xff1a;https://www.virtualbox.org 导入虚拟机 设置为桥接模式 2.获取靶机IP Kali设为桥接模式 3.访问靶机 4.获取敏感目录文件和端口 gobuster dir -u http://172.16.2.68 -w /usr/share/wordlists/dirbuster/directory-list-2.3-me…

C语言实验:数组,指针实现问题求解

实验目的&#xff1a;掌握数组&#xff0c;指针的使用 实验内容&#xff1a; 1直接选择排序 2字符串运算 3交换数字 流程图&#xff1a; 1直接选择排序 2字符串运算 3交换数字 程序调试 1直接选择排序 1-1出现问题&#xff08;贴图并说明&#xff09; 错误原因&#xf…

【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解

【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解 &#xff08;图1-1&#xff09; 一、鸿蒙中App、HAP、HAR、HSP是什么&#xff1f; &#xff08;1&#xff09;App Pack&#xff08;Application Package&#xff09; 是应用发布的形态&#xff0c;上架应用市场是以App Pa…

LiteIDE中配置golang编译生成无CMD窗口EXE的步骤

LiteIDE中配置golang编译生成无CMD窗口EXE的步骤 一、环境配置1、设置GOROOT‌2、配置GOPATH‌ 二、项目编译参数设置1、新建/打开项目‌2、修改编译配置‌3、其他优化选项&#xff08;可选&#xff09;‌ 三、构建与验证1、编译生成EXE‌2、验证无窗口效果‌ 四、注意事项 一、…

暗光增强技术研究进展与产品落地综合分析(2023-2025)

一、引言 暗光增强技术作为计算机视觉与移动影像领域的核心研究方向之一,近年来在算法创新、硬件适配及产品落地方面取得了显著进展。本文从技术研究与产业应用两个维度,系统梳理近三年(2023-2025)该领域的关键突破,并对比分析主流手机厂商的影像技术优劣势。 二、暗光增…

理解 RAG 第四部分:RAGA 和其他评估框架

检索增强生成(RAG) 在扩展独立大型语言模型(LLM)的限制和克服其诸多局限性方面发挥了关键作用。通过整合检索器&#xff0c;RAG 提高了响应相关性和事实准确性&#xff1a;它只需实时利用外部知识源&#xff08;如矢量文档库&#xff09;&#xff0c;并在原始用户查询或提示中添…

基于视觉的核桃分级与套膜装置研究(大纲)

基于视觉的核桃分级与套膜装置研究&#xff1a;从设计到实现的完整指南 &#xff08;SolidWorks、OpenCV、STM32开发实践&#xff09; &#x1f31f; 项目背景与目标 1.1 为什么选择视觉分级与套膜&#xff1f; 产业痛点&#xff1a; 中国核桃年产量全球第一&#xff0c;但…

蓝桥杯2023年第十四届省赛真题-子矩阵

题目来自DOTCPP&#xff1a; 暴力思路&#xff08;两个测试点超时&#xff09;&#xff1a; 题目要求我们求出子矩阵的最大值和最小值的乘积&#xff0c;我们可以枚举矩阵中的所有点&#xff0c;以这个点为其子矩阵的左上顶点&#xff0c;然后判断一下能不能构成子矩阵。如果可…

系统思考—啤酒游戏经营决策沙盘模拟

再次感谢文华学院的邀请&#xff0c;为经纬集团管理层带来 《啤酒游戏经营决策沙盘》&#xff01; 很多朋友问&#xff1a;“最近是不是啤酒游戏上的少了&#xff1f;” 其实&#xff0c;真正的关键不是游戏本身&#xff0c;而是——如何让大家真正看见复杂系统中的隐性结构。 …

Linux 驱动开发笔记--1.驱动开发的引入

1.引入 Linux内核的整体架构本就非常庞大&#xff0c;其包含的组件也非常多。而我们怎样把需要的部分都包含在内核中呢? 一种方法是把所有需要的功能都编译到Linux内核中。这会导致两个问题&#xff0c;一是生成的内核会很大&#xff0c;二是如果我们要在现有的内核中新增或删…

跨域问题确认及处理

背景如下&#xff1a; 近期在做的项目中&#xff0c;有个奇怪的需求&#xff0c;需要在JSP项目中嵌套一个VUE项目&#xff0c;原因是&#xff1a;JSP项目是在运且不大方便重构的一个项目&#xff0c;新需求又想为了未来着想做一套单独的项目&#xff0c;无奈只能嵌套。 当项目开…

Qwen2.5-VL 开源视觉大模型,模型体验、下载、推理、微调、部署实战

一、Qwen2.5-VL 简介 Qwen2.5-VL&#xff0c;Qwen 模型家族的旗舰视觉语言模型&#xff0c;比 Qwen2-VL 实现了巨大的飞跃。 欢迎访问 Qwen Chat &#xff08;Qwen Chat&#xff09;并选择 Qwen2.5-VL-72B-Instruct 进行体验。 1. 主要增强功能 1&#xff09;直观地理解事物&…

实时监控、数据分析!Web-Check构建你的网站健康检测系统实操方案

文章目录 前言1.关于Web-Check2.功能特点3.安装Docker4.创建并启动Web-Check容器5.本地访问测试6.公网远程访问本地Web-Check7.内网穿透工具安装8.创建远程连接公网地址9.使用固定公网地址远程访问 前言 在数字化运维领域&#xff0c;网站稳定性保障始终是开发者和运维团队的核…

为什么在外置容器时要保证打包方式是war包?

目录 1. 符合Java EE标准 2. 打包结构清晰 3. 便于部署 4. 支持热部署 5. 与Spring Boot的对比 示例&#xff1a;将Spring Boot应用打包为WAR文件 在传统的Java Web应用开发中&#xff0c;当使用外置容器&#xff08;如Tomcat、Jetty等&#xff09;部署应用时&#xff0c…

【大语言模型_8】vllm启动的模型通过fastapi封装增加api-key验证

背景&#xff1a; vllm推理框架启动模型不具备api-key验证。需借助fastapi可以实现该功能 代码实现&#xff1a; rom fastapi import FastAPI, Header, HTTPException, Request,Response import httpx import logging# 创建 FastAPI 应用 app FastAPI() logging.basicConfig(…

【Linux】快速上手Makeflie CMake

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:Ubuntu 22.04 server 64bit) 目录 快速上手Makefile 基本结构 变量 自动变量 常用目标 快速上手CMake CMake与Makefile的关系 CMake的使用步骤 常用命令 (1) 基本配置 (2) 变量与选…

智能蔬菜收获移动平台设计(大纲)

智能蔬菜收获移动平台设计 基于视觉识别与机械臂协同的自动化采摘系统 第一章 绪论 1.1 研究背景与意义 农业自动化需求&#xff1a; 人力成本高、采摘效率低&#xff08;尤其在温室、大棚等复杂环境&#xff09;传统机械采摘易造成蔬菜损伤&#xff0c;缺乏柔性化能力 技…