Haystack 集成 Oracle AI Vector Search:OracleDocumentStore 与 OracleEmbeddingRetriever 完整实战指南
【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack
本文基于 Haystack 仓库中 Oracle 集成 API 参考文档(docs-website/reference_versioned_docs/version-2.20/integrations-api/oracle.md)编写,系统讲解如何将 Oracle Database 23ai 的 AI Vector Search 作为 Haystack 的向量文档存储后端,涵盖连接配置(Thin/Thick 模式)、文档写入与去重、HNSW 近似检索索引、向量相似度检索、元数据过滤与统计、删除清理、异步 API 及序列化等全部能力。读完本文,你将能够在自己的 RAG 与语义搜索流水线中,把OracleDocumentStore与OracleEmbeddingRetriever真正跑起来。
集成概览:把 Oracle 23ai 变成 Haystack 的向量后端
OracleDocumentStore是 Haystack 中由 Oracle AI Vector Search 支撑的 Document Store。它把文档连同稠密向量一起存进 Oracle 原生的VECTOR列,并借助自动管理的DBMS_SEARCH索引同时支持向量相似度检索与关键字全文检索。该集成要求Oracle Database 23ai 或更高版本,因为 23ai 才提供VECTOR数据类型与IF NOT EXISTSDDL 支持。
集成由两个核心构件组成:
OracleDocumentStore(haystack_integrations.document_stores.oracle.document_store):负责建表、建索引、读写文档与元数据操作的后端存储;OracleEmbeddingRetriever(haystack_integrations.components.retrievers.oracle.embedding_retriever):基于向量相似度从OracleDocumentStore中取回相关文档,通常作为 Text Embedder 之后的检索组件。
配套的使用指南可参考仓库内的 OracleEmbeddingRetriever 组件文档 与 OracleDocumentStore 文档。
安装集成包:
pip install oracle-haystack如果使用 Sentence Transformers 系列的嵌入器,还需要安装:
pip install sentence-transformers-haystack连接配置:OracleConnectionConfig 的 Thin 与 Thick 两种模式
OracleConnectionConfig是集成的连接参数数据类,支持两种连接模式:
- Thin 模式(默认):通过直接 TCP 连接 Oracle,无需安装 Oracle Instant Client;
- Thick 模式:当传入
wallet_location时自动激活,用于连接 Oracle Autonomous Database(ADB-S),需要钱包(wallet)文件做认证。
基础连接(Thin 模式)
推荐把敏感信息放进环境变量,再用Secret.from_env_var引用:
export ORACLE_USER="haystack" export ORACLE_PASSWORD="secret" export ORACLE_DSN="localhost:1521/freepdb1"from haystack.utils import Secret from haystack_integrations.document_stores.oracle import ( OracleDocumentStore, OracleConnectionConfig, ) store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), ), embedding_dim=1536, )连接 Oracle Autonomous Database(Thick 模式)
给OracleConnectionConfig传入wallet_location与wallet_password,集成会自动切换到 Thick 模式:
document_store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), wallet_location="/path/to/wallet", wallet_password=Secret.from_env_var("WALLET_PASSWORD"), ), embedding_dim=1536, )OracleConnectionConfig同样实现了to_dict()/from_dict()两个方法,用于把连接配置序列化为字典、以及从字典反序列化,方便配合 Haystack 的 YAML 管线持久化机制使用。
本地快速启动 Oracle 23ai
想在本地跑通示例,可以用 Docker 启动 Oracle Free 23ai(参考 OracleEmbeddingRetriever 组件文档):
docker run -d --name oracle23ai \ -p 1521:1521 \ -e ORACLE_PASSWORD=oracle \ -e ORACLE_INIT_PARAMS=vector_memory_size=512M \ gvenzl/oracle-free:23-slimOracleDocumentStore 初始化参数详解
OracleDocumentStore.__init__的完整签名如下(见 API 参考):
__init__( *, connection_config: OracleConnectionConfig, table_name: str = "haystack_documents", embedding_dim: int, distance_metric: Literal["COSINE", "EUCLIDEAN", "DOT"] = "COSINE", create_table_if_not_exists: bool = True, create_index: bool = False, hnsw_neighbors: int = 32, hnsw_ef_construction: int = 200, hnsw_accuracy: int = 95, hnsw_parallel: int = 4 ) -> None各参数含义与默认值:
| 参数 | 默认值 | 说明 |
|---|---|---|
connection_config | (必填) | Oracle 连接配置(user、password、DSN、可选 wallet)。 |
table_name | "haystack_documents" | 存放文档的 Oracle 表名。必须是合法的 Oracle 标识符:仅含字母、数字、_、$、#,最长 128 字符,且不能以数字开头。 |
embedding_dim | (必填) | 向量维度,必须与生成向量的模型一致。例如all-MiniLM-L6-v2是 384/768 维,OpenAI 的 text-embedding-3 系列常用 1536 维。 |
distance_metric | "COSINE" | 相似度搜索使用的向量距离函数,可选"COSINE"、"EUCLIDEAN"、"DOT"。 |
create_table_if_not_exists | True | 为True(默认)时,首次使用时自动创建表以及DBMS_SEARCH关键字索引;连接已存在的表时请设为False。 |
create_index | False | 为True时在初始化阶段创建 HNSW 向量索引,等价于手动调用create_hnsw_index()。 |
hnsw_neighbors | 32 | HNSW 图中的邻居数。值越大召回率越高,但索引体积与构建时间也越大。 |
hnsw_ef_construction | 200 | HNSW 索引构建期间动态候选列表的大小。值越大召回率越高,构建时间越长。 |
hnsw_accuracy | 95 | HNSW 索引的目标召回率百分比(0-100)。 |
hnsw_parallel | 4 | 构建 HNSW 索引时的并行度。 |
初始化时若table_name不是合法的 Oracle 标识符,或embedding_dim不是正整数,会抛出ValueError。
关于向量检索模式与 HNSW 索引
默认情况下,存储执行的是精确向量搜索。当数据集较大时,可创建 HNSW 索引启用近似最近邻(ANN)搜索以换取更快的查询速度:
document_store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), ), embedding_dim=768, distance_metric="COSINE", create_index=True, # 启动时创建 HNSW 索引 hnsw_neighbors=32, hnsw_ef_construction=200, hnsw_accuracy=95, )除了初始化参数,文档存储还暴露了三个索引管理方法:
create_keyword_index():在该表上创建DBMS_SEARCH关键字索引,用于关键字检索。可安全地重复调用——索引已存在时会静默跳过。当create_table_if_not_exists=True时会被自动调用;但连接已存在的表时,必须显式调用。create_hnsw_index():在 embedding 列上创建 HNSW 向量索引,使用IF NOT EXISTS,可安全重复调用。create_hnsw_index_async():异步版create_hnsw_index(),同样使用IF NOT EXISTS。
写入文档与去重策略 DuplicatePolicy
write_documents/write_documents_async负责把文档写入存储:
write_documents( documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE ) -> intdocuments:待写入的文档列表;policy:写入时的去重策略,返回值为实际写入的文档数量。
去重策略DuplicatePolicy定义在核心仓库的 haystack/document_stores/types/policy.py,共四个取值:
| 枚举值 | 含义 |
|---|---|
DuplicatePolicy.NONE | 默认值,不主动检查去重,遇到重名 id 时可能直接失败(见下方异常说明)。 |
DuplicatePolicy.SKIP | 跳过已存在的文档。 |
DuplicatePolicy.OVERWRITE | 用新内容覆盖已存在的文档。 |
DuplicatePolicy.FAIL | 遇到已存在的文档直接抛错。 |
当 id 相同的文档已存在、且策略为DuplicatePolicy.FAIL或DuplicatePolicy.NONE时,会抛出DuplicateDocumentError。
向量检索:OracleEmbeddingRetriever
OracleEmbeddingRetriever是兼容OracleDocumentStore的 embedding 检索器,它借助 Oracle AI Vector Search 比较查询向量与文档向量,返回最相关的文档。在管线中的典型位置是 Text Embedder 之后:
pipeline.add_component("embedder", SentenceTransformersTextEmbedder()) pipeline.add_component("retriever", OracleEmbeddingRetriever( document_store=store, top_k=5 )) pipeline.connect("embedder.embedding", "retriever.query_embedding")run / run_async 方法
run( query_embedding: list[float], filters: dict[str, Any] | None = None, top_k: int | None = None, ) -> dict[str, list[Document]]query_embedding:来自嵌入器组件的稠密浮点向量(必填);filters:运行时过滤器,按照filter_policy与构造时传入的过滤器合并;top_k:覆盖构造时top_k的本次调用参数;- 返回值:
{"documents": [Document, ...]}。
run_async是run的异步变体,签名与返回结构完全一致。
过滤器合并规则(filter_policy)
filters的合并遵循 Haystack 核心库定义的FilterPolicy(实现见 haystack/document_stores/types/filter_policy.py):
FilterPolicy.REPLACE(默认):运行时过滤器直接替换初始化时设置的过滤器,适合为不同查询动态切换过滤条件;FilterPolicy.MERGE:把运行时过滤器与初始化过滤器合并(运行时值优先覆盖同名字段),用于逐步收窄搜索空间。
过滤器本身的语法(比较过滤器{"field", "operator", "value"}、逻辑过滤器{"operator", "conditions"})可参考仓库文档 docs-website/docs/concepts/metadata-filtering.mdx。
独立使用与完整管线示例
单独调用(示例来自 OracleEmbeddingRetriever 组件文档):
from haystack.utils import Secret from haystack_integrations.document_stores.oracle import ( OracleDocumentStore, OracleConnectionConfig, ) from haystack_integrations.components.retrievers.oracle import OracleEmbeddingRetriever document_store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), ), embedding_dim=768, ) retriever = OracleEmbeddingRetriever(document_store=document_store) # 使用假向量保持示例简单 retriever.run(query_embedding=[0.1] * 768)在 Pipeline 中完成"索引 + 查询"的完整流程:
from haystack import Document, Pipeline from haystack.document_stores.types import DuplicatePolicy from haystack_integrations.components.embedders.sentence_transformers import ( SentenceTransformersDocumentEmbedder, SentenceTransformersTextEmbedder, ) from haystack.utils import Secret from haystack_integrations.document_stores.oracle import ( OracleDocumentStore, OracleConnectionConfig, ) from haystack_integrations.components.retrievers.oracle import OracleEmbeddingRetriever document_store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), ), embedding_dim=768, ) documents = [ Document(content="There are over 7,000 languages spoken around the world today."), Document( content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.", ), Document( content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.", ), ] document_embedder = SentenceTransformersDocumentEmbedder( model="sentence-transformers/all-MiniLM-L6-v2", ) documents_with_embeddings = document_embedder.run(documents) document_store.write_documents( documents_with_embeddings["documents"], policy=DuplicatePolicy.OVERWRITE, ) query_pipeline = Pipeline() query_pipeline.add_component( "text_embedder", SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2"), ) query_pipeline.add_component( "retriever", OracleEmbeddingRetriever(document_store=document_store), ) query_pipeline.connect("text_embedder.embedding", "retriever.query_embedding") query = "How many languages are there?" result = query_pipeline.run({"text_embedder": {"text": query}}) print(result["retriever"]["documents"][0])注意:使用OracleEmbeddingRetriever时,必须保证文档(索引期)与查询(查询期)都有 embedding——索引管线用 Document Embedder,查询管线用 Text Embedder。距离度量(COSINE / EUCLIDEAN / DOT)是在OracleDocumentStore上配置的。
文档过滤、统计与元数据操作
OracleDocumentStore提供了一整套与元数据打交道的方法,支撑构建复杂的过滤、统计与运维场景(完整签名见 API 参考)。
过滤与计数
filter_documents(filters=None)/filter_documents_async:返回匹配过滤条件的文档列表。过滤器的详细规范见 docs-website/docs/concepts/metadata-filtering.mdx。count_documents()/count_documents_async:返回存储中的文档总数。count_documents_by_filter(filters)/count_documents_by_filter_async:返回匹配过滤条件的文档数量,空字典匹配全部文档。delete_by_filter(filters)/delete_by_filter_async:删除所有匹配过滤条件的文档并返回删除数量。空字典视为 no-op,返回0且不触碰表。
更新元数据(JSON_MERGEPATCH)
update_by_filter(filters: dict[str, Any], meta: dict[str, Any]) -> int把meta合并进所有匹配文档的元数据中。底层使用 Oracle 的JSON_MERGEPATCH语义:已存在的键被更新、新键被添加、meta中值为null的键被删除。meta必须是非空字典,否则抛出ValueError。
元数据字段统计
count_unique_metadata_by_filter(filters, metadata_fields):统计匹配文档中各元数据字段的去重值数量。字段名可以带"meta."前缀(如"meta.lang"或"lang");metadata_fields必须非空,字段名只能包含[A-Za-z0-9_.],否则抛ValueError。get_metadata_fields_info():返回元数据字段名到其检测类型的映射。底层使用 Oracle 的JSON_DATAGUIDE聚合函数对存储的 metadata 列做类型探查,结果形如{"field_name": {"type": "<type>"}, ...},<type>为"text"、"number"或"boolean";表为空时返回空字典。get_metadata_field_min_max(metadata_field):返回某个元数据字段在全库的最小值与最大值。实现上优先尝试用TO_NUMBER做数值比较,因此MAX(1, 5, 10)会返回10而不是按字典序取胜的"5";当字段包含非数值时回退到纯字符串比较。数值字符串在结果中会自动转成int或float。返回{"min": <value>, "max": <value>},表为空或字段不存在时两个值均为None。get_metadata_field_unique_values(metadata_field, search_term=None, from_=0, size=10, filters=None):返回某个元数据字段去重值的分页列表及总数,返回(values, total)元组。支持:search_term:对该字段自身值做不区分大小写的子串过滤;from_/size:零基偏移与页大小(size=None时返回从from_起的所有值);filters:限制参与统计的文档范围。- 值得注意的语义:不同类型的 JSON 值不合并——字符串
"1"与数字1是两个不同的去重值。唯一的例外是metadata列为 Oracle 原生JSON类型,会规范化数值存储,因此整数值的浮点1.0与整数1会合并为同一值;带小数的浮点(如1.5)不受影响。
以上每个统计方法都有对应的_async异步版本,签名与返回一致。
删除与清理操作
存储层提供从细粒度到全量的一整套删除能力,且对不可逆操作给出了明确警告:
delete_documents(document_ids)/delete_documents_async:按 id 列表删除文档。delete_all_documents()/delete_all_documents_async:使用TRUNCATE清空表中所有文档。TRUNCATE不可恢复——不能回滚,且绕过行级触发器;表结构与索引会被保留。delete_table()/delete_table_async:永久删除文档表及其关联的DBMS_SEARCH关键字索引。底层使用DROP TABLE ... PURGE,绕过 Oracle 回收站,操作不可逆;关键字索引在表之后删除,两步中任一步失败都会抛出DocumentStoreError。
异步 API 一览
该集成对核心方法全面提供了异步版本,适合在高并发、IO 密集的 async 场景下使用。同步与异步方法一一对应:
| 同步方法 | 异步方法 |
|---|---|
run(Retriever) | run_async |
create_hnsw_index | create_hnsw_index_async |
write_documents | write_documents_async |
filter_documents | filter_documents_async |
delete_documents | delete_documents_async |
count_documents | count_documents_async |
delete_table | delete_table_async |
delete_all_documents | delete_all_documents_async |
count_documents_by_filter | count_documents_by_filter_async |
delete_by_filter | delete_by_filter_async |
update_by_filter | update_by_filter_async |
count_unique_metadata_by_filter | count_unique_metadata_by_filter_async |
get_metadata_fields_info | get_metadata_fields_info_async |
get_metadata_field_min_max | get_metadata_field_min_max_async |
get_metadata_field_unique_values | get_metadata_field_unique_values_async |
此外,OracleEmbeddingRetriever与OracleDocumentStore都实现了close()方法,用于释放底层 Document Store 持有的同步资源。
序列化与反序列化
两个核心类都实现了标准的 Haystack 序列化协议:
to_dict() -> dict[str, Any]:把组件序列化为字典;from_dict(data) -> OracleEmbeddingRetriever/from_dict(data) -> OracleDocumentStore:从字典反序列化还原组件。
这使 Oracle 集成的文档存储与检索器可以被纳入 Haystack 的 YAML 管线定义,实现配置化、可版本化的部署。
端到端示例:基于 Oracle 的 RAG 管线
把上面的能力组合起来,就是一个完整的 RAG 应用(示例来自 OracleDocumentStore 文档):
from haystack import Document, Pipeline from haystack.document_stores.types import DuplicatePolicy from haystack_integrations.components.embedders.sentence_transformers import ( SentenceTransformersDocumentEmbedder, SentenceTransformersTextEmbedder, ) from haystack.components.builders import ChatPromptBuilder from haystack.components.generators.chat import OpenAIChatGenerator from haystack.dataclasses import ChatMessage from haystack.utils import Secret from haystack_integrations.document_stores.oracle import ( OracleDocumentStore, OracleConnectionConfig, ) from haystack_integrations.components.retrievers.oracle import OracleEmbeddingRetriever document_store = OracleDocumentStore( connection_config=OracleConnectionConfig( user=Secret.from_env_var("ORACLE_USER"), password=Secret.from_env_var("ORACLE_PASSWORD"), dsn=Secret.from_env_var("ORACLE_DSN"), ), embedding_dim=384, ) # 1. 索引文档 documents = [ Document(content="There are over 7,000 languages spoken around the world today."), Document(content="Elephants have been observed to behave in a way that indicates a high level of self-awareness."), Document(content="In certain places, you can witness the phenomenon of bioluminescent waves."), ] doc_embedder = SentenceTransformersDocumentEmbedder( model="sentence-transformers/all-MiniLM-L6-v2", ) embedded_docs = doc_embedder.run(documents)["documents"] document_store.write_documents(embedded_docs, policy=DuplicatePolicy.OVERWRITE) # 2. 构建 RAG 管线 template = [ ChatMessage.from_user( """ Given the following context, answer the question. Context: {% for doc in documents %}{{ doc.content }}{% endfor %} Question: {{ query }} """, ), ] pipeline = Pipeline() pipeline.add_component( "embedder", SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2"), ) pipeline.add_component( "retriever", OracleEmbeddingRetriever(document_store=document_store, top_k=3), ) pipeline.add_component("prompt_builder", ChatPromptBuilder(template=template)) pipeline.add_component( "llm", OpenAIChatGenerator(api_key=Secret.from_env_var("OPENAI_API_KEY")), ) pipeline.connect("embedder.embedding", "retriever.query_embedding") pipeline.connect("retriever.documents", "prompt_builder.documents") pipeline.connect("prompt_builder.prompt", "llm.messages") result = pipeline.run( { "embedder": {"text": "How many languages are there?"}, "prompt_builder": {"query": "How many languages are there?"}, }, ) print(result["llm"]["replies"][0].text)小结
Oracle AI Vector Search 集成让 Haystack 用户可以把企业级 Oracle Database 23ai 直接用作 RAG / 语义搜索的向量后端:OracleConnectionConfig兼顾 Thin/Thick 两种连接方式,OracleDocumentStore提供完整的文档生命周期管理(写入、过滤、统计、更新、删除)与精确/近似(HNSW)两种检索路径,OracleEmbeddingRetriever则无缝接入 Haystack 管线。若需进一步深入,可在仓库内继续阅读 OracleDocumentStore 使用文档、OracleEmbeddingRetriever 使用文档 以及过滤器语法规范 docs-website/docs/concepts/metadata-filtering.mdx。
【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考