Skip to content

Commit

Permalink
fix(qdrant): Support custom payload also when using fromExistingColle…
Browse files Browse the repository at this point in the history
  • Loading branch information
Sascha Wolff committed Oct 25, 2024
1 parent a2fe51f commit 4b2d1fe
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 38 deletions.
18 changes: 7 additions & 11 deletions libs/langchain-qdrant/src/tests/vectorstores.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,12 @@ test("QdrantVectorStore adds vectors with custom payload", async () => {
});

// Define a custom payload
const customPayload = {
customPayload: [
const customPayload = [
{
customField1: "value1",
customField2: "value2",
},
],
};
];

// Add documents with custom payload
await qdrantVectorStore.addDocuments(
Expand All @@ -83,7 +81,7 @@ test("QdrantVectorStore adds vectors with custom payload", async () => {
payload: expect.objectContaining({
content: "hello",
metadata: {},
customPayload: customPayload.customPayload[0],
customPayload: customPayload[0],
}),
}),
],
Expand All @@ -109,17 +107,15 @@ test("QdrantVectorStore adds vectors with multiple custom payload", async () =>
});

// Define a custom payload
const customPayload = {
customPayload: [
const customPayload = [
{
customField1: "value1",
customField2: "value2",
},
{
customField3: "value3",
},
],
};
];

// Add documents with custom payload
await qdrantVectorStore.addDocuments(
Expand Down Expand Up @@ -149,14 +145,14 @@ test("QdrantVectorStore adds vectors with multiple custom payload", async () =>
payload: expect.objectContaining({
content: "hello",
metadata: {},
customPayload: customPayload.customPayload[0],
customPayload: customPayload[0],
}),
}),
expect.objectContaining({
payload: expect.objectContaining({
content: "Goodbye",
metadata: {},
customPayload: customPayload.customPayload[1],
customPayload: customPayload[1],
}),
}),
expect.objectContaining({
Expand Down
60 changes: 33 additions & 27 deletions libs/langchain-qdrant/src/vectorstores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ export interface QdrantLibArgs {
apiKey?: string;
collectionName?: string;
collectionConfig?: QdrantSchemas["CreateCollection"];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
customPayload?: Record<string, any>[];
customPayload?: QdrantCustomPayload;
contentPayloadKey?: string;
metadataPayloadKey?: string;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type QdrantCustomPayload = Record<string, any>;

export type QdrantAddDocumentOptions = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
customPayload: Record<string, any>[];
customPayload: QdrantCustomPayload[];
};

export type QdrantFilter = QdrantSchemas["Filter"];
Expand Down Expand Up @@ -78,6 +79,8 @@ export class QdrantVectorStore extends VectorStore {

metadataPayloadKey: string;

customPayload?: QdrantCustomPayload;

_vectorstoreType(): string {
return "qdrant";
}
Expand All @@ -103,6 +106,8 @@ export class QdrantVectorStore extends VectorStore {

this.collectionConfig = args.collectionConfig;

this.customPayload = args.customPayload;

this.contentPayloadKey = args.contentPayloadKey ?? CONTENT_KEY;

this.metadataPayloadKey = args.metadataPayloadKey ?? METADATA_KEY;
Expand All @@ -113,18 +118,18 @@ export class QdrantVectorStore extends VectorStore {
* from the documents using the `Embeddings` instance and then adds the
* vectors to the database.
* @param documents Array of `Document` instances to be added to the Qdrant database.
* @param documentOptions Optional `QdrantAddDocumentOptions` which has a list of JSON objects for extra querying
* @param customPayloads Optional `QdrantCustomPayload` array which has a list of JSON objects for extra querying.
* @returns Promise that resolves when the documents have been added to the database.
*/
async addDocuments(
documents: Document[],
documentOptions?: QdrantAddDocumentOptions
customPayloads?: QdrantCustomPayload[],
): Promise<void> {
const texts = documents.map(({ pageContent }) => pageContent);
await this.addVectors(
await this.embeddings.embedDocuments(texts),
documents,
documentOptions
customPayloads
);
}

Expand All @@ -134,29 +139,35 @@ export class QdrantVectorStore extends VectorStore {
* database.
* @param vectors Array of vectors to be added to the Qdrant database.
* @param documents Array of `Document` instances associated with the vectors.
* @param documentOptions Optional `QdrantAddDocumentOptions` which has a list of JSON objects for extra querying
* @param customPayloads Optional `QdrantCustomPayload` array which has a list of JSON objects for extra querying. Will be merged with custom payload of dbConfig.
* @returns Promise that resolves when the vectors have been added to the database.
*/
async addVectors(
vectors: number[][],
documents: Document[],
documentOptions?: QdrantAddDocumentOptions
customPayloads?: QdrantCustomPayload[],
): Promise<void> {
if (vectors.length === 0) {
return;
}

await this.ensureCollection();

const points = vectors.map((embedding, idx) => ({
id: documents[idx].id ?? uuid(),
vector: embedding,
payload: {
[this.contentPayloadKey]: documents[idx].pageContent,
[this.metadataPayloadKey]: documents[idx].metadata,
customPayload: documentOptions?.customPayload[idx],
},
}));
const points = vectors.map((embedding, idx) => {
const customPayload = {
...this.customPayload,
...customPayloads?.[idx],
}
return {
id: documents[idx].id ?? uuid(),
vector: embedding,
payload: {
[this.contentPayloadKey]: documents[idx].pageContent,
[this.metadataPayloadKey]: documents[idx].metadata,
customPayload: Object.keys(customPayload).length > 0 ? customPayload : undefined,
},
}
});

try {
await this.client.upsert(this.collectionName, {
Expand Down Expand Up @@ -332,22 +343,17 @@ export class QdrantVectorStore extends VectorStore {
* @param docs Array of `Document` instances to be added to the Qdrant database.
* @param embeddings `Embeddings` instance used to generate vectors from the documents.
* @param dbConfig `QdrantLibArgs` instance specifying the configuration for the Qdrant database.
* @param customPayloads Optional `QdrantCustomPayload` array which has a list of JSON objects for extra querying.
* @returns Promise that resolves with a new `QdrantVectorStore` instance.
*/
static async fromDocuments(
docs: Document[],
embeddings: EmbeddingsInterface,
dbConfig: QdrantLibArgs
dbConfig: QdrantLibArgs,
customPayloads?: QdrantCustomPayload[]
): Promise<QdrantVectorStore> {
const instance = new this(embeddings, dbConfig);
if (dbConfig.customPayload) {
const documentOptions = {
customPayload: dbConfig?.customPayload,
};
await instance.addDocuments(docs, documentOptions);
} else {
await instance.addDocuments(docs);
}
await instance.addDocuments(docs, customPayloads);
return instance;
}

Expand Down

0 comments on commit 4b2d1fe

Please sign in to comment.