Skip to main content

Couchbase

Couchbase 是一个屡获殊荣的分布式 NoSQL 云数据库,为您的所有云、移动、AI 和边缘计算应用程序提供无与伦比的多功能性、性能、可扩展性和财务价值。Couchbase 拥抱 AI,为开发人员提供编码辅助和应用程序的向量搜索功能。

向量搜索是 Couchbase 中的全文搜索服务(搜索服务)的一部分。

本教程解释了如何在 Couchbase 中使用向量搜索。您可以使用 Couchbase Capella 或您自管理的 Couchbase Server。

安装

要使用 Couchbase 向量存储,您需要安装 couchbase 和 langchain 社区包。在本教程中,我们将使用 OpenAI 的嵌入:

npm install couchbase @langchain/openai @langchain/community @langchain/core

创建 Couchbase 连接对象

我们首先创建到 Couchbase 集群的连接,然后将集群对象传递给向量存储。这里我们使用用户名和密码进行连接。 您也可以使用其他支持的方式连接到您的集群。

有关连接到 Couchbase 集群的更多信息,请参阅 Node SDK 文档

import { Cluster } from "couchbase";

const connectionString = "couchbase://localhost"; // 或者如果使用 TLS 则为 couchbases://localhost
const dbUsername = "Administrator"; // 对要查询的存储桶具有读取权限的有效数据库用户
const dbPassword = "Password"; // 数据库用户的密码

const couchbaseClient = await Cluster.connect(connectionString, {
username: dbUsername,
password: dbPassword,
configProfile: "wanDevelopment",
});

创建搜索索引

目前,搜索索引需要从 Couchbase Capella 或 Server 的 UI 界面或使用 REST 接口创建。

对于本示例,让我们在 UI 的搜索服务中使用导入索引功能。

让我们在测试存储桶上定义一个名为 vector-index 的搜索索引。 我们在测试存储桶的 _default 范围的 _default 集合上定义索引,向量字段设置为 embedding,维度为 1536,文本字段设置为 text。 我们还将文档中 metadata 下的所有字段作为动态映射进行索引和存储,以适应不同的文档结构。相似度度量设置为 dot_product

如何将索引导入全文搜索服务?

  • Couchbase Server
    • 点击 Search -> Add Index -> Import
    • 在导入界面中复制以下索引定义
    • 点击 Create Index 创建索引。
  • Couchbase Capella
    • 将以下索引定义复制到新文件 index.json
    • 使用文档中的说明在 Capella 中导入文件。
    • 点击 Create Index 创建索引。

索引定义

{
"name": "vector-index",
"type": "fulltext-index",
"params": {
"doc_config": {
"docid_prefix_delim": "",
"docid_regexp": "",
"mode": "type_field",
"type_field": "type"
},
"mapping": {
"default_analyzer": "standard",
"default_datetime_parser": "dateTimeOptional",
"default_field": "_all",
"default_mapping": {
"dynamic": true,
"enabled": true,
"properties": {
"metadata": {
"dynamic": true,
"enabled": true
},
"embedding": {
"enabled": true,
"dynamic": false,
"fields": [
{
"dims": 1536,
"index": true,
"name": "embedding",
"similarity": "dot_product",
"type": "vector",
"vector_index_optimized_for": "recall"
}
]
},
"text": {
"enabled": true,
"dynamic": false,
"fields": [
{
"index": true,
"name": "text",
"store": true,
"type": "text"
}
]
}
}
},
"default_type": "_default",
"docvalues_dynamic": false,
"index_dynamic": true,
"store_dynamic": true,
"type_field": "_type"
},
"store": {
"indexType": "scorch",
"segmentVersion": 16
}
},
"sourceType": "gocbcore",
"sourceName": "testing",
"sourceParams": {},
"planParams": {
"maxPartitionsPerPIndex": 103,
"indexPartitions": 10,
"numReplicas": 0
}
}

有关如何创建支持向量字段的搜索索引的更多详细信息,请参阅文档:

要使用此向量存储,需要配置 CouchbaseVectorStoreArgs。 textKey 和 embeddingKey 是可选字段,如果您想使用特定键则需要指定:

const couchbaseConfig: CouchbaseVectorStoreArgs = {
cluster: couchbaseClient,
bucketName: "testing",
scopeName: "_default",
collectionName: "_default",
indexName: "vector-index",
textKey: "text",
embeddingKey: "embedding",
};

创建向量存储

我们使用集群信息和搜索索引名称创建向量存储对象。

const store = await CouchbaseVectorStore.initialize(
embeddings, // 用于从文本创建嵌入的嵌入对象
couchbaseConfig
);

基础向量搜索示例

以下示例展示了如何使用 Couchbase 向量搜索并执行相似性搜索。 在此示例中,我们将通过 TextLoader 加载 "state_of_the_union.txt" 文件, 将文本分成 500 个字符的块(无重叠),并将所有这些块索引到 Couchbase 中。

数据索引完成后,我们执行一个简单的查询,以找到与查询 "What did president say about Ketanji Brown Jackson" 最相似的前 4 个块。 最后,它还展示了如何获取相似性得分。

import { OpenAIEmbeddings } from "@langchain/openai";
import {
CouchbaseVectorStoreArgs,
CouchbaseVectorStore,
} from "@langchain/community/vectorstores/couchbase";
import { Cluster } from "couchbase";
import { TextLoader } from "langchain/document_loaders/fs/text";
import { CharacterTextSplitter } from "@langchain/textsplitters";

const connectionString =
process.env.COUCHBASE_DB_CONN_STR ?? "couchbase://localhost";
const databaseUsername = process.env.COUCHBASE_DB_USERNAME ?? "Administrator";
const databasePassword = process.env.COUCHBASE_DB_PASSWORD ?? "Password";

// 从文件加载文档
const loader = new TextLoader("./state_of_the_union.txt");
const rawDocuments = await loader.load();
const splitter = new CharacterTextSplitter({
chunkSize: 500,
chunkOverlap: 0,
});
const docs = await splitter.splitDocuments(rawDocuments);

const couchbaseClient = await Cluster.connect(connectionString, {
username: databaseUsername,
password: databasePassword,
configProfile: "wanDevelopment",
});

// 使用 OpenAIEmbeddings 需要 Open AI API Key,也可以使用其他嵌入
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
});

const couchbaseConfig: CouchbaseVectorStoreArgs = {
cluster: couchbaseClient,
bucketName: "testing",
scopeName: "_default",
collectionName: "_default",
indexName: "vector-index",
textKey: "text",
embeddingKey: "embedding",
};

const store = await CouchbaseVectorStore.fromDocuments(
docs,
embeddings,
couchbaseConfig
);

const query = "What did president say about Ketanji Brown Jackson";

const resultsSimilaritySearch = await store.similaritySearch(query);
console.log("结果文档: ", resultsSimilaritySearch[0]);

// 带评分的相似性搜索
const resultsSimilaritySearchWithScore = await store.similaritySearchWithScore(
query,
1
);
console.log("结果文档: ", resultsSimilaritySearchWithScore[0][0]);
console.log("结果评分: ", resultsSimilaritySearchWithScore[0][1]);

const result = await store.similaritySearch(query, 1, {
fields: ["metadata.source"],
});
console.log(result[0]);

指定返回的字段

在搜索期间,您可以通过 filter 参数中的 fields 参数指定要从文档中返回的字段。 这些字段作为 metadata 对象的一部分返回。您可以获取索引中存储的任何字段。 文档的 textKey 作为文档的 pageContent 的一部分返回。

如果您没有指定要获取的字段,则会返回索引中存储的所有字段。

如果您想获取 metadata 中的一个字段,您需要使用 . 来指定。 例如,要获取 metadata 中的 source 字段,您需要使用 metadata.source

const result = await store.similaritySearch(query, 1, {
fields: ["metadata.source"],
});
console.log(result[0]);

混合搜索

Couchbase 允许您通过将向量搜索结果与文档的非向量字段(如 metadata 对象)的搜索结果结合来进行混合搜索。

结果将基于向量搜索和全文搜索服务支持的搜索结果的组合。每个组件搜索的评分相加,得到结果的总评分。

要执行混合搜索,在所有相似性搜索中可以传递一个可选的 searchOptions 键到 fields 参数中。 searchOptions 支持的不同搜索/查询可能性可以在这里找到: Couchbase CapellaCouchbase Server

为混合搜索创建多样化的元数据

为了模拟混合搜索,让我们从现有文档中创建一些随机的元数据。 我们统一地向元数据中添加三个字段:date(2010 到 2020 年之间)、rating(1 到 5)和 author(John Doe 或 Jane Doe)。 我们还将声明几个示例查询。

for (let i = 0; i < docs.length; i += 1) {
docs[i].metadata.date = `${2010 + (i % 10)}-01-01`;
docs[i].metadata.rating = 1 + (i % 5);
docs[i].metadata.author = ["John Doe", "Jane Doe"][i % 2];
}

const store = await CouchbaseVectorStore.fromDocuments(
docs,
embeddings,
couchbaseConfig
);

const query = "What did the president say about Ketanji Brown Jackson";
const independenceQuery = "Any mention about independence?";

示例:按精确值搜索

我们可以搜索 metadata 对象中文本字段(如作者)的精确匹配。

const exactValueResult = await store.similaritySearch(query, 4, {
fields: ["metadata.author"],
searchOptions: {
query: { field: "metadata.author", match: "John Doe" },
},
});
console.log(exactValueResult[0]);

示例:按部分匹配搜索

我们可以通过为搜索指定模糊性来搜索部分匹配。当您想搜索搜索查询的轻微变体或拼写错误时,这非常有用。

在这里,"Johny" 与 "John Doe" 相似(模糊性为 1)。

const partialMatchResult = await store.similaritySearch(query, 4, {
fields: ["metadata.author"],
searchOptions: {
query: { field: "metadata.author", match: "Johny", fuzziness: 1 },
},
});
console.log(partialMatchResult[0]);

示例:按日期范围查询搜索

我们可以搜索在日期字段(如 metadata.date)上符合日期范围查询的文档。

const dateRangeResult = await store.similaritySearch(independenceQuery, 4, {
fields: ["metadata.date", "metadata.author"],
searchOptions: {
query: {
start: "2016-12-31",
end: "2017-01-02",
inclusiveStart: true,
inclusiveEnd: false,
field: "metadata.date",
},
},
});
console.log(dateRangeResult[0]);

示例:按数字范围查询搜索

我们可以搜索在数字字段(如 metadata.rating)上符合范围查询的文档。

const ratingRangeResult = await store.similaritySearch(independenceQuery, 4, {
fields: ["metadata.rating"],
searchOptions: {
query: {
min: 3,
max: 5,
inclusiveMin: false,
inclusiveMax: true,
field: "metadata.rating",
},
},
});
console.log(ratingRangeResult[0]);

示例:组合多个搜索条件

不同的查询可以通过 AND(合取)或 OR(析取)运算符组合在一起。

在此示例中,我们检查评分在 3 到 4 之间且日期在 2015 到 2018 年之间的文档。

const multipleConditionsResult = await store.similaritySearch(texts[0], 4, {
fields: ["metadata.rating", "metadata.date"],
searchOptions: {
query: {
conjuncts: [
{ min: 3, max: 4, inclusive_max: true, field: "metadata.rating" },
{ start: "2016-12-31", end: "2017-01-02", field: "metadata.date" },
],
},
},
});
console.log(multipleConditionsResult[0]);

其他查询

同样,您可以在 filter 参数的 searchOptions 键中使用任何支持的查询方法,例如地理距离、多边形搜索、通配符、正则表达式等。 有关支持的查询方法及其语法的更多详细信息,请参阅文档:



常见问题

问题:在创建 CouchbaseVectorStore 对象之前是否需要创建搜索索引?

是的,目前在创建 CouchbaseVectorStore 对象之前需要创建搜索索引。

问题:我在搜索结果中看不到我指定的所有字段。

在 Couchbase 中,我们只能返回搜索索引中存储的字段。请确保您在搜索结果中尝试访问的字段是搜索索引的一部分。

处理此问题的一种方法是在索引中动态地索引和存储文档的字段。

  • 在 Capella 中,您需要进入 "Advanced Mode",然后在 "General Settings" 下的 chevron 中勾选 "[X] Store Dynamic Fields" 或 "[X] Index Dynamic Fields"
  • 在 Couchbase Server 中,在 Index Editor(不是 Quick Editor)下的 "Advanced" chevron 中勾选 "[X] Store Dynamic Fields" 或 "[X] Index Dynamic Fields"

请注意,这些选项会增加索引的大小。

有关动态映射的更多详细信息,请参阅 文档

问题:我在搜索结果中无法看到 metadata 对象。

这很可能是由于 Couchbase 搜索索引没有对文档中的 metadata 字段进行索引和/或存储。为了对文档中的 metadata 字段进行索引,您需要将其作为子映射添加到索引中。

如果您选择映射映射中的所有字段,您将能够按所有元数据字段进行搜索。或者,为了优化索引,您可以选择 metadata 对象中的特定字段进行索引。 您可以参考文档 了解更多关于索引子映射的信息。

要创建子映射,您可以参考以下文档:

相关内容


Was this page helpful?


You can also leave detailed feedback on GitHub.