UNPKG

@langchain/community

Version:
1 lines • 20.4 kB
{"version":3,"file":"cassandra.cjs","names":["VectorStore","args: CassandraLibArgs","value: T | T[]","primaryKeyArg: Column[]","nonKeyColumnsArg: Column[]","defaultColumn: Column","columns: Column | Column[]","columnName: string","embeddings: EmbeddingsInterface","CassandraTable","vectors: number[][]","documents: Document[]","query: number[]","k: number","filter?: WhereClause","includeEmbedding?: boolean","orderBy: Filter","Document","query: string","options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>","texts: string[]","metadatas: object | object[]","docs: Document[]"],"sources":["../../src/vectorstores/cassandra.ts"],"sourcesContent":["import { v4 as uuidv4 } from \"uuid\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport {\n VectorStore,\n MaxMarginalRelevanceSearchOptions,\n} from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\nimport { maximalMarginalRelevance } from \"@langchain/core/utils/math\";\n\nimport {\n CassandraClientArgs,\n Column,\n Filter,\n WhereClause,\n CassandraTableArgs,\n CassandraTable,\n} from \"../utils/cassandra.js\";\n\nexport type SupportedVectorTypes = \"cosine\" | \"dot_product\" | \"euclidean\";\n\nexport interface CassandraLibArgs\n extends CassandraClientArgs,\n Omit<CassandraTableArgs, \"nonKeyColumns\" | \"keyspace\"> {\n // keyspace is optional on CassandraClientArgs, but mandatory on CassandraTableArgs; we make it mandatory here\n keyspace: string;\n vectorType?: SupportedVectorTypes;\n dimensions: number;\n metadataColumns?: Column[];\n nonKeyColumns?: Column | Column[];\n}\n\n/**\n * Class for interacting with the Cassandra database. It extends the\n * VectorStore class and provides methods for adding vectors and\n * documents, searching for similar vectors, and creating instances from\n * texts or documents.\n */\nexport class CassandraStore extends VectorStore {\n declare FilterType: WhereClause;\n\n private readonly table: CassandraTable;\n\n private readonly idColumnAutoName = \"id\";\n\n private readonly idColumnAutoGenerated: boolean;\n\n private readonly vectorColumnName = \"vector\";\n\n private readonly vectorColumn: Column;\n\n private readonly textColumnName = \"text\";\n\n private readonly textColumn: Column;\n\n private readonly metadataColumnDefaultName = \"metadata\";\n\n private readonly metadataColumns: Column[];\n\n private readonly similarityColumn: Column;\n\n private readonly embeddingColumnAlias = \"embedding\";\n\n _vectorstoreType(): string {\n return \"cassandra\";\n }\n\n private _cleanArgs(\n args: CassandraLibArgs\n ): CassandraLibArgs & { metadataColumns: Column[]; nonKeyColumns: Column[] } {\n const {\n table,\n dimensions,\n primaryKey,\n nonKeyColumns,\n indices,\n metadataColumns,\n vectorType = \"cosine\",\n } = args;\n\n if (!table || !dimensions) {\n throw new Error(\"Missing required arguments\");\n }\n\n // Utility function to ensure the argument is treated as an array\n function _toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n }\n\n const indicesArg = indices || [];\n\n // Use the primary key if provided, else default to a single auto-generated UUID column\n let primaryKeyArg: Column[];\n if (primaryKey) {\n primaryKeyArg = _toArray(primaryKey);\n } else {\n primaryKeyArg = [\n { name: this.idColumnAutoName, type: \"uuid\", partition: true },\n ];\n }\n\n // The combined nonKeyColumns and metadataColumns, de-duped by name\n const combinedColumns = [\n ..._toArray(nonKeyColumns || []),\n ..._toArray(metadataColumns || []),\n ];\n\n const deduplicatedColumns = combinedColumns.filter(\n (col, index, self) => self.findIndex((c) => c.name === col.name) === index\n );\n\n const nonKeyColumnsArg: Column[] = [...deduplicatedColumns];\n\n // If no metadata columns are specified, add a default metadata column consistent with Langchain Python\n if (nonKeyColumnsArg.length === 0) {\n nonKeyColumnsArg.push({\n name: this.metadataColumnDefaultName,\n type: \"map<text, text>\",\n });\n indicesArg.push({\n name: `idx_${this.metadataColumnDefaultName}_${table}_keys`,\n value: `(keys(${this.metadataColumnDefaultName}))`,\n });\n indicesArg.push({\n name: `idx_${this.metadataColumnDefaultName}_${table}_entries`,\n value: `(entries(${this.metadataColumnDefaultName}))`,\n });\n }\n\n const addDefaultNonKeyColumnIfNeeded = (defaultColumn: Column) => {\n const column = nonKeyColumnsArg.find(\n (col) => col.name === defaultColumn.name\n );\n if (!column) {\n nonKeyColumnsArg.push(defaultColumn);\n }\n };\n\n addDefaultNonKeyColumnIfNeeded({ name: this.textColumnName, type: \"text\" });\n addDefaultNonKeyColumnIfNeeded({\n name: this.vectorColumnName,\n type: `VECTOR<FLOAT,${dimensions}>`,\n alias: this.embeddingColumnAlias,\n });\n\n // If no index is specified for the vector column, add a default index\n if (\n !indicesArg.some((index) =>\n new RegExp(`\\\\(\\\\s*${this.vectorColumnName.toLowerCase()}\\\\s*\\\\)`).test(\n index.value.toLowerCase()\n )\n )\n ) {\n indicesArg.push({\n name: `idx_${this.vectorColumnName}_${table}`,\n value: `(${this.vectorColumnName})`,\n options: `{'similarity_function': '${vectorType.toLowerCase()}'}`,\n });\n }\n\n // Metadata the user will see excludes vector column and text column\n const metadataColumnsArg = [...primaryKeyArg, ...nonKeyColumnsArg].filter(\n (column) =>\n column.name !== this.vectorColumnName &&\n column.name !== this.textColumnName\n );\n\n return {\n ...args,\n vectorType,\n primaryKey: primaryKeyArg,\n nonKeyColumns: nonKeyColumnsArg,\n metadataColumns: metadataColumnsArg,\n indices: indicesArg,\n };\n }\n\n private _getColumnByName(\n columns: Column | Column[],\n columnName: string\n ): Column {\n const columnsArray = Array.isArray(columns) ? columns : [columns];\n const column = columnsArray.find((col) => col.name === columnName);\n if (!column) {\n throw new Error(`Column ${columnName} not found`);\n }\n return column;\n }\n\n constructor(embeddings: EmbeddingsInterface, args: CassandraLibArgs) {\n super(embeddings, args);\n\n const cleanedArgs = this._cleanArgs(args);\n\n // This check here to help the compiler understand that nonKeyColumns will always\n // have values after the _cleanArgs call. It is the cleanest way to handle the fact\n // that the compiler is not able to make this determination, no matter how hard we try!\n if (!cleanedArgs.nonKeyColumns || cleanedArgs.nonKeyColumns.length === 0) {\n throw new Error(\"No non-key columns provided\");\n }\n\n this.vectorColumn = this._getColumnByName(\n cleanedArgs.nonKeyColumns,\n this.vectorColumnName\n );\n this.textColumn = this._getColumnByName(\n cleanedArgs.nonKeyColumns,\n this.textColumnName\n );\n\n this.similarityColumn = {\n name: `similarity_${cleanedArgs.vectorType}(${this.vectorColumnName},?)`,\n alias: \"similarity_score\",\n type: \"\",\n };\n this.idColumnAutoGenerated = !args.primaryKey;\n this.metadataColumns = cleanedArgs.metadataColumns;\n\n this.table = new CassandraTable(cleanedArgs);\n }\n\n /**\n * Method to save vectors to the Cassandra database.\n * @param vectors Vectors to save.\n * @param documents The documents associated with the vectors.\n * @returns Promise that resolves when the vectors have been added.\n */\n async addVectors(vectors: number[][], documents: Document[]): Promise<void> {\n if (vectors.length === 0) {\n return;\n }\n // Prepare the values for upsert\n const values = vectors.map((vector, index) => {\n const document = documents[index];\n const docMetadata = document.metadata || {};\n\n // If idColumnAutoGenerated is true and ID is not provided, generate a UUID\n if (\n this.idColumnAutoGenerated &&\n (docMetadata[this.idColumnAutoName] === undefined ||\n docMetadata[this.idColumnAutoName] === \"\")\n ) {\n docMetadata[this.idColumnAutoName] = uuidv4();\n }\n\n // Construct the row\n const row = [];\n\n // Add values for each metadata column\n this.metadataColumns.forEach((col) => {\n row.push(docMetadata[col.name] || null);\n });\n\n // Add the text content and vector\n row.push(document.pageContent);\n row.push(new Float32Array(vector));\n\n return row;\n });\n\n const columns = [\n ...this.metadataColumns,\n { name: this.textColumnName, type: \"\" },\n { name: this.vectorColumnName, type: \"\" },\n ];\n\n return this.table.upsert(values, columns);\n }\n\n getCassandraTable(): CassandraTable {\n return this.table;\n }\n\n /**\n * Method to add documents to the Cassandra database.\n * @param documents The documents to add.\n * @returns Promise that resolves when the documents have been added.\n */\n async addDocuments(documents: Document[]): Promise<void> {\n return this.addVectors(\n await this.embeddings.embedDocuments(documents.map((d) => d.pageContent)),\n documents\n );\n }\n\n /**\n * Helper method to search for vectors that are similar to a given query vector.\n * @param query The query vector.\n * @param k The number of similar Documents to return.\n * @param filter Optional filter to be applied as a WHERE clause.\n * @param includeEmbedding Whether to include the embedding vectors in the results.\n * @returns Promise that resolves with an array of tuples, each containing a Document and a score.\n */\n async search(\n query: number[],\n k: number,\n filter?: WhereClause,\n includeEmbedding?: boolean\n ): Promise<[Document, number][]> {\n const vectorAsFloat32Array = new Float32Array(query);\n\n const similarityColumnWithBinds = {\n ...this.similarityColumn,\n binds: [vectorAsFloat32Array],\n };\n\n const queryCols = [\n ...this.metadataColumns,\n this.textColumn,\n similarityColumnWithBinds,\n ];\n\n if (includeEmbedding) {\n queryCols.push(this.vectorColumn);\n }\n\n const orderBy: Filter = {\n name: this.vectorColumnName,\n operator: \"ANN OF\",\n value: [vectorAsFloat32Array],\n };\n\n const queryResultSet = await this.table.select(\n queryCols,\n filter,\n [orderBy],\n k\n );\n\n return queryResultSet?.rows.map((row) => {\n const textContent = row[this.textColumnName];\n const sanitizedRow = { ...row };\n delete sanitizedRow[this.textColumnName];\n delete sanitizedRow.similarity_score;\n\n Object.keys(sanitizedRow).forEach((key) => {\n if (sanitizedRow[key] === null) {\n delete sanitizedRow[key];\n }\n });\n\n return [\n new Document({ pageContent: textContent, metadata: sanitizedRow }),\n row.similarity_score,\n ];\n });\n }\n\n /**\n * Method to search for vectors that are similar to a given query vector.\n * @param query The query vector.\n * @param k The number of similar Documents to return.\n * @param filter Optional filter to be applied as a WHERE clause.\n * @returns Promise that resolves with an array of tuples, each containing a Document and a score.\n */\n async similaritySearchVectorWithScore(\n query: number[],\n k: number,\n filter?: WhereClause\n ): Promise<[Document, number][]> {\n return this.search(query, k, filter, false);\n }\n\n /**\n * Method to search for vectors that are similar to a given query vector, but with\n * the results selected using the maximal marginal relevance.\n * @param query The query string.\n * @param options.k The number of similar Documents to return.\n * @param options.fetchK=4*k The number of records to fetch before passing to the MMR algorithm.\n * @param options.lambda=0.5 The degree of diversity among the results between 0 (maximum diversity) and 1 (minimum diversity).\n * @param options.filter Optional filter to be applied as a WHERE clause.\n * @returns List of documents selected by maximal marginal relevance.\n */\n async maxMarginalRelevanceSearch(\n query: string,\n options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>\n ): Promise<Document[]> {\n const { k, fetchK = 4 * k, lambda = 0.5, filter } = options;\n\n const queryEmbedding = await this.embeddings.embedQuery(query);\n\n const queryResults = await this.search(\n queryEmbedding,\n fetchK,\n filter,\n true\n );\n\n const embeddingList = queryResults.map(\n (doc) => doc[0].metadata[this.embeddingColumnAlias]\n );\n\n const mmrIndexes = maximalMarginalRelevance(\n queryEmbedding,\n embeddingList,\n lambda,\n k\n );\n\n return mmrIndexes.map((idx) => {\n const doc = queryResults[idx][0];\n delete doc.metadata[this.embeddingColumnAlias];\n return doc;\n });\n }\n\n /**\n * Static method to create an instance of CassandraStore from texts.\n * @param texts The texts to use.\n * @param metadatas The metadata associated with the texts.\n * @param embeddings The embeddings to use.\n * @param args The arguments for the CassandraStore.\n * @returns Promise that resolves with a new instance of CassandraStore.\n */\n static async fromTexts(\n texts: string[],\n metadatas: object | object[],\n embeddings: EmbeddingsInterface,\n args: CassandraLibArgs\n ): Promise<CassandraStore> {\n const docs: Document[] = [];\n\n for (let index = 0; index < texts.length; index += 1) {\n const metadata = Array.isArray(metadatas) ? metadatas[index] : metadatas;\n const doc = new Document({\n pageContent: texts[index],\n metadata,\n });\n docs.push(doc);\n }\n\n return CassandraStore.fromDocuments(docs, embeddings, args);\n }\n\n /**\n * Static method to create an instance of CassandraStore from documents.\n * @param docs The documents to use.\n * @param embeddings The embeddings to use.\n * @param args The arguments for the CassandraStore.\n * @returns Promise that resolves with a new instance of CassandraStore.\n */\n static async fromDocuments(\n docs: Document[],\n embeddings: EmbeddingsInterface,\n args: CassandraLibArgs\n ): Promise<CassandraStore> {\n const instance = new this(embeddings, args);\n await instance.addDocuments(docs);\n return instance;\n }\n\n /**\n * Static method to create an instance of CassandraStore from an existing\n * index.\n * @param embeddings The embeddings to use.\n * @param args The arguments for the CassandraStore.\n * @returns Promise that resolves with a new instance of CassandraStore.\n */\n static async fromExistingIndex(\n embeddings: EmbeddingsInterface,\n args: CassandraLibArgs\n ): Promise<CassandraStore> {\n const instance = new this(embeddings, args);\n return instance;\n }\n}\n"],"mappings":"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"}