feat: implement Qdrant memory optimization with constants in @roo-code/types

- Create comprehensive Qdrant configuration constants in @roo-code/types package
- Add memory optimization config fields to codebase-index schema
- Configure Qdrant to use on-disk storage for vectors and HNSW indexes by default
- Add memory-mapped file support for segments larger than 50k vectors
- Keep HNSW search parameter (ef) at 128 for testing purposes
- Update all affected files to use constants from types package
- Update all test files to handle new configuration parameters

Fixes #6262
This commit is contained in:
Roo Code 2025-07-29 17:00:53 +00:00
parent b117c0fe52
commit 2b3d8aa4d1
10 changed files with 465 additions and 9 deletions

View file

@ -34,6 +34,10 @@ export const codebaseIndexConfigSchema = z.object({
// OpenAI Compatible specific fields
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
// Memory optimization settings
codebaseIndexUseOnDiskStorage: z.boolean().optional(),
codebaseIndexMemoryMapThreshold: z.number().optional(),
codebaseIndexHnswEfSearch: z.number().optional(),
})
export type CodebaseIndexConfig = z.infer<typeof codebaseIndexConfigSchema>

View file

@ -21,3 +21,4 @@ export * from "./tool.js"
export * from "./type-fu.js"
export * from "./vscode.js"
export * from "./todo.js"
export * from "./qdrant.js"

View file

@ -0,0 +1,141 @@
/**
* Qdrant Vector Store Configuration Constants
*
* These constants define default values for Qdrant memory optimization settings
* to reduce RAM usage by storing vectors and indexes on disk instead of in memory.
*/
/**
* Default memory optimization settings for Qdrant
*/
export const QDRANT_MEMORY_OPTIMIZATION_DEFAULTS = {
/**
* Enable on-disk storage for vectors and HNSW indexes by default
* This significantly reduces memory usage at the cost of slightly slower access
*/
USE_ON_DISK_STORAGE: true,
/**
* Number of vectors before using memory-mapped files
* Segments larger than this threshold will use memory-mapped files for better memory management
*/
MEMORY_MAP_THRESHOLD: 50000,
/**
* HNSW search parameter (ef) - controls search quality vs memory usage
* Higher values = better search quality but more memory usage
* Lower values = less memory usage but potentially lower search quality
* Default: 128 (original value, not reduced for testing purposes)
*/
HNSW_EF_SEARCH: 128,
} as const
/**
* HNSW (Hierarchical Navigable Small World) index configuration constants
*/
export const QDRANT_HNSW_CONFIG_DEFAULTS = {
/**
* Number of bi-directional links created for each node during construction
*/
M: 16,
/**
* Size of the dynamic list during index construction
*/
EF_CONSTRUCT: 100,
/**
* Use full scan for collections smaller than this threshold
*/
FULL_SCAN_THRESHOLD: 10000,
/**
* Maximum number of threads for indexing (0 = use all available CPU cores)
*/
MAX_INDEXING_THREADS: 0,
/**
* Payload index configuration (null = use default)
*/
PAYLOAD_M: null,
} as const
/**
* Optimizer configuration constants for memory-mapped storage
*/
export const QDRANT_OPTIMIZER_CONFIG_DEFAULTS = {
/**
* Trigger optimization when this percentage of vectors are deleted
*/
DELETED_THRESHOLD: 0.2,
/**
* Minimum number of vectors before vacuum operation
*/
VACUUM_MIN_VECTOR_NUMBER: 1000,
/**
* Default number of segments to create
*/
DEFAULT_SEGMENT_NUMBER: 2,
/**
* Maximum segment size (null = no limit)
*/
MAX_SEGMENT_SIZE: null,
/**
* Start indexing after this many vectors
*/
INDEXING_THRESHOLD: 20000,
/**
* Flush to disk interval in seconds
*/
FLUSH_INTERVAL_SEC: 5,
/**
* Maximum optimization threads (0 = use all available CPU cores)
*/
MAX_OPTIMIZATION_THREADS: 0,
} as const
/**
* Quantization configuration for additional memory efficiency
*/
export const QDRANT_QUANTIZATION_CONFIG_DEFAULTS = {
/**
* Enable quantization for memory efficiency
*/
IGNORE: false,
/**
* Rescore with original vectors for accuracy
*/
RESCORE: true,
/**
* Oversample to maintain quality
*/
OVERSAMPLING: 2.0,
} as const
/**
* Memory optimization configuration interface
*/
export interface QdrantMemoryOptimizationConfig {
/**
* Enable on-disk storage for vectors and indexes
*/
useOnDiskStorage?: boolean
/**
* Number of vectors before using memory-mapped files
*/
memoryMapThreshold?: number
/**
* HNSW search parameter (ef) - controls search quality vs memory usage
*/
hnswEfSearch?: number
}

View file

@ -104,11 +104,18 @@ describe("CodeIndexConfigManager", () => {
isConfigured: false,
embedderProvider: "openai",
modelId: undefined,
modelDimension: undefined,
openAiOptions: { openAiNativeApiKey: "" },
ollamaOptions: { ollamaBaseUrl: "" },
openAiCompatibleOptions: undefined,
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://localhost:6333",
qdrantApiKey: "",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
expect(result.requiresRestart).toBe(false)
})
@ -135,11 +142,18 @@ describe("CodeIndexConfigManager", () => {
isConfigured: true,
embedderProvider: "openai",
modelId: "text-embedding-3-large",
modelDimension: undefined,
openAiOptions: { openAiNativeApiKey: "test-openai-key" },
ollamaOptions: { ollamaBaseUrl: "" },
openAiCompatibleOptions: undefined,
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})
@ -168,15 +182,21 @@ describe("CodeIndexConfigManager", () => {
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "text-embedding-3-large",
modelDimension: undefined,
openAiOptions: { openAiNativeApiKey: "" },
ollamaOptions: { ollamaBaseUrl: "" },
openAiCompatibleOptions: {
baseUrl: "https://api.example.com/v1",
apiKey: "test-openai-compatible-key",
},
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})
@ -212,9 +232,14 @@ describe("CodeIndexConfigManager", () => {
baseUrl: "https://api.example.com/v1",
apiKey: "test-openai-compatible-key",
},
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})
@ -243,6 +268,7 @@ describe("CodeIndexConfigManager", () => {
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "custom-model",
modelDimension: undefined,
openAiOptions: { openAiNativeApiKey: "" },
ollamaOptions: { ollamaBaseUrl: "" },
openAiCompatibleOptions: {
@ -250,9 +276,14 @@ describe("CodeIndexConfigManager", () => {
apiKey: "test-openai-compatible-key",
// modelDimension is undefined when not set
},
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})
@ -289,9 +320,13 @@ describe("CodeIndexConfigManager", () => {
apiKey: "test-openai-compatible-key",
},
geminiOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})
@ -1292,14 +1327,19 @@ describe("CodeIndexConfigManager", () => {
isConfigured: true,
embedderProvider: "openai",
modelId: "text-embedding-3-large",
modelDimension: undefined,
openAiOptions: { openAiNativeApiKey: "test-openai-key" },
ollamaOptions: { ollamaBaseUrl: undefined },
geminiOptions: undefined,
openAiCompatibleOptions: undefined,
mistralOptions: undefined,
qdrantUrl: "http://qdrant.local",
qdrantApiKey: "test-qdrant-key",
searchMinScore: 0.4,
searchMaxResults: 50,
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
})
})

View file

@ -49,6 +49,11 @@ describe("CodeIndexServiceFactory", () => {
mockConfigManager = {
getConfig: vitest.fn(),
memoryOptimizationConfig: {
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
}
mockCacheManager = {}
@ -367,6 +372,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
3072,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -392,6 +402,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
768,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -417,6 +432,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
3072,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -449,6 +469,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
modelDimension, // Should use model's built-in dimension, not manual
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -480,6 +505,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
manualDimension, // Should use manual dimension as fallback
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -509,6 +539,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
768,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -578,6 +613,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
3072,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -603,6 +643,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
3072,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})
@ -627,6 +672,11 @@ describe("CodeIndexServiceFactory", () => {
"http://localhost:6333",
1536,
"test-key",
{
useOnDiskStorage: true,
memoryMapThreshold: 50000,
hnswEfSearch: 128,
},
)
})

View file

@ -4,6 +4,7 @@ import { EmbedderProvider } from "./interfaces/manager"
import { CodeIndexConfig, PreviousConfigSnapshot } from "./interfaces/config"
import { DEFAULT_SEARCH_MIN_SCORE, DEFAULT_MAX_SEARCH_RESULTS } from "./constants"
import { getDefaultModelId, getModelDimension, getModelScoreThreshold } from "../../shared/embeddingModels"
import { QDRANT_MEMORY_OPTIMIZATION_DEFAULTS } from "@roo-code/types"
/**
* Manages configuration state and validation for the code indexing feature.
@ -23,6 +24,10 @@ export class CodeIndexConfigManager {
private qdrantApiKey?: string
private searchMinScore?: number
private searchMaxResults?: number
// Memory optimization settings
private useOnDiskStorage?: boolean
private memoryMapThreshold?: number
private hnswEfSearch?: number
constructor(private readonly contextProxy: ContextProxy) {
// Initialize with current configuration to avoid false restart triggers
@ -50,6 +55,9 @@ export class CodeIndexConfigManager {
codebaseIndexEmbedderModelId: "",
codebaseIndexSearchMinScore: undefined,
codebaseIndexSearchMaxResults: undefined,
codebaseIndexUseOnDiskStorage: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
codebaseIndexMemoryMapThreshold: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.MEMORY_MAP_THRESHOLD,
codebaseIndexHnswEfSearch: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.HNSW_EF_SEARCH,
}
const {
@ -60,6 +68,9 @@ export class CodeIndexConfigManager {
codebaseIndexEmbedderModelId,
codebaseIndexSearchMinScore,
codebaseIndexSearchMaxResults,
codebaseIndexUseOnDiskStorage,
codebaseIndexMemoryMapThreshold,
codebaseIndexHnswEfSearch,
} = codebaseIndexConfig
const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? ""
@ -76,6 +87,10 @@ export class CodeIndexConfigManager {
this.qdrantApiKey = qdrantApiKey ?? ""
this.searchMinScore = codebaseIndexSearchMinScore
this.searchMaxResults = codebaseIndexSearchMaxResults
this.useOnDiskStorage = codebaseIndexUseOnDiskStorage ?? QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE
this.memoryMapThreshold =
codebaseIndexMemoryMapThreshold ?? QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.MEMORY_MAP_THRESHOLD
this.hnswEfSearch = codebaseIndexHnswEfSearch ?? QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.HNSW_EF_SEARCH
// Validate and set model dimension
const rawDimension = codebaseIndexConfig.codebaseIndexEmbedderModelDimension
@ -144,6 +159,9 @@ export class CodeIndexConfigManager {
qdrantUrl?: string
qdrantApiKey?: string
searchMinScore?: number
useOnDiskStorage?: boolean
memoryMapThreshold?: number
hnswEfSearch?: number
}
requiresRestart: boolean
}> {
@ -187,6 +205,9 @@ export class CodeIndexConfigManager {
qdrantUrl: this.qdrantUrl,
qdrantApiKey: this.qdrantApiKey,
searchMinScore: this.currentSearchMinScore,
useOnDiskStorage: this.useOnDiskStorage,
memoryMapThreshold: this.memoryMapThreshold,
hnswEfSearch: this.hnswEfSearch,
},
requiresRestart,
}
@ -379,6 +400,9 @@ export class CodeIndexConfigManager {
qdrantApiKey: this.qdrantApiKey,
searchMinScore: this.currentSearchMinScore,
searchMaxResults: this.currentSearchMaxResults,
useOnDiskStorage: this.useOnDiskStorage,
memoryMapThreshold: this.memoryMapThreshold,
hnswEfSearch: this.hnswEfSearch,
}
}
@ -413,6 +437,21 @@ export class CodeIndexConfigManager {
}
}
/**
* Gets the memory optimization settings
*/
public get memoryOptimizationConfig(): {
useOnDiskStorage?: boolean
memoryMapThreshold?: number
hnswEfSearch?: number
} {
return {
useOnDiskStorage: this.useOnDiskStorage,
memoryMapThreshold: this.memoryMapThreshold,
hnswEfSearch: this.hnswEfSearch,
}
}
/**
* Gets the current model ID being used for embeddings.
*/

View file

@ -1,5 +1,6 @@
import { ApiHandlerOptions } from "../../../shared/api" // Adjust path if needed
import { EmbedderProvider } from "./manager"
import { QdrantMemoryOptimizationConfig } from "@roo-code/types"
/**
* Configuration state for the code indexing feature
@ -18,6 +19,10 @@ export interface CodeIndexConfig {
qdrantApiKey?: string
searchMinScore?: number
searchMaxResults?: number
// Memory optimization settings
useOnDiskStorage?: boolean
memoryMapThreshold?: number
hnswEfSearch?: number
}
/**
@ -37,4 +42,8 @@ export type PreviousConfigSnapshot = {
mistralApiKey?: string
qdrantUrl?: string
qdrantApiKey?: string
// Memory optimization settings
useOnDiskStorage?: boolean
memoryMapThreshold?: number
hnswEfSearch?: number
}

View file

@ -136,8 +136,17 @@ export class CodeIndexServiceFactory {
throw new Error(t("embeddings:serviceFactory.qdrantUrlMissing"))
}
// Assuming constructor is updated: new QdrantVectorStore(workspacePath, url, vectorSize, apiKey?)
return new QdrantVectorStore(this.workspacePath, config.qdrantUrl, vectorSize, config.qdrantApiKey)
// Get memory optimization config from config manager
const memoryOptimization = this.configManager.memoryOptimizationConfig
// Create QdrantVectorStore with memory optimization settings
return new QdrantVectorStore(
this.workspacePath,
config.qdrantUrl,
vectorSize,
config.qdrantApiKey,
memoryOptimization,
)
}
/**

View file

@ -528,6 +528,25 @@ describe("QdrantVectorStore", () => {
vectors: {
size: mockVectorSize,
distance: "Cosine", // Assuming 'Cosine' is the DISTANCE_METRIC
on_disk: true, // Default memory optimization
},
hnsw_config: {
m: 16,
ef_construct: 100,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: true,
payload_m: null,
},
optimizers_config: {
deleted_threshold: 0.2,
vacuum_min_vector_number: 1000,
default_segment_number: 2,
max_segment_size: null,
memmap_threshold: 50000,
indexing_threshold: 20000,
flush_interval_sec: 5,
max_optimization_threads: 0,
},
})
expect(mockQdrantClientInstance.deleteCollection).not.toHaveBeenCalled()
@ -606,6 +625,25 @@ describe("QdrantVectorStore", () => {
vectors: {
size: mockVectorSize, // Should use the new, correct vector size
distance: "Cosine",
on_disk: true, // Default memory optimization
},
hnsw_config: {
m: 16,
ef_construct: 100,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: true,
payload_m: null,
},
optimizers_config: {
deleted_threshold: 0.2,
vacuum_min_vector_number: 1000,
default_segment_number: 2,
max_segment_size: null,
memmap_threshold: 50000,
indexing_threshold: 20000,
flush_interval_sec: 5,
max_optimization_threads: 0,
},
})
@ -899,6 +937,25 @@ describe("QdrantVectorStore", () => {
vectors: {
size: newVectorSize, // Should create with new 768 dimensions
distance: "Cosine",
on_disk: true, // Default memory optimization
},
hnsw_config: {
m: 16,
ef_construct: 100,
full_scan_threshold: 10000,
max_indexing_threads: 0,
on_disk: true,
payload_m: null,
},
optimizers_config: {
deleted_threshold: 0.2,
vacuum_min_vector_number: 1000,
default_segment_number: 2,
max_segment_size: null,
memmap_threshold: 50000,
indexing_threshold: 20000,
flush_interval_sec: 5,
max_optimization_threads: 0,
},
})
expect(mockQdrantClientInstance.createPayloadIndex).toHaveBeenCalledTimes(5)
@ -1244,8 +1301,13 @@ describe("QdrantVectorStore", () => {
score_threshold: DEFAULT_SEARCH_MIN_SCORE,
limit: DEFAULT_MAX_SEARCH_RESULTS,
params: {
hnsw_ef: 128,
hnsw_ef: 128, // Default memory optimized value
exact: false,
quantization: {
ignore: false,
rescore: true,
oversampling: 2.0,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],
@ -1295,8 +1357,13 @@ describe("QdrantVectorStore", () => {
score_threshold: DEFAULT_SEARCH_MIN_SCORE,
limit: DEFAULT_MAX_SEARCH_RESULTS,
params: {
hnsw_ef: 128,
hnsw_ef: 128, // Default memory optimized value
exact: false,
quantization: {
ignore: false,
rescore: true,
oversampling: 2.0,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],
@ -1321,8 +1388,13 @@ describe("QdrantVectorStore", () => {
score_threshold: customMinScore,
limit: DEFAULT_MAX_SEARCH_RESULTS,
params: {
hnsw_ef: 128,
hnsw_ef: 128, // Default memory optimized value
exact: false,
quantization: {
ignore: false,
rescore: true,
oversampling: 2.0,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],
@ -1345,8 +1417,13 @@ describe("QdrantVectorStore", () => {
score_threshold: DEFAULT_SEARCH_MIN_SCORE,
limit: customMaxResults,
params: {
hnsw_ef: 128,
hnsw_ef: 128, // Default memory optimized value
exact: false,
quantization: {
ignore: false,
rescore: true,
oversampling: 2.0,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],
@ -1492,8 +1569,13 @@ describe("QdrantVectorStore", () => {
score_threshold: DEFAULT_SEARCH_MIN_SCORE,
limit: DEFAULT_MAX_SEARCH_RESULTS,
params: {
hnsw_ef: 128,
hnsw_ef: 128, // Default memory optimized value
exact: false,
quantization: {
ignore: false,
rescore: true,
oversampling: 2.0,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],

View file

@ -6,6 +6,13 @@ import { IVectorStore } from "../interfaces/vector-store"
import { Payload, VectorStoreSearchResult } from "../interfaces"
import { DEFAULT_MAX_SEARCH_RESULTS, DEFAULT_SEARCH_MIN_SCORE } from "../constants"
import { t } from "../../../i18n"
import {
QdrantMemoryOptimizationConfig,
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS,
QDRANT_HNSW_CONFIG_DEFAULTS,
QDRANT_OPTIMIZER_CONFIG_DEFAULTS,
QDRANT_QUANTIZATION_CONFIG_DEFAULTS,
} from "@roo-code/types"
/**
* Qdrant implementation of the vector store interface
@ -17,13 +24,23 @@ export class QdrantVectorStore implements IVectorStore {
private client: QdrantClient
private readonly collectionName: string
private readonly qdrantUrl: string = "http://localhost:6333"
private readonly memoryOptimization: QdrantMemoryOptimizationConfig
/**
* Creates a new Qdrant vector store
* @param workspacePath Path to the workspace
* @param url Optional URL to the Qdrant server
* @param vectorSize Size of the vectors
* @param apiKey Optional API key for authentication
* @param memoryOptimization Optional memory optimization settings
*/
constructor(workspacePath: string, url: string, vectorSize: number, apiKey?: string) {
constructor(
workspacePath: string,
url: string,
vectorSize: number,
apiKey?: string,
memoryOptimization?: QdrantMemoryOptimizationConfig,
) {
// Parse the URL to determine the appropriate QdrantClient configuration
const parsedUrl = this.parseQdrantUrl(url)
@ -79,6 +96,11 @@ export class QdrantVectorStore implements IVectorStore {
const hash = createHash("sha256").update(workspacePath).digest("hex")
this.vectorSize = vectorSize
this.collectionName = `ws-${hash.substring(0, 16)}`
this.memoryOptimization = memoryOptimization || {
useOnDiskStorage: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
memoryMapThreshold: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.MEMORY_MAP_THRESHOLD,
hnswEfSearch: QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.HNSW_EF_SEARCH,
}
}
/**
@ -155,6 +177,33 @@ export class QdrantVectorStore implements IVectorStore {
vectors: {
size: this.vectorSize,
distance: this.DISTANCE_METRIC,
on_disk:
this.memoryOptimization.useOnDiskStorage ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
},
// Configure HNSW index for memory efficiency
hnsw_config: {
m: QDRANT_HNSW_CONFIG_DEFAULTS.M,
ef_construct: QDRANT_HNSW_CONFIG_DEFAULTS.EF_CONSTRUCT,
full_scan_threshold: QDRANT_HNSW_CONFIG_DEFAULTS.FULL_SCAN_THRESHOLD,
max_indexing_threads: QDRANT_HNSW_CONFIG_DEFAULTS.MAX_INDEXING_THREADS,
on_disk:
this.memoryOptimization.useOnDiskStorage ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
payload_m: QDRANT_HNSW_CONFIG_DEFAULTS.PAYLOAD_M,
},
// Enable memory-mapped storage for better memory management
optimizers_config: {
deleted_threshold: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.DELETED_THRESHOLD,
vacuum_min_vector_number: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.VACUUM_MIN_VECTOR_NUMBER,
default_segment_number: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.DEFAULT_SEGMENT_NUMBER,
max_segment_size: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.MAX_SEGMENT_SIZE,
memmap_threshold:
this.memoryOptimization.memoryMapThreshold ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.MEMORY_MAP_THRESHOLD,
indexing_threshold: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.INDEXING_THRESHOLD,
flush_interval_sec: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.FLUSH_INTERVAL_SEC,
max_optimization_threads: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.MAX_OPTIMIZATION_THREADS,
},
})
created = true
@ -244,6 +293,33 @@ export class QdrantVectorStore implements IVectorStore {
vectors: {
size: this.vectorSize,
distance: this.DISTANCE_METRIC,
on_disk:
this.memoryOptimization.useOnDiskStorage ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
},
// Configure HNSW index for memory efficiency
hnsw_config: {
m: QDRANT_HNSW_CONFIG_DEFAULTS.M,
ef_construct: QDRANT_HNSW_CONFIG_DEFAULTS.EF_CONSTRUCT,
full_scan_threshold: QDRANT_HNSW_CONFIG_DEFAULTS.FULL_SCAN_THRESHOLD,
max_indexing_threads: QDRANT_HNSW_CONFIG_DEFAULTS.MAX_INDEXING_THREADS,
on_disk:
this.memoryOptimization.useOnDiskStorage ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.USE_ON_DISK_STORAGE,
payload_m: QDRANT_HNSW_CONFIG_DEFAULTS.PAYLOAD_M,
},
// Enable memory-mapped storage for better memory management
optimizers_config: {
deleted_threshold: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.DELETED_THRESHOLD,
vacuum_min_vector_number: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.VACUUM_MIN_VECTOR_NUMBER,
default_segment_number: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.DEFAULT_SEGMENT_NUMBER,
max_segment_size: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.MAX_SEGMENT_SIZE,
memmap_threshold:
this.memoryOptimization.memoryMapThreshold ??
QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.MEMORY_MAP_THRESHOLD,
indexing_threshold: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.INDEXING_THRESHOLD,
flush_interval_sec: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.FLUSH_INTERVAL_SEC,
max_optimization_threads: QDRANT_OPTIMIZER_CONFIG_DEFAULTS.MAX_OPTIMIZATION_THREADS,
},
})
console.log(`[QdrantVectorStore] Successfully created new collection ${this.collectionName}`)
@ -391,8 +467,13 @@ export class QdrantVectorStore implements IVectorStore {
score_threshold: minScore ?? DEFAULT_SEARCH_MIN_SCORE,
limit: maxResults ?? DEFAULT_MAX_SEARCH_RESULTS,
params: {
hnsw_ef: 128,
hnsw_ef: this.memoryOptimization.hnswEfSearch ?? QDRANT_MEMORY_OPTIMIZATION_DEFAULTS.HNSW_EF_SEARCH,
exact: false,
quantization: {
ignore: QDRANT_QUANTIZATION_CONFIG_DEFAULTS.IGNORE,
rescore: QDRANT_QUANTIZATION_CONFIG_DEFAULTS.RESCORE,
oversampling: QDRANT_QUANTIZATION_CONFIG_DEFAULTS.OVERSAMPLING,
},
},
with_payload: {
include: ["filePath", "codeChunk", "startLine", "endLine", "pathSegments"],