mirror of
https://github.com/qdrant/qdrant.git
synced 2026-08-05 09:31:05 -05:00
Make EdgeConfig tunables optional with a layered fallback chain (#9714)
Tunable EdgeConfig parameters (on_disk_payload, hnsw_config, optimizers) are now Option, and every tunable resolves through the fallback chain provided -> persisted -> derived from segments -> default when loading an existing shard. Leaving a parameter unspecified keeps the shard as it is; an explicit value overwrites it and existing segments converge to it through the optimizers. vectors/sparse_vectors are excluded from overwrite semantics: an empty map inherits the persisted/segment-derived definitions, a non-empty map is validated for compatibility against the loaded segments (size, distance, multivector, datatype, sparse modifier) and fails the load on mismatch. The derived layer folds over all segments in UUID order instead of taking an arbitrary first segment, so a plain appendable segment (which carries no HNSW parameters) can never mask an indexed segment's actual build parameters. Previously a lost edge_config.json could resolve unspecified HNSW params to compiled-in defaults and silently trigger a full re-index via ConfigMismatchOptimizer. The read-only follower accepts an optional config on open: provided tunables are applied once over the segment-derived config (vectors always come from the segments), and refresh re-derives from segments alone. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
generall
parent
500c68ecbb
commit
2bb287d693
@@ -254,7 +254,7 @@ class EdgeConfig:
|
||||
Union["EdgeVectorParams", Dict[str, "EdgeVectorParams"]]
|
||||
] = None,
|
||||
sparse_vectors: Optional[Dict[str, "EdgeSparseVectorParams"]] = None,
|
||||
on_disk_payload: bool = True,
|
||||
on_disk_payload: Optional[bool] = None,
|
||||
hnsw_config: Optional["HnswIndexConfig"] = None,
|
||||
quantization_config: Optional[QuantizationConfigType] = None,
|
||||
optimizers: Optional["EdgeOptimizersConfig"] = None,
|
||||
@@ -263,12 +263,19 @@ class EdgeConfig:
|
||||
"""
|
||||
Create an EdgeConfig.
|
||||
|
||||
Parameters left as None are "not specified": when loading an existing shard each
|
||||
one resolves through provided -> persisted -> derived from segments -> default,
|
||||
so an unspecified parameter keeps the shard as it is. vectors and sparse_vectors
|
||||
define the stored data: if provided they are validated for compatibility against
|
||||
the existing segments, if omitted they are inherited from the shard.
|
||||
|
||||
Args:
|
||||
vectors: Dense vector configuration. Can be a single EdgeVectorParams for
|
||||
the default vector (name "") or a dict of name -> EdgeVectorParams.
|
||||
Optional if sparse_vectors is provided (sparse-only config).
|
||||
sparse_vectors: Optional sparse vector configurations.
|
||||
on_disk_payload: If True, store payload on disk (mmap); otherwise in RAM.
|
||||
None keeps the shard's current value (defaults to on-disk).
|
||||
hnsw_config: Optional global HNSW config (used when building HNSW index).
|
||||
quantization_config: Optional global quantization config.
|
||||
optimizers: Optional optimizer settings.
|
||||
@@ -290,13 +297,13 @@ class EdgeConfig:
|
||||
...
|
||||
|
||||
@property
|
||||
def on_disk_payload(self) -> bool:
|
||||
"""Whether payload is stored on disk."""
|
||||
def on_disk_payload(self) -> Optional[bool]:
|
||||
"""Whether payload is stored on disk, or None if not specified."""
|
||||
...
|
||||
|
||||
@property
|
||||
def hnsw_config(self) -> "HnswIndexConfig":
|
||||
"""Global HNSW config."""
|
||||
def hnsw_config(self) -> Optional["HnswIndexConfig"]:
|
||||
"""Global HNSW config, or None if not specified."""
|
||||
...
|
||||
|
||||
@property
|
||||
@@ -305,8 +312,8 @@ class EdgeConfig:
|
||||
...
|
||||
|
||||
@property
|
||||
def optimizers(self) -> "EdgeOptimizersConfig":
|
||||
"""Optimizer settings."""
|
||||
def optimizers(self) -> Optional["EdgeOptimizersConfig"]:
|
||||
"""Optimizer settings, or None if not specified."""
|
||||
...
|
||||
|
||||
@property
|
||||
|
||||
@@ -25,13 +25,13 @@ pub struct PyEdgeConfig(pub EdgeConfig);
|
||||
#[pymethods]
|
||||
impl PyEdgeConfig {
|
||||
#[new]
|
||||
#[pyo3(signature = (vectors=None, sparse_vectors=None, on_disk_payload=true, hnsw_config=None, quantization_config=None, optimizers=None, max_search_threads=None))]
|
||||
#[pyo3(signature = (vectors=None, sparse_vectors=None, on_disk_payload=None, hnsw_config=None, quantization_config=None, optimizers=None, max_search_threads=None))]
|
||||
pub fn new(
|
||||
#[pyo3(from_py_with = option_edge_vectors_helper)] vectors: Option<
|
||||
HashMap<String, PyEdgeVectorParams>,
|
||||
>,
|
||||
sparse_vectors: Option<HashMap<String, PyEdgeSparseVectorParams>>,
|
||||
on_disk_payload: bool,
|
||||
on_disk_payload: Option<bool>,
|
||||
hnsw_config: Option<PyHnswIndexConfig>,
|
||||
quantization_config: Option<PyQuantizationConfig>,
|
||||
optimizers: Option<PyEdgeOptimizersConfig>,
|
||||
@@ -52,9 +52,9 @@ impl PyEdgeConfig {
|
||||
on_disk_payload,
|
||||
vectors,
|
||||
sparse_vectors,
|
||||
hnsw_config: hnsw_config.map(|h| h.0).unwrap_or_default(),
|
||||
hnsw_config: hnsw_config.map(|h| h.0),
|
||||
quantization_config: quantization_config.map(QuantizationConfig::from),
|
||||
optimizers: optimizers.map(|o| o.0).unwrap_or_default(),
|
||||
optimizers: optimizers.map(|o| o.0),
|
||||
wal_options: None,
|
||||
max_search_threads,
|
||||
}))
|
||||
@@ -71,13 +71,13 @@ impl PyEdgeConfig {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn on_disk_payload(&self) -> bool {
|
||||
pub fn on_disk_payload(&self) -> Option<bool> {
|
||||
self.0.on_disk_payload
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn hnsw_config(&self) -> PyHnswIndexConfig {
|
||||
PyHnswIndexConfig(self.0.hnsw_config)
|
||||
pub fn hnsw_config(&self) -> Option<PyHnswIndexConfig> {
|
||||
self.0.hnsw_config.map(PyHnswIndexConfig)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -86,8 +86,8 @@ impl PyEdgeConfig {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn optimizers(&self) -> PyEdgeOptimizersConfig {
|
||||
PyEdgeOptimizersConfig(self.0.optimizers.clone())
|
||||
pub fn optimizers(&self) -> Option<PyEdgeOptimizersConfig> {
|
||||
self.0.optimizers.clone().map(PyEdgeOptimizersConfig)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
|
||||
Reference in New Issue
Block a user