Skip to main content
Oracle AI 数据库支持通过含义(语义)而不仅仅是关键词来查询数据的 AI 工作负载。它将非结构化内容的语义搜索业务数据的关系型过滤结合在一个系统中——因此您可以构建检索工作流(如 RAG),而无需引入单独的向量数据库或将数据分散在多个平台上。 本指南演示如何使用 OracleVS(用于 Oracle AI 向量搜索的 LangChain 向量存储集成)来:
  • 将文档和嵌入向量摄入到 Oracle 中
  • 运行相似性搜索
  • 创建 HNSW 和 IVF 索引
  • 应用元数据过滤器进行高级检索
  • 在 Oracle 数据库 26ai 中启用混合搜索(关键词 + 语义)
  • 使用 Oracle Text 运行全文搜索

先决条件

安装 langchain-oracledbpython-oracledb 驱动程序将作为依赖项自动安装。
pip install -qU langchain-oracledb

连接到 Oracle 数据库

以下示例代码将展示如何连接到 Oracle 数据库。默认情况下,python-oracledb 以“Thin”模式运行,该模式直接连接到 Oracle 数据库。此模式不需要 Oracle 客户端库。但是,当 python-oracledb 使用它们时,可以使用一些额外的功能。当使用 Oracle 客户端库时,python-oracledb 被称为处于“Thick”模式。两种模式都具有全面的功能,支持 Python 数据库 API v2.0 规范。请参阅以下指南,了解每种模式支持的功能。如果您无法使用 thin 模式,可能需要切换到 thick 模式。
import oracledb

# 请更新您的用户名、密码、主机名、端口和服务名
username = "<username>"
password = "<password>"
dsn = "<hostname>:<port>/<service_name>"

connection = oracledb.connect(user=username, password=password, dsn=dsn)
print("连接成功!")

导入所需的依赖项

from langchain_oracledb.vectorstores import oraclevs
from langchain_oracledb.vectorstores.oraclevs import OracleVS
from langchain_community.vectorstores.utils import DistanceStrategy
from langchain_core.documents import Document
from langchain_huggingface import HuggingFaceEmbeddings

加载文档

# 定义一个文档列表(以下示例是来自 Oracle 概念手册的 5 个随机文档)

documents_json_list = [
    {
        "id": "cncpt_15.5.3.2.2_P4",
        "text": "如果任何先前问题的答案是“是”,则数据库停止搜索并从指定的表空间分配空间;否则,从数据库默认共享临时表空间分配空间。",
        "link": "https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/logical-storage-structures.html#GUID-5387D7B2-C0CA-4C1E-811B-C7EB9B636442",
    },
    {
        "id": "cncpt_15.5.5_P1",
        "text": "只要数据库处于打开状态,表空间可以是联机的(可访问)或脱机的(不可访问)。\n表空间通常是联机的,以便其数据可供用户使用。SYSTEM 表空间和临时表空间不能脱机。",
        "link": "https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/logical-storage-structures.html#GUID-D02B2220-E6F5-40D9-AFB5-BC69BCEF6CD4",
    },
    {
        "id": "cncpt_22.3.4.3.1_P2",
        "text": "数据库存储 LOB 的方式与其他数据类型不同。创建 LOB 列会隐式创建一个 LOB 段和一个 LOB 索引。包含 LOB 段和 LOB 索引(它们始终存储在一起)的表空间可能与包含该表的表空间不同。\n有时数据库可以将少量 LOB 数据存储在表本身中,而不是存储在单独的 LOB 段中。",
        "link": "https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/concepts-for-database-developers.html#GUID-3C50EAB8-FC39-4BB3-B680-4EACCE49E866",
    },
    {
        "id": "cncpt_22.3.4.3.1_P3",
        "text": "LOB 段以称为块的片段存储数据。块是一组逻辑上连续的数据块,是 LOB 的最小分配单元。表中的一行存储一个称为 LOB 定位器的指针,该指针指向 LOB 索引。当查询表时,数据库使用 LOB 索引来快速定位 LOB 块。",
        "link": "https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/concepts-for-database-developers.html#GUID-3C50EAB8-FC39-4BB3-B680-4EACCE49E866",
    },
]
# 创建 LangChain 文档

documents_langchain = []

for doc in documents_json_list:
    metadata = {"id": doc["id"], "link": doc["link"]}
    doc_langchain = Document(page_content=doc["text"], metadata=metadata)
    documents_langchain.append(doc_langchain)

使用不同的距离度量创建向量存储

首先,我们将创建三个向量存储,每个使用不同的距离函数。由于我们尚未在其中创建索引,它们现在只会创建表。稍后我们将使用这些向量存储来创建 HNSW 索引。要了解更多关于 Oracle AI 向量搜索支持的不同类型索引的信息,请参阅以下指南 您可以手动连接到 Oracle 数据库,您将看到三个表: Documents_DOTDocuments_COSINEDocuments_EUCLIDEAN 然后我们将创建三个额外的表 Documents_DOT_IVFDocuments_COSINE_IVFDocuments_EUCLIDEAN_IVF,这些表将用于在表上创建 IVF 索引,而不是 HNSW 索引。
# 使用不同的距离策略将文档摄入到 Oracle 向量存储中

# 当使用我们的 API 调用时,首先通过 from_documents() 使用文档子集初始化您的向量存储,
# 然后使用 add_texts() 增量添加更多文档。
# 这种方法可以防止系统过载并确保高效的文档处理。

model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")

vector_store_dot = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_DOT",
    distance_strategy=DistanceStrategy.DOT_PRODUCT,
)
vector_store_max = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_COSINE",
    distance_strategy=DistanceStrategy.COSINE,
)
vector_store_euclidean = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_EUCLIDEAN",
    distance_strategy=DistanceStrategy.EUCLIDEAN_DISTANCE,
)

# 使用不同的距离策略将文档摄入到 Oracle 向量存储中
vector_store_dot_ivf = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_DOT_IVF",
    distance_strategy=DistanceStrategy.DOT_PRODUCT,
)
vector_store_max_ivf = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_COSINE_IVF",
    distance_strategy=DistanceStrategy.COSINE,
)
vector_store_euclidean_ivf = OracleVS.from_documents(
    documents_langchain,
    model,
    client=connection,
    table_name="Documents_EUCLIDEAN_IVF",
    distance_strategy=DistanceStrategy.EUCLIDEAN_DISTANCE,
)

文本的添加和删除操作,以及基本的相似性搜索

def manage_texts(vector_stores):
    """
    向每个向量存储添加文本,演示重复添加的错误处理,
    并执行文本删除。展示每个向量存储的相似性搜索和索引创建。

    参数:
    - vector_stores (list): OracleVS 实例列表。
    """
    texts = ["Rohan", "Shailendra"]
    metadata = [
        {"id": "100", "link": "Document Example Test 1"},
        {"id": "101", "link": "Document Example Test 2"},
    ]

    for i, vs in enumerate(vector_stores, start=1):
        # 添加文本
        try:
            vs.add_texts(texts, metadata)
            print(f"\n\n\n向量存储 {i} 添加文本完成\n\n\n")
        except Exception as ex:
            print(f"\n\n\n向量存储 {i} 重复添加的预期错误\n\n\n")

        # 使用 'id' 的值删除文本
        vs.delete([metadata[0]["id"]])
        print(f"\n\n\n向量存储 {i} 删除文本完成\n\n\n")

        # 相似性搜索
        results = vs.similarity_search("LOB 在 Oracle 数据库中如何存储", 2)
        print(f"\n\n\n向量存储 {i} 的相似性搜索结果:{results}\n\n\n")


vector_store_list = [
    vector_store_dot,
    vector_store_max,
    vector_store_euclidean,
    vector_store_dot_ivf,
    vector_store_max_ivf,
    vector_store_euclidean_ivf,
]
manage_texts(vector_store_list)

使用特定参数创建索引

def create_search_indices(connection):
    """
    为向量存储创建搜索索引,每个索引都根据其距离策略定制了特定参数。
    """
    # DOT_PRODUCT 策略的索引
    # 注意我们正在使用默认参数创建 HNSW 索引
    # 这将默认创建一个具有 8 个并行工作线程的 HNSW 索引,并使用 Oracle AI 向量搜索使用的默认精度
    oraclevs.create_index(
        connection,
        vector_store_dot,
        params={"idx_name": "hnsw_idx1", "idx_type": "HNSW"},
    )

    # COSINE 策略的索引,具有特定参数
    # 注意我们正在创建一个具有 16 个并行线程且目标精度规范为 97% 的 HNSW 索引
    oraclevs.create_index(
        connection,
        vector_store_max,
        params={
            "idx_name": "hnsw_idx2",
            "idx_type": "HNSW",
            "accuracy": 97,
            "parallel": 16,
        },
    )

    # EUCLIDEAN_DISTANCE 策略的索引,具有特定参数
    # 注意我们正在通过指定高级用户参数(neighbors = 64 和 efConstruction = 100)来创建 HNSW 索引
    oraclevs.create_index(
        connection,
        vector_store_euclidean,
        params={
            "idx_name": "hnsw_idx3",
            "idx_type": "HNSW",
            "neighbors": 64,
            "efConstruction": 100,
        },
    )

    # DOT_PRODUCT 策略的索引,具有特定参数
    # 注意我们正在使用默认参数创建 IVF 索引
    # 这将默认创建一个具有 8 个并行工作线程的 IVF 索引,并使用 Oracle AI 向量搜索使用的默认精度
    oraclevs.create_index(
        connection,
        vector_store_dot_ivf,
        params={
            "idx_name": "ivf_idx1",
            "idx_type": "IVF",
        },
    )

    # COSINE 策略的索引,具有特定参数
    # 注意我们正在创建一个具有 32 个并行线程且目标精度规范为 90% 的 IVF 索引
    oraclevs.create_index(
        connection,
        vector_store_max_ivf,
        params={
            "idx_name": "ivf_idx2",
            "idx_type": "IVF",
            "accuracy": 90,
            "parallel": 32,
        },
    )

    # EUCLIDEAN_DISTANCE 策略的索引,具有特定参数
    # 注意我们正在通过指定高级用户参数 neighbor_part = 64 来创建 IVF 索引
    oraclevs.create_index(
        connection,
        vector_store_euclidean_ivf,
        params={"idx_name": "ivf_idx3", "idx_type": "IVF", "neighbor_part": 64},
    )

    print("索引创建完成。")


create_search_indices(connection)

高级搜索

Oracle 数据库 23ai 支持预过滤、过滤中和后过滤,以增强 AI 向量搜索功能。这些过滤机制允许用户在执行向量相似性搜索之前、期间和之后应用约束,从而提高搜索性能和准确性。 关于 Oracle 23ai 中过滤的关键点:
  1. 预过滤 应用传统 SQL 过滤器,在执行向量相似性搜索之前减少数据集。 通过限制 AI 算法处理的数据量来帮助提高效率。
  2. 过滤中 利用 AI 向量搜索直接在向量嵌入上执行相似性搜索,使用优化的索引和算法。 无需完整数据集扫描即可根据向量相似性高效过滤结果。
  3. 后过滤 在向量相似性搜索之后应用额外的 SQL 过滤以细化结果。 允许根据业务逻辑或额外的元数据条件进行进一步细化。
为什么这很重要?
  • 性能优化:预过滤显著减少查询执行时间,使在海量数据集上的搜索更高效。
  • 准确性增强:过滤中确保向量搜索在语义上有意义,提高搜索结果的质量。

过滤器详情

OracleVS 支持一组过滤器,可以使用 filter 参数应用于 metadata 字段。这些过滤器允许您根据各种标准选择和细化数据。 可用的过滤器运算符:
运算符描述
\$exists字段存在。
\$eq字段值等于操作数值 (=)。
\$ne字段存在且值不等于操作数值 (!=)。
\$gt字段值大于操作数值 (>)。
\$lt字段值小于操作数值 (<)。
\$gte字段值大于或等于操作数值 (>=)。
\$lte字段值小于或等于操作数值 (<=)。
\$between字段值介于操作数数组中的两个值之间(或等于)。
\$startsWith字段值以操作数值开头。
\$hasSubstring字段值包含操作数作为子字符串。
\$instr字段值包含操作数作为子字符串。
\$regex字段值匹配给定的正则表达式模式。
\$like字段值匹配操作数模式(使用类 SQL 语法)。
\$in字段值等于操作数数组中的至少一个值。
\$nin字段存在,但其值不等于操作数数组中的任何值,或者字段不存在。
\$all字段值是一个数组,包含操作数数组中的所有项,或匹配单个操作数的标量。
  • 您可以使用逻辑运算符组合这些过滤器:
逻辑运算符描述
\$and逻辑与
\$or逻辑或
\$nor逻辑或非
过滤器示例:
{
  "age": 65,
  "name": {"$regex": "*rk"},
  "$or": [
    {
      "$and": [
        {"name": "Jason"},
        {"drinks": {"$in": ["tea", "soda"]}}
      ]
    },
    {
      "$nor": [
        {"age": {"$lt": 65}},
        {"name": "Jason"}
      ]
    }
  ]
}
其他使用提示:
  • 当对象中的所有过滤器都必须满足时,您可以省略 $and。以下两种写法是等效的:
{ "$and": [
    { "name": { "$startsWith": "Fred" } },
    { "salary": { "$gt": 10000, "$lte": 20000 } }
]}
{
  "name": { "$startsWith": "Fred" },
  "salary": { "$gt": 10000, "$lte": 20000 }
}
  • $not 子句可以否定比较运算符:
{ "address.zip": { "$not": { "$eq": "90001" } } }
  • 使用 field: scalar 等同于 field: { "$eq": scalar }
{ "animal": "cat" }
有关更多过滤器示例,请参阅测试规范
# 创建索引后进行高级搜索
def conduct_advanced_searches(vector_stores):
    query = "LOB 在 Oracle 数据库中如何存储"
    # 构建一个过滤器,用于直接与文档元数据进行比较
    # 此过滤器旨在包含元数据 'id' 恰好为 '2' 的文档
    db_filter = {
        "$and": [
            {"id": "101"},  # 过滤条件
            {
                "$or": [  # 过滤组
                    {"status": "approved"},
                    {"link": "Document Example Test 2"},
                    {
                        "$and": [  # 嵌套过滤组
                            {"status": "approved"},
                            {"link": "Document Example Test 2"},
                        ]
                    },
                ]
            },
        ]
    }

    for i, vs in enumerate(vector_stores, start=1):
        print(f"\n--- 向量存储 {i} 高级搜索 ---")
        # 不带过滤器的相似性搜索
        print("\n不带过滤器的相似性搜索结果:")
        print(vs.similarity_search(query, 2))

        # 带过滤器的相似性搜索
        print("\n带过滤器的相似性搜索结果:")
        print(vs.similarity_search(query, 2, filter=db_filter))

        # 带相关性分数的相似性搜索
        print("\n带相关性分数的相似性搜索:")
        print(vs.similarity_search_with_score(query, 2))

        # 带过滤器的相关性分数相似性搜索
        print("\n带过滤器的相关性分数相似性搜索:")
        print(vs.similarity_search_with_score(query, 2, filter=db_filter))

        # 最大边际相关性搜索
        print("\n最大边际相关性搜索结果:")
        print(vs.max_marginal_relevance_search(query, 2, fetch_k=20, lambda_mult=0.5))

        # 带过滤器的最大边际相关性搜索
        print("\n带过滤器的最大边际相关性搜索结果:")
        print(
            vs.max_marginal_relevance_search(
                query, 2, fetch_k=20, lambda_mult=0.5, filter=db_filter
            )
        )


conduct_advanced_searches(vector_store_list)

混合搜索

Oracle 数据库 26ai 支持混合搜索,将关键词(全文)和语义(向量)搜索结合到单一的检索功能中。langchain-oracledb 集成公开了:
  • OracleVectorizerPreference:创建一个数据库端的向量化器偏好,供混合索引使用。
  • create_hybrid_index / acreate_hybrid_index:创建一个混合向量索引。
  • OracleHybridSearchRetriever:在 OracleVS 表上执行关键词、语义或混合检索。

先决条件和模型配置

使用混合搜索时,请使用 OracleEmbeddings 配置您的 OracleVS,以便向量化器偏好与嵌入配置完全匹配。您可以通过 OracleVectorizerPreference 提供额外参数来进一步调整混合向量索引。有关详细信息,请参阅文档
from langchain_core.documents import Document
from langchain_oracledb.embeddings import OracleEmbeddings
from langchain_oracledb.vectorstores.oraclevs import OracleVS
from langchain_oracledb.retrievers.hybrid_search import (
    OracleVectorizerPreference,
    create_hybrid_index,
    OracleHybridSearchRetriever,
)

# 使用 OracleEmbeddings(显示数据库驻留模型)
embeddings = OracleEmbeddings(conn=connection, params={"provider": "database", "model": "DB_MODEL"})

# 创建/加载您的向量存储
vs = OracleVS(connection, table_name="DOCS", embedding_function=embeddings)

# 创建一个向量化器偏好
pref = OracleVectorizerPreference.create_preference(
    vector_store=vs, preference_name="PREF_DOCS"
)

# 创建一个混合向量索引
create_hybrid_index(
    connection,
    idx_name="IDX_DOCS_HYB",
    vectorizer_preference=pref
)

# 构建检索器并搜索
retriever = OracleHybridSearchRetriever(
    vector_store=vs,
    idx_name="IDX_DOCS_HYB",
    search_mode="hybrid",     # "hybrid" | "keyword" | "semantic"
    k=5,
    return_scores=True,       # 在元数据中包含 score, text_score, vector_score
)

docs = retriever.invoke("高级套餐的退款政策")
for d in docs:
    print(d.page_content, d.metadata.get("score"), d.metadata.get("text_score"), d.metadata.get("vector_score"))

# 使用完偏好后可选清理:
# pref.drop_preference()
替代方案 在不使用显式偏好情况下创建索引:
  • 如果您不想管理命名的偏好,请改为传递 vector_store。该函数将创建一个临时偏好,构建索引,然后自动删除该偏好。
create_hybrid_index(
    connection,
    idx_name="IDX_DOCS_HYB2",
    vector_store=vs,          # 与 vectorizer_preference 互斥
    params={"parallel": 8},
)
说明和提示:
  • search_mode 决定使用哪些信号:
    • “keyword”:仅关键词
    • “semantic”:仅向量
    • “hybrid”(默认):两者结合
  • 通过检索器的 params 参数传递 DBMS_HYBRID_VECTOR 参数。
  • return_scores=True 将总体分数以及组成部分 text_score 和 vector_score 添加到 Document.metadata。
  • 通过 acreate_hybrid_indexOracleHybridSearchRetriever.ainvoke 支持异步使用。
更多信息:

全文搜索 (Oracle Text)

您可以使用 Oracle Text 直接对 Oracle 数据库运行高质量的关键词搜索。langchain-oracledb 集成公开了:
  • create_text_index / acreate_text_index:在列上创建一个 Oracle Text SEARCH INDEX
  • OracleTextSearchRetriever:运行 CONTAINS 查询并返回 LangChain Document 对象。
索引选项:
  • 如果您有一个 OracleVS 向量存储,您可以索引其内置的 “text” 列。
  • 您也可以通过直接提供 table_name + column_name 来索引任何其他表/列。
from langchain_oracledb.retrievers.text_search import create_text_index, OracleTextSearchRetriever

# 使用 OracleVS 表(索引 'text' 列)
retriever_text = None
create_text_index(
    connection,
    idx_name="IDX_DOCS_TEXT",
    vector_store=vs,
)

# 构建检索器。使用 OracleVS 时,returned_columns 默认为 ["metadata"]。
retriever_text = OracleTextSearchRetriever(
    vector_store=vs,
    k=5,
    fuzzy=True,          # 当 operator_search=False 时,对每个令牌应用 Oracle Text FUZZY
    return_scores=True,  # 将 SCORE(1) 作为 metadata["score"] 添加
)
docs = retriever_text.invoke("退款政策")
for d in docs:
    print(d.page_content, d.metadata.get("score"))

# 或者,索引任意表/列:
# create_text_index(connection, idx_name="IDX_MYDOCS_TEXT", table_name="MYDOCS", column_name="CONTENT")
# retriever_text = OracleTextSearchRetriever(client=connection, table_name="MYDOCS", column_name="CONTENT", k=5)
运算符模式和高级查询:
  • 默认行为 (operator_search=False):
    • 输入被视为字面文本,在非单词字符上分词,并重写为 ACCUM 表达式。
    • fuzzy=True 时,每个令牌被包装为 FUZZY("token") 以匹配拼写错误。
  • 运算符模式 (operator_search=True):
    • 原样传递 Oracle Text 表达式(NEARABOUTANDORNOTWITHIN 等)。在此模式下,fuzzy 被忽略。
返回的列:
  • 当针对原始表时,通过 returned_columns 在结果中包含额外的列;它们被附加到 Document.metadata
  • 使用 OracleVS 时,returned_columns 默认为 [“metadata”]。
# 运算符模式示例
retriever_text_ops = OracleTextSearchRetriever(
    vector_store=vs,
    operator_search=True,   # 直接传递 Oracle Text 表达式
    return_scores=True,
)
docs = retriever_text_ops.invoke('NEAR((policy, refund), 2, TRUE)')
说明和提示:
  • 当使用 operator_search=True 时,fuzzy 被忽略(设计如此)。
  • 通过 acreate_text_indexOracleTextSearchRetriever.ainvoke 支持异步使用。
更多信息:

端到端演示

请参阅我们完整的演示指南 Oracle AI 向量搜索端到端演示指南,以借助 Oracle AI 向量搜索构建端到端的 RAG 管道。