Skip to content

Feature/qdrant mrl support#6057

Closed
voreskovic wants to merge 2 commits intoFlowiseAI:mainfrom
voreskovic:feature/Qdrant-MRL-support
Closed

Feature/qdrant mrl support#6057
voreskovic wants to merge 2 commits intoFlowiseAI:mainfrom
voreskovic:feature/Qdrant-MRL-support

Conversation

@voreskovic
Copy link
Copy Markdown

No description provided.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Qdrant vector store integration by introducing Matryoshka Representation Learning (MRL) support. This allows the system to manage and query vector embeddings more efficiently by storing them at various truncated dimensions. The changes involve adding new functionalities for configuring and utilizing MRL, which provides greater flexibility in balancing search precision and performance.

Highlights

  • Matryoshka Representation Learning (MRL) Support: Introduced MRL capabilities for Qdrant, allowing embeddings to be stored and queried at multiple truncated dimensions using named vectors. This enables more flexible and potentially faster similarity searches.
  • New MRL Utility Functions: Added several helper functions: parseMrlDimensions for parsing dimension strings, buildMrlVectorsConfig for creating Qdrant named vector configurations, truncateAndNormalize for processing embeddings, buildMrlVectorMap for MRL-specific vector mapping, and ensureMrlCollection for collection management.
  • Qdrant Node Configuration Updates: Updated the Qdrant node to include new UI parameters: mrlEnabled (boolean), mrlDimensions (comma-separated string of dimensions), and mrlSearchVector (string for specifying which named vector to use for search).
  • Enhanced Vector Storage and Retrieval Logic: Modified the init and run methods within the Qdrant node to conditionally apply MRL logic during vector upsert operations and to override the similaritySearchVectorWithScore method for MRL-aware searching.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Matryoshka Representation Learning (MRL) support for Qdrant vector stores. This includes new utility functions for parsing MRL dimensions, building vector configurations, truncating and normalizing embeddings, and managing MRL-specific vector maps. New UI options (mrlEnabled, mrlDimensions, mrlSearchVector) have been added to configure MRL. The core logic for indexing and searching has been updated to conditionally handle MRL, including ensuring collection setup and overriding similarity search for MRL vectors. The version of the Qdrant component has been incremented. Feedback includes removing an accidental line in the README.md, improving the efficiency of ensureMrlCollection, enhancing readability by refactoring a repeated MRL condition into a variable, removing a redundant collection existence check in the index function, improving type safety by using specific Qdrant types instead of any for points and res parameters, and addressing code duplication in the batch upsert logic within the index function.


<div align="center">

Nice
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line appears to be an accidental addition and should be removed to keep the README clean.

Comment on lines +76 to +82
async function ensureMrlCollection(client: QdrantClient, collectionName: string, collectionConfig: Record<string, any>): Promise<void> {
const response = await client.getCollections()
const collectionNames = response.collections.map((c: any) => c.name)
if (!collectionNames.includes(collectionName)) {
await client.createCollection(collectionName, collectionConfig)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of ensureMrlCollection fetches all collections to check if one exists, which can be inefficient if there are many collections. A more performant approach is to try fetching the specific collection by name and creating it only if a "not found" error (e.g., status 404) is returned.

async function ensureMrlCollection(client: QdrantClient, collectionName: string, collectionConfig: Record<string, any>): Promise<void> {
    try {
        await client.getCollection(collectionName)
    } catch (e: any) {
        if (e.status === 404) {
            await client.createCollection(collectionName, collectionConfig)
        } else {
            throw e
        }
    }
}

Comment on lines +333 to +336
const collectionConfig =
mrlEnabled && mrlDimensions.length > 0
? { vectors: buildMrlVectorsConfig(fullDimension, mrlDimensions, distance) }
: { vectors: { size: fullDimension, distance } }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The condition mrlEnabled && mrlDimensions.length > 0 is used multiple times. To improve readability and reduce repetition, consider storing this boolean check in a variable like isMrlActive and reusing it.

References
  1. Prioritize code readability and understandability over conciseness. A series of simple, chained operations can be preferable to a single, more complex one if it improves understandability and reduces the potential for future errors.

Comment on lines +351 to +355
if (mrlEnabled && mrlDimensions.length > 0) {
await ensureMrlCollection(client, collectionName, collectionConfig)
} else {
await vectorStore.ensureCollection()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This call to ensure the collection exists is redundant. The overridden addVectors method on line 357 also calls ensureMrlCollection (or vectorStore.ensureCollection). Since the index function will call addVectors, the check for the collection's existence should only be within addVectors. Please remove this redundant block.

await client.upsert(collectionName, {
wait: true,
points: batchPoints
points: batchPoints as any
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Casting points to any compromises type safety. You can import PointStruct from @qdrant/js-client-rest and apply it to your points array. This will provide better type checking and allow you to remove the as any cast. This feedback also applies to lines 398, 457, and 463.

Comment on lines +436 to 479
if (mrlEnabled && mrlDimensions.length > 0) {
await ensureMrlCollection(client, collectionName, collectionConfig)

const texts = finalDocs.map((doc) => doc.pageContent)
const allEmbeddings = await embeddings.embedDocuments(texts)

const points = allEmbeddings.map((embedding: number[], idx: number) => ({
id: uuid(),
vector: buildMrlVectorMap(embedding, mrlDimensions, fullDimension),
payload: {
[contentPayloadKey]: finalDocs[idx].pageContent,
[metadataPayloadKey]: finalDocs[idx].metadata
}
}))

if (_batchSize) {
const batchSize = parseInt(_batchSize, 10)
for (let i = 0; i < points.length; i += batchSize) {
const batchPoints = points.slice(i, i + batchSize)
await client.upsert(collectionName, {
wait: true,
points: batchPoints as any
})
}
} else {
await client.upsert(collectionName, {
wait: true,
points: points as any
})
}

return { numAdded: finalDocs.length, addedDocs: finalDocs }
} else {
await QdrantVectorStore.fromDocuments(finalDocs, embeddings, dbConfig)
if (_batchSize) {
const batchSize = parseInt(_batchSize, 10)
for (let i = 0; i < finalDocs.length; i += batchSize) {
const batch = finalDocs.slice(i, i + batchSize)
await QdrantVectorStore.fromDocuments(batch, embeddings, dbConfig)
}
} else {
await QdrantVectorStore.fromDocuments(finalDocs, embeddings, dbConfig)
}
return { numAdded: finalDocs.length, addedDocs: finalDocs }
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication in this block. The logic for batch upserting points is repeated from the addVectors override (lines 386-400). Additionally, the return { numAdded: finalDocs.length, addedDocs: finalDocs } statement is duplicated in both branches of the MRL conditional.

To improve maintainability, consider extracting the batching logic into a helper function and moving the common return statement outside the conditional block.

References
  1. Prioritize code readability and understandability over conciseness. A series of simple, chained operations can be preferable to a single, more complex one if it improves understandability and reduces the potential for future errors.

})
).points

return results.map((res: any) => [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for the res parameter reduces type safety. You can import ScoredPoint from @qdrant/js-client-rest and use it to type the res parameter. This will improve code quality and provide better type-checking.

Suggested change
return results.map((res: any) => [
return results.map((res: ScoredPoint) => [

@voreskovic voreskovic closed this Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant