UNPKG

@langchain/community

Version:
1 lines • 30.6 kB
{"version":3,"file":"couchbase_search.cjs","names":["VectorStore","embedding: EmbeddingsInterface","config: CouchbaseSearchVectorStoreArgs","embeddings: EmbeddingsInterface","scopeCollectionMap: Record<string, any>","fields: any","metadataFields: { [key: string]: any }","queryEmbeddings: number[]","filter: CouchbaseSearchVectorStoreFilter","SearchRequest","VectorSearch","VectorQuery","docsWithScore: [Document, number][]","Document","query: string","documentsToInsert: {\n [x: string]: any;\n }[]","successfulDocIds: string[]","vectors: number[][]","documents: Document[]","options: AddVectorOptions","ids: string[] | undefined","metadata: any","id: string","index: number","docIds: string[]","texts: string[]","metadatas: any","ids: string[]"],"sources":["../../src/vectorstores/couchbase_search.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable import/no-extraneous-dependencies */\nimport { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport {\n Bucket,\n Cluster,\n Collection,\n Scope,\n SearchRequest,\n VectorQuery,\n VectorSearch,\n} from \"couchbase\";\nimport { Document } from \"@langchain/core/documents\";\nimport { v4 as uuid } from \"uuid\";\n\n/**\n * This interface define the optional fields for adding vector\n * - `ids` - vector of ids for each document. If undefined, then uuid will be used\n * - `metadata` - vector of metadata object for each document\n */\nexport interface AddVectorOptions {\n ids?: string[];\n metadata?: Record<string, any>[];\n}\n\n/**\n * This interface defines the fields required to initialize a vector store\n * These are the fields part of config:\n * @property {Cluster} cluster - The Couchbase cluster that the store will interact with.\n * @property {string} bucketName - The name of the bucket in the Couchbase cluster.\n * @property {string} scopeName - The name of the scope within the bucket.\n * @property {string} collectionName - The name of the collection within the scope.\n * @property {string} indexName - The name of the index to be used for vector search.\n * @property {string} textKey - The key to be used for text in the documents. Defaults to \"text\".\n * @property {string} embeddingKey - The key to be used for embeddings in the documents. Defaults to \"embedding\".\n * @property {boolean} scopedIndex - Whether to use a scoped index for vector search. Defaults to true.\n * @property {AddVectorOptions} addVectorOptions - Options for adding vectors with specific id/metadata\n */\nexport interface CouchbaseSearchVectorStoreArgs {\n cluster: Cluster;\n bucketName: string;\n scopeName: string;\n collectionName: string;\n indexName: string;\n textKey?: string;\n embeddingKey?: string;\n scopedIndex?: boolean;\n addVectorOptions?: AddVectorOptions;\n}\n\n/**\n * This type defines the search filters used in couchbase vector search\n * - `fields`: Optional list of fields to include in the\n * metadata of results. Note that these need to be stored in the index.\n * If nothing is specified, defaults to all the fields stored in the index.\n * - `searchOptions`: Optional search options that are passed to Couchbase search. Defaults to empty object.\n */\ntype CouchbaseSearchVectorStoreFilter = {\n fields?: any;\n searchOptions?: any;\n};\n\n/**\n * Class for interacting with the Couchbase database. It extends the\n * VectorStore class and provides methods for adding vectors and\n * documents, and searching for similar vectors.\n * Initiate the class using initialize() method.\n */\nexport class CouchbaseSearchVectorStore extends VectorStore {\n declare FilterType: CouchbaseSearchVectorStoreFilter;\n\n private metadataKey = \"metadata\";\n\n private readonly defaultTextKey = \"text\";\n\n private readonly defaultScopedIndex = true;\n\n private readonly defaultEmbeddingKey = \"embedding\";\n\n private cluster: Cluster;\n\n private _bucket: Bucket;\n\n private _scope: Scope;\n\n private _collection: Collection;\n\n private bucketName: string;\n\n private scopeName: string;\n\n private collectionName: string;\n\n private indexName: string;\n\n private textKey = this.defaultTextKey;\n\n private embeddingKey = this.defaultEmbeddingKey;\n\n private scopedIndex: boolean;\n\n /**\n * The private constructor used to provide embedding to parent class.\n * Initialize the class using static initialize() method\n * @param embedding - object to generate embedding\n * @param config - the fields required to initialize a vector store\n */\n private constructor(\n embedding: EmbeddingsInterface,\n config: CouchbaseSearchVectorStoreArgs\n ) {\n super(embedding, config);\n }\n\n /**\n * initialize class for interacting with the Couchbase database.\n * It extends the VectorStore class and provides methods\n * for adding vectors and documents, and searching for similar vectors.\n * This also verifies the params\n *\n * @param embeddings - object to generate embedding\n * @param config - the fields required to initialize a vector store\n */\n static async initialize(\n embeddings: EmbeddingsInterface,\n config: CouchbaseSearchVectorStoreArgs\n ) {\n const store = new CouchbaseSearchVectorStore(embeddings, config);\n\n const {\n cluster,\n bucketName,\n scopeName,\n collectionName,\n indexName,\n textKey,\n embeddingKey,\n scopedIndex,\n } = config;\n\n store.cluster = cluster;\n store.bucketName = bucketName;\n store.scopeName = scopeName;\n store.collectionName = collectionName;\n store.indexName = indexName;\n if (textKey) {\n store.textKey = textKey;\n } else {\n store.textKey = store.defaultTextKey;\n }\n\n if (embeddingKey) {\n store.embeddingKey = embeddingKey;\n } else {\n store.embeddingKey = store.defaultEmbeddingKey;\n }\n\n if (scopedIndex !== undefined) {\n store.scopedIndex = scopedIndex;\n } else {\n store.scopedIndex = store.defaultScopedIndex;\n }\n\n try {\n store._bucket = store.cluster.bucket(store.bucketName);\n store._scope = store._bucket.scope(store.scopeName);\n store._collection = store._scope.collection(store.collectionName);\n } catch {\n throw new Error(\n \"Error connecting to couchbase, Please check connection and credentials\"\n );\n }\n\n try {\n if (\n !(await store.checkBucketExists()) ||\n !(await store.checkIndexExists()) ||\n !(await store.checkScopeAndCollectionExists())\n ) {\n throw new Error(\"Error while initializing vector store\");\n }\n } catch (err) {\n throw new Error(`Error while initializing vector store: ${err}`);\n }\n return store;\n }\n\n /**\n * An asynchrononous method to verify the search indexes.\n * It retrieves all indexes and checks if specified index is present.\n *\n * @throws - If the specified index does not exist in the database.\n *\n * @returns - returns promise true if no error is found\n */\n private async checkIndexExists(): Promise<boolean> {\n if (this.scopedIndex) {\n const allIndexes = await this._scope.searchIndexes().getAllIndexes();\n const indexNames = allIndexes.map((index) => index.name);\n if (!indexNames.includes(this.indexName)) {\n throw new Error(\n `Index ${this.indexName} does not exist. Please create the index before searching.`\n );\n }\n } else {\n const allIndexes = await this.cluster.searchIndexes().getAllIndexes();\n const indexNames = allIndexes.map((index) => index.name);\n if (!indexNames.includes(this.indexName)) {\n throw new Error(\n `Index ${this.indexName} does not exist. Please create the index before searching.`\n );\n }\n }\n return true;\n }\n\n /**\n * An asynchronous method to verify the existence of a bucket.\n * It retrieves the bucket using the bucket manager and checks if the specified bucket is present.\n *\n * @throws - If the specified bucket does not exist in the database.\n *\n * @returns - Returns a promise that resolves to true if no error is found, indicating the bucket exists.\n */\n private async checkBucketExists(): Promise<boolean> {\n const bucketManager = this.cluster.buckets();\n try {\n await bucketManager.getBucket(this.bucketName);\n return true;\n } catch {\n throw new Error(\n `Bucket ${this.bucketName} does not exist. Please create the bucket before searching.`\n );\n }\n }\n\n /**\n * An asynchronous method to verify the existence of a scope and a collection within that scope.\n * It retrieves all scopes and collections in the bucket, and checks if the specified scope and collection are present.\n *\n * @throws - If the specified scope does not exist in the bucket, or if the specified collection does not exist in the scope.\n *\n * @returns - Returns a promise that resolves to true if no error is found, indicating the scope and collection exist.\n */\n private async checkScopeAndCollectionExists(): Promise<boolean> {\n const scopeCollectionMap: Record<string, any> = {};\n\n // Get a list of all scopes in the bucket\n const scopes = await this._bucket.collections().getAllScopes();\n for (const scope of scopes) {\n scopeCollectionMap[scope.name] = [];\n\n // Get a list of all the collections in the scope\n for (const collection of scope.collections) {\n scopeCollectionMap[scope.name].push(collection.name);\n }\n }\n\n // Check if the scope exists\n if (!Object.keys(scopeCollectionMap).includes(this.scopeName)) {\n throw new Error(\n `Scope ${this.scopeName} not found in Couchbase bucket ${this.bucketName}`\n );\n }\n\n // Check if the collection exists in the scope\n if (!scopeCollectionMap[this.scopeName].includes(this.collectionName)) {\n throw new Error(\n `Collection ${this.collectionName} not found in scope ${this.scopeName} in Couchbase bucket ${this.bucketName}`\n );\n }\n return true;\n }\n\n _vectorstoreType(): string {\n return \"couchbase-search\";\n }\n\n /**\n * Formats couchbase metadata by removing `metadata.` from initials\n * @param fields - all the fields of row\n * @returns - formatted metadata fields\n */\n private formatMetadata = (fields: any) => {\n const fieldsCopy = { ...fields };\n delete fieldsCopy[this.textKey];\n const metadataFields: { [key: string]: any } = {};\n for (const key in fieldsCopy) {\n if (Object.prototype.hasOwnProperty.call(fieldsCopy, key)) {\n const newKey = key.replace(`${this.metadataKey}.`, \"\");\n metadataFields[newKey] = fieldsCopy[key];\n }\n }\n return metadataFields;\n };\n\n /**\n * Performs a similarity search on the vectors in the Couchbase database and returns the documents and their corresponding scores.\n *\n * @param queryEmbeddings - Embedding vector to look up documents similar to.\n * @param k - Number of documents to return. Defaults to 4.\n * @param filter - Optional search filter that are passed to Couchbase search. Defaults to empty object.\n * - `fields`: Optional list of fields to include in the\n * metadata of results. Note that these need to be stored in the index.\n * If nothing is specified, defaults to all the fields stored in the index.\n * - `searchOptions`: Optional search options that are passed to Couchbase search. Defaults to empty object.\n *\n * @returns - Promise of list of [document, score] that are the most similar to the query vector.\n *\n * @throws If the search operation fails.\n */\n async similaritySearchVectorWithScore(\n queryEmbeddings: number[],\n k = 4,\n filter: CouchbaseSearchVectorStoreFilter = {}\n ): Promise<[Document, number][]> {\n let { fields } = filter;\n const { searchOptions } = filter;\n\n if (!fields) {\n fields = [\"*\"];\n }\n if (\n !(fields.length === 1 && fields[0] === \"*\") &&\n !fields.includes(this.textKey)\n ) {\n fields.push(this.textKey);\n }\n\n const searchRequest = new SearchRequest(\n VectorSearch.fromVectorQuery(\n new VectorQuery(this.embeddingKey, queryEmbeddings).numCandidates(k)\n )\n );\n\n let searchIterator;\n const docsWithScore: [Document, number][] = [];\n try {\n if (this.scopedIndex) {\n searchIterator = this._scope.search(this.indexName, searchRequest, {\n limit: k,\n fields,\n raw: searchOptions,\n });\n } else {\n searchIterator = this.cluster.search(this.indexName, searchRequest, {\n limit: k,\n fields,\n raw: searchOptions,\n });\n }\n\n const searchRows = (await searchIterator).rows;\n for (const row of searchRows) {\n const text = row.fields[this.textKey];\n const metadataFields = this.formatMetadata(row.fields);\n const searchScore = row.score;\n const doc = new Document({\n pageContent: text,\n metadata: metadataFields,\n });\n docsWithScore.push([doc, searchScore]);\n }\n } catch (err) {\n console.log(\"error received\");\n throw new Error(`Search failed with error: ${err}`);\n }\n return docsWithScore;\n }\n\n /**\n * Return documents that are most similar to the vector embedding.\n *\n * @param queryEmbeddings - Embedding to look up documents similar to.\n * @param k - The number of similar documents to return. Defaults to 4.\n * @param filter - Optional search filter that are passed to Couchbase search. Defaults to empty object.\n * - `fields`: Optional list of fields to include in the\n * metadata of results. Note that these need to be stored in the index.\n * If nothing is specified, defaults to all the fields stored in the index.\n * - `searchOptions`: Optional search options that are passed to Couchbase search. Defaults to empty object.\n *\n * @returns - A promise that resolves to an array of documents that match the similarity search.\n */\n async similaritySearchByVector(\n queryEmbeddings: number[],\n k = 4,\n filter: CouchbaseSearchVectorStoreFilter = {}\n ): Promise<Document[]> {\n const docsWithScore = await this.similaritySearchVectorWithScore(\n queryEmbeddings,\n k,\n filter\n );\n const docs = [];\n for (const doc of docsWithScore) {\n docs.push(doc[0]);\n }\n return docs;\n }\n\n /**\n * Return documents that are most similar to the query.\n *\n * @param query - Query to look up for similar documents\n * @param k - The number of similar documents to return. Defaults to 4.\n * @param filter - Optional search filter that are passed to Couchbase search. Defaults to empty object.\n * - `fields`: Optional list of fields to include in the\n * metadata of results. Note that these need to be stored in the index.\n * If nothing is specified, defaults to all the fields stored in the index.\n * - `searchOptions`: Optional search options that are passed to Couchbase search. Defaults to empty object.\n *\n * @returns - Promise of list of documents that are most similar to the query.\n */\n async similaritySearch(\n query: string,\n k = 4,\n filter: CouchbaseSearchVectorStoreFilter = {}\n ): Promise<Document[]> {\n const queryEmbeddings = await this.embeddings.embedQuery(query);\n const docsWithScore = await this.similaritySearchVectorWithScore(\n queryEmbeddings,\n k,\n filter\n );\n const docs = [];\n for (const doc of docsWithScore) {\n docs.push(doc[0]);\n }\n return docs;\n }\n\n /**\n * Return documents that are most similar to the query with their scores.\n *\n * @param query - Query to look up for similar documents\n * @param k - The number of similar documents to return. Defaults to 4.\n * @param filter - Optional search filter that are passed to Couchbase search. Defaults to empty object.\n * - `fields`: Optional list of fields to include in the\n * metadata of results. Note that these need to be stored in the index.\n * If nothing is specified, defaults to all the fields stored in the index.\n * - `searchOptions`: Optional search options that are passed to Couchbase search. Defaults to empty object.\n *\n * @returns - Promise of list of documents that are most similar to the query.\n */\n async similaritySearchWithScore(\n query: string,\n k = 4,\n filter: CouchbaseSearchVectorStoreFilter = {}\n ): Promise<[Document, number][]> {\n const queryEmbeddings = await this.embeddings.embedQuery(query);\n const docsWithScore = await this.similaritySearchVectorWithScore(\n queryEmbeddings,\n k,\n filter\n );\n return docsWithScore;\n }\n\n /**\n * upsert documents asynchronously into a couchbase collection\n * @param documentsToInsert Documents to be inserted into couchbase collection with embeddings, original text and metadata\n * @returns DocIds of the inserted documents\n */\n private async upsertDocuments(\n documentsToInsert: {\n [x: string]: any;\n }[]\n ) {\n // Create promises for each document to be upserted\n const upsertDocumentsPromises = documentsToInsert.map((document) => {\n const currentDocumentKey = Object.keys(document)[0];\n return this._collection\n .upsert(currentDocumentKey, document[currentDocumentKey])\n .then(() => currentDocumentKey)\n .catch((e) => {\n console.error(\"error received while upserting document\", e);\n throw new Error(`Upsert failed with error: ${e}`);\n });\n });\n\n try {\n // Upsert all documents asynchronously\n const docIds = await Promise.all(upsertDocumentsPromises);\n const successfulDocIds: string[] = [];\n for (const id of docIds) {\n if (id) {\n successfulDocIds.push(id);\n }\n }\n return successfulDocIds;\n } catch (e) {\n console.error(\n \"An error occurred with Promise.all at upserting all documents\",\n e\n );\n throw e;\n }\n }\n\n /**\n * Add vectors and corresponding documents to a couchbase collection\n * If the document IDs are passed, the existing documents (if any) will be\n * overwritten with the new ones.\n * @param vectors - The vectors to be added to the collection.\n * @param documents - The corresponding documents to be added to the collection.\n * @param options - Optional parameters for adding vectors.\n * This may include the IDs and metadata of the documents to be added. Defaults to an empty object.\n *\n * @returns - A promise that resolves to an array of document IDs that were added to the collection.\n */\n public async addVectors(\n vectors: number[][],\n documents: Document[],\n options: AddVectorOptions = {}\n ): Promise<string[]> {\n // Get document ids. if ids are not available then use UUIDs for each document\n let ids: string[] | undefined = options ? options.ids : undefined;\n if (ids === undefined) {\n ids = Array.from({ length: documents.length }, () => uuid());\n }\n\n // Get metadata for each document. if metadata is not available, use empty object for each document\n let metadata: any = options ? options.metadata : undefined;\n if (metadata === undefined) {\n metadata = Array.from({ length: documents.length }, () => ({}));\n }\n\n const documentsToInsert = ids.map((id: string, index: number) => ({\n [id]: {\n [this.textKey]: documents[index].pageContent,\n [this.embeddingKey]: vectors[index],\n [this.metadataKey]: metadata[index],\n },\n }));\n\n let docIds: string[] = [];\n try {\n docIds = await this.upsertDocuments(documentsToInsert);\n } catch (err) {\n console.error(\"Error while adding vectors\", err);\n throw err;\n }\n\n return docIds;\n }\n\n /**\n * Run texts through the embeddings and persist in vectorstore.\n * If the document IDs are passed, the existing documents (if any) will be\n * overwritten with the new ones.\n * @param documents - The corresponding documents to be added to the collection.\n * @param options - Optional parameters for adding documents.\n * This may include the IDs and metadata of the documents to be added. Defaults to an empty object.\n *\n * @returns - A promise that resolves to an array of document IDs that were added to the collection.\n */\n public async addDocuments(\n documents: Document[],\n options: AddVectorOptions = {}\n ) {\n const texts = documents.map(({ pageContent }) => pageContent);\n const metadatas = documents.map((doc) => doc.metadata);\n const optionsWithMetadata = {\n ...options,\n metadata: options.metadata ?? metadatas,\n };\n return this.addVectors(\n await this.embeddings.embedDocuments(texts),\n documents,\n optionsWithMetadata\n );\n }\n\n /**\n * Create a new CouchbaseVectorStore from a set of documents.\n * This function will initialize a new store, add the documents to it, and then return the store.\n * @param documents - The documents to be added to the new store.\n * @param embeddings - The embeddings to be used for the documents.\n * @param config - The configuration for the new CouchbaseVectorStore. This includes the options for adding vectors.\n *\n * @returns - A promise that resolves to the new CouchbaseVectorStore that contains the added documents.\n */\n static async fromDocuments(\n documents: Document[],\n embeddings: EmbeddingsInterface,\n config: CouchbaseSearchVectorStoreArgs\n ): Promise<CouchbaseSearchVectorStore> {\n const store = await this.initialize(embeddings, config);\n await store.addDocuments(documents, config.addVectorOptions);\n return store;\n }\n\n /**\n * Create a new CouchbaseVectorStore from a set of texts.\n * This function will convert each text and its corresponding metadata into a Document,\n * initialize a new store, add the documents to it, and then return the store.\n * @param texts - The texts to be converted into Documents and added to the new store.\n * @param metadatas - The metadata for each text. If an array is passed, each text will have its corresponding metadata.\n * If not, all texts will have the same metadata.\n * @param embeddings - The embeddings to be used for the documents.\n * @param config - The configuration for the new CouchbaseVectorStore. This includes the options for adding vectors.\n *\n * @returns - A promise that resolves to the new CouchbaseVectorStore that contains the added documents.\n */\n static async fromTexts(\n texts: string[],\n metadatas: any,\n embeddings: EmbeddingsInterface,\n config: CouchbaseSearchVectorStoreArgs\n ): Promise<CouchbaseSearchVectorStore> {\n const docs = [];\n\n for (let i = 0; i < texts.length; i += 1) {\n const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n const newDoc = new Document({\n pageContent: texts[i],\n metadata,\n });\n docs.push(newDoc);\n }\n return await this.fromDocuments(docs, embeddings, config);\n }\n\n /**\n * Delete documents asynchronously from the collection.\n * This function will attempt to remove each document in the provided list of IDs from the collection.\n * If an error occurs during the deletion of a document, an error will be thrown with the ID of the document and the error message.\n * @param ids - An array of document IDs to be deleted from the collection.\n *\n * @returns - A promise that resolves when all documents have been attempted to be deleted. If a document could not be deleted, an error is thrown.\n */\n public async delete(ids: string[]): Promise<void> {\n const deleteDocumentsPromises = ids.map((id) =>\n this._collection.remove(id).catch((err) => {\n throw new Error(\n `Error while deleting document - Document Id: ${id}, Error: ${err}`\n );\n })\n );\n try {\n await Promise.all(deleteDocumentsPromises);\n } catch (err) {\n throw new Error(`Error while deleting documents, Error: ${err}`);\n }\n }\n}\n"],"mappings":"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"}