跳到主要内容
Couchbase 是一款屡获殊荣的分布式 NoSQL 云数据库,为您的所有云、移动、AI 和边缘计算应用程序提供无与伦比的多功能性、性能、可扩展性和财务价值。Couchbase 通过为开发人员提供编码协助和为其应用程序提供向量搜索来拥抱 AI。 向量搜索是 Couchbase 中全文搜索服务(搜索服务)的一部分。 本教程介绍了如何在 Couchbase 中使用向量搜索。您可以使用 Couchbase Capella 和您的自管 Couchbase Server。

安装

您将需要 couchbase 和 langchain 社区版才能使用 couchbase 向量存储。在本教程中,我们将使用 OpenAI 嵌入
npm
npm install couchbase @langchain/openai @langchain/community @langchain/core

创建 Couchbase 连接对象

我们首先创建一个到 Couchbase 集群的连接,然后将集群对象传递给向量存储。在这里,我们使用用户名和密码进行连接。您也可以使用任何其他受支持的方式连接到您的集群。 有关连接到 Couchbase 集群的更多信息,请查看 Node SDK 文档
import { Cluster } from "couchbase";

const connectionString = "couchbase://"; // or couchbases:// if you are using TLS
const dbUsername = "Administrator"; // valid database user with read access to the bucket being queried
const dbPassword = "Password"; // password for the database user

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

创建搜索索引

目前,搜索索引需要通过 Couchbase Capella 或 Server UI 或使用 REST 接口创建。 在本例中,我们将在 UI 的搜索服务上使用导入索引功能。 让我们在测试存储桶上定义一个名为 vector-index 的搜索索引。我们正在 testing 存储桶的 _default 范围的 _default 集合上定义一个索引,其中向量字段设置为 embedding,维度为 1536,文本字段设置为 text。我们还在文档中索引和存储 metadata 下的所有字段作为动态映射,以适应不同的文档结构。相似性度量设置为 dot_product

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

  • Couchbase Server
    • 点击 搜索 -> 添加索引 -> 导入
    • 在导入屏幕中复制以下索引定义
    • 点击创建索引以创建索引。
  • Couchbase Capella
    • 将以下索引定义复制到一个新文件 index.json
    • 使用文档中的说明将文件导入到 Capella 中。
    • 点击创建索引以创建索引。

索引定义

{
  "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, // embeddings object to create embeddings from text
  couchbaseConfig
);

基本向量搜索示例

以下示例展示了如何使用 couchbase 向量搜索并执行相似性搜索。在本例中,我们将通过 TextLoader 加载“state_of_the_union.txt”文件,将文本分成 500 个字符的块,没有重叠,并将所有这些块索引到 Couchbase 中。 数据索引后,我们执行一个简单的查询,以查找与查询“总统对 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/classic/document_loaders/fs/text";
import { CharacterTextSplitter } from "@langchain/textsplitters";

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

// Load documents from file
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",
});

// Open AI API Key is required to use OpenAIEmbeddings, some other embeddings may also be used
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("resulting documents: ", resultsSimilaritySearch[0]);

// Similarity Search With Score
const resultsSimilaritySearchWithScore = await store.similaritySearchWithScore(
  query,
  1
);
console.log("resulting documents: ", resultsSimilaritySearchWithScore[0][0]);
console.log("resulting scores: ", resultsSimilaritySearchWithScore[0][1]);

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

指定要返回的字段

您可以使用搜索筛选器中的 fields 参数指定要从文档返回的字段。这些字段作为 metadata 对象的一部分返回。您可以获取索引中存储的任何字段。文档的 textKey 作为文档的 pageContent 的一部分返回。 如果您未指定要获取的任何字段,则返回索引中存储的所有字段。 如果您想获取元数据中的某个字段,您需要使用 . 指定它。例如,要获取元数据中的 source 字段,您需要使用 metadata.source
const result = await store.similaritySearch(query, 1, {
  fields: ["metadata.source"],
});
console.log(result[0]);
Couchbase 允许您通过将向量搜索结果与文档的非向量字段(如 metadata 对象)的搜索相结合来进行混合搜索。 结果将基于向量搜索和全文搜索服务支持的搜索结果的组合。每个组件搜索的分数相加得到结果的总分数。 要执行混合搜索,fields 参数中有一个可选键 searchOptions,可以传递给所有相似性搜索。searchOptions 的不同搜索/查询可能性可以在此处找到。 为了模拟混合搜索,让我们从现有文档中创建一些随机元数据。我们统一地向元数据中添加三个字段:介于 2010 年和 2020 年之间的 date,介于 1 到 5 之间的 rating,以及设置为 John Doe 或 Jane Doe 的 author。我们还将声明一些示例查询。
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 中,您需要进入“高级模式”,然后在“常规设置”的 V 形箭头下,您可以选中“[X] 存储动态字段”或“[X] 索引动态字段”。
  • 在 Couchbase Server 中,在索引编辑器(非快速编辑器)的“高级”V 形箭头下,您可以选中“[X] 存储动态字段”或“[X] 索引动态字段”。
请注意,这些选项会增加索引的大小。 有关动态映射的更多详细信息,请参阅文档

问题:我的搜索结果中无法看到元数据对象。

这很可能是由于文档中的 metadata 字段未被 Couchbase 搜索索引编入索引和/或存储。为了将文档中的 metadata 字段编入索引,您需要将其作为子映射添加到索引中。 如果您选择映射映射中的所有字段,您将能够通过所有元数据字段进行搜索。或者,为了优化索引,您可以选择要编入索引的 metadata 对象中的特定字段。您可以参考文档了解有关索引子映射的更多信息。 要创建子映射,您可以参考以下文档 -
以编程方式连接这些文档到 Claude、VSCode 等,通过 MCP 获取实时答案。
© . This site is unofficial and not affiliated with LangChain, Inc.