Commit Graph

26 Commits

Author SHA1 Message Date
qdrant-cloud-bot
7e15d343c2 Introduce EdgeShardConfig for edge shard (#8322)
* Introduce EdgeShardConfig for edge shard

- Add EdgeShardConfig and EdgeOptimizersConfig in lib/edge/src/config.rs
  - Segment config (vector_data, sparse_vector_data, payload_storage_type)
  - Global hnsw_config and per-vector HNSW in segment config
  - Optimizer params: deleted_threshold, vacuum_min_vector_number,
    default_segment_number, max_segment_size, indexing_threshold,
    prevent_unoptimized (excludes memmap_threshold, flush_interval_sec,
    max_optimization_threads)
- Persist/load as edge_config.json in shard path
- EdgeShard uses RwLock<EdgeShardConfig>; load() accepts Option<EdgeShardConfig>,
  falls back to file or infer from segments; compatibility checked on load
- load_with_segment_config() for backward compatibility (SegmentConfig -> EdgeShardConfig)
- optimize() uses EdgeShardConfig for hnsw and optimizer thresholds
- Public methods: set_hnsw_config(), set_vector_hnsw_config(), set_optimizers_config()
  (update and persist)
- Python and examples use load_with_segment_config with existing config API

Made-with: Cursor

* Refactor EdgeShardConfig: user-facing params only, config module

- Replace SegmentConfig inside EdgeShardConfig with user-facing fields:
  - on_disk_payload (bool) instead of payload_storage_type
  - vectors: HashMap<VectorNameBuf, EdgeVectorParams> with on_disk per vector,
    no per-vector quantization; global quantization_config only
  - sparse_vectors: HashMap<VectorNameBuf, EdgeSparseVectorParams> with on_disk
- EdgeVectorParams / EdgeSparseVectorParams use on_disk (bool) instead of
  storage_type; conversion to VectorDataConfig/SparseVectorDataConfig in
  to_segment_config()
- Add config module: mod.rs, optimizers.rs, vectors.rs, shard.rs
- from_segment_config(&SegmentConfig) fills all inferrable params
- to_segment_config() builds SegmentConfig for segments and optimize()
- load_with_segment_config takes Option<SegmentConfig>, uses from_segment_config

Made-with: Cursor

* Move optimizer threshold helpers to shard crate

- Add get_number_segments, get_indexing_threshold_kb, get_max_segment_size_kb,
  get_deferred_points_threshold_bytes in shard::optimizers::config
- Collection OptimizersConfig and edge EdgeOptimizersConfig delegate to these
- Single place for threshold logic; collection and edge use shard helpers

Made-with: Cursor

* Use destructuring in config conversions to avoid missing new fields

- EdgeVectorParams: destructure VectorDataConfig in from_*, destructure self in to_vector_data_config
- EdgeSparseVectorParams: destructure SparseVectorDataConfig and SparseIndexConfig in from_*, destructure self in to_sparse_vector_data_config
- EdgeShardConfig: destructure SegmentConfig in from_segment_config, destructure self in to_segment_config
Adding new fields to source structs will now cause compile errors until conversions are updated.

Made-with: Cursor

* refactor: centralize on_disk_payload→payload_storage_type, on_disk→storage_type, and appendable quantization logic

- PayloadStorageType::from_on_disk_payload(bool) in segment (Mmap/InRamMmap)
- VectorStorageType::from_on_disk(bool) in segment (ChunkedMmap/InRamChunkedMmap)
- QuantizationConfig::for_appendable_segment(Option<&Self>) in segment (feature flag + supports_appendable)
- collection: use from_on_disk_payload in non-rocksdb branch
- edge shard/vectors: use new helpers; remove duplicated conditionals
- shard optimizers: use from_on_disk and for_appendable_segment

Made-with: Cursor

* refactor(edge): use EdgeShardConfig directly, drop segment_config

- Add plain_segment_config() for create_appendable_segment (no HNSW)
- Add segment_optimizer_config() built from EdgeShardConfig for blocking optimizers
- Add vector_data_config(name) for query/MMR
- build_blocking_optimizers: use segment_optimizer_config() instead of SegmentConfig
- create_appendable_segment: use plain_segment_config()
- search/query: use config().vectors and vector_data_config() instead of segment_config()
- Remove segment_config() from EdgeShardConfig and EdgeShard
- Add to_plain_vector_data_config on EdgeVectorParams

Made-with: Cursor

* [manual] review changes

* refactor(edge-py): wrap EdgeShardConfig, add EdgeVectorParams/EdgeSparseVectorParams

- PyEdgeConfig now wraps EdgeShardConfig (vectors, sparse_vectors, on_disk_payload, etc.)
- PyEdgeVectorParams / PyEdgeSparseVectorParams wrap edge config types
- PyEdgeOptimizersConfig for optional optimizer settings
- EdgeShard.load() uses EdgeShardConfig; edge::config made pub for Python crate
- cargo fmt + clippy (remove map_identity)

Made-with: Cursor

* refactor(edge-py): simplify config API, remove unused Py* types, add EdgeConfig

- Remove unused PyPayloadStorageType, PyVectorDataConfig, PyVectorStorageType,
  PySparseVectorDataConfig, PySparseVectorStorageType from Python bindings
- Move PyEdgeOptimizersConfig to lib/edge/python/src/config/optimizers.rs
- Update qdrant_edge.pyi: EdgeConfig with vectors/sparse_vectors,
  EdgeVectorParams, EdgeSparseVectorParams, EdgeOptimizersConfig
- Update examples (common.py, repr.py) to use new config API
- Run cargo fmt

Made-with: Cursor

* [manual] review changes

* [manual] review changes

* [manual] fix test

* Address CodeRabbit review comments for PR 8322 (#8324)

* Address CodeRabbit review comments for PR 8322

- Python examples: explicit imports (repr.py, common.py) and new EdgeConfig API
- HnswIndexConfig: add max_indexing_threads param and property in .pyi and Rust bindings
- EdgeConfig: make vectors optional for sparse-only configs; validate at least one of vectors/sparse_vectors
- EdgeShardConfig::load: use try_exists(), propagate I/O errors
- from_segment_config: infer hnsw_config from per-vector HNSW when all agree
- EdgeShard setters: atomic clone-mutate-save-then-replace; persist config save errors
- Segment compat: prefix vector name in error messages; resolve None datatype to Float32
- max_indexing_threads: preserve 0 (auto) sentinel in trait default; remove per-optimizer overrides
- SegmentOptimizerConfig:🆕 build plain and optimizer maps in single pass
- config_mismatch_optimizer tests: use VectorNameBuf::from() instead of .into()
- vectors.rs: doc updates for per-vector quantization

Made-with: Cursor

* Address @generall review: SaveOnDisk for config, resolve num_rayon_threads in optimizer

- Use SaveOnDisk<EdgeShardConfig> for EdgeShard config (generall: 'We have SaveOnDisk struct for this')
  - Create via SaveOnDisk::new() after resolving config; setters use .write() for atomic persist
  - set_vector_hnsw_config: clone then mutate then write (fallible setter)
- max_indexing_threads: resolve 0 (auto) via num_rayon_threads inside impl (generall: 'proper solution would be to resolve num_rayon_threads inside the optimizer impl')
  - max_indexing_threads_sentinel_aware() now returns Some(num_rayon_threads(raw)) so callers get actual thread count

Made-with: Cursor

* [manual] reorganize num_rayon_threads -> get_num_indexing_threads to better account per-vector configuration

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: generall <andrey@vasnetsov.com>

* update docstring and pyi

* fmt

* fmt

* clipy

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: generall <andrey@vasnetsov.com>
2026-03-10 00:10:04 +01:00
Ivan Pleshkov
30cf43382b Deferred threshold integration (#8246)
* Deferred threshold integration

* update deferred id

* apply update_deferred_internal_id

* fix segment inspector

* use avaliable bytes count

* renamings

* review remarks

* review remarks

* move has_deferred_points

* remove todo

* update comments
2026-03-02 09:57:19 +01:00
xzfc
77c71712db Indexing progress (#7625)
* Add progress_tracker.rs

* Pass progress tracker around

* Populate progress tracker with actual data

* Expose progress on `/collections/{name}/optimizations` endpoint
2025-12-09 00:15:36 +00:00
xzfc
95b4bbf978 Rename HnswConfig::{copy_vectors -> inline_storage} (#7389) 2025-10-13 10:08:06 +00:00
xzfc
22df6bc30a Integrate hnsw_with_vectors (#7232)
* StorageGraphLinksVectors::try_new, make GraphLinksVectorsLayout non-fallible

* Integrate hnsw_with_vectors

* remove unused function

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2025-09-18 17:36:48 +00:00
xzfc
706571d8b4 Configurable HNSW healing threshold (#6756) 2025-06-25 10:22:18 +00:00
Tim Visée
f90b9d6d65 Fix tests after removing RocksDB feature flag (#6649)
* Use sparse vector storage fixture without RocksDB

* Fix some tests

* Replace RocksDB sparse storage with Gristore in mutable text index tests

* Use in-memory vector storage in multivector HNSW test

* Flag many more RocksDB specifics in tests

* Use database placeholder type without RocksDB flag

* Flag more tests

* Flag even more tests

* Fix imports, fix typo, and repair base test build

* Initialize dummy database if RocksDB flag is disabled

* Assert correct storage types

* Don't use old vector storage type when RocksDB is disabled

* Expos default for vector storage type only in tests

* Only expose simple segment constructor in tests

* Don't derive Default

* Fix inverted appendable flag
2025-06-11 15:04:27 +02:00
Luis Cossío
93dea164e8 Deterministic HNSW builder (#6477)
* pass a RNG to hnsw index building

* use single-threaded build for accuracy-measuring tests

* clippy
2025-05-07 11:20:19 -04:00
xzfc
89d399ef99 Incremental HNSW index building: append-only case (#6325)
* Pass FeatureFlags into VectorIndexBuildArgs

* Incremental HNSW index building: append-only case

* Use debug_assert

* first_few_ids

* Check deleted_point_count

* Drop unused method
2025-04-09 18:56:53 +00:00
Andrey Vasnetsov
0266508736 disk cache hygiene (#6323)
* wip: implement explicit populate and clear_cache functions for all components

* fmt

* implement clear and populate for vector storages

* fmt

* implement clear and populate for payload storage

* wip: implement explicit populate and clear_cache functions payload indexes

* implement explicit populate and clear_cache functions payload indexes

* fix clippy on CI

* only compile posix_fadvise on linux

* only compile posix_fadvise on linux

* implement explicit populate and clear_cache functions for quantized vectors

* fmt

* remove post-load prefault

* fix typo

* implement is-on-disk for payload indexes, implement clear on drop for segment, implement clear after segment build

* fmt

* also evict quantized vectors after optimization

* re-use and replace advise_dontneed
2025-04-09 10:54:30 +02:00
Arnaud Gourlay
7723d91427 Document Multivector Euclidean scoring discrepancy (#6320) 2025-04-04 15:54:28 +02:00
Tim Visée
3e536347e1 Bump Rust edition to 2024 (#6042)
* Bump Rust edition to 2024

* gen is a reserved keyword now

* Remove ref mut on references

* Mark extern C as unsafe

* Wrap unsafe function bodies in unsafe block

* Geo hash implements Copy, don't reference but pass by value instead

* Replace secluded self import with parent

* Update execute_cluster_read_operation with new match semantics

* Fix lifetime issue

* Replace map_or with is_none_or

* set_var is unsafe now

* Reformat
2025-02-25 11:21:25 +01:00
Andrey Vasnetsov
f7d0814ab6 IO resource usage permit (#6015)
* rename cpu_budget -> resource_budget

* clippy

* add io budget to resources

* fmt

* move budget structures into a separate file

* add extend permit function

* dont extend existing permit

* switch from IO to CPU permit

* do not release resource before aquiring an extension

* fmt

* Review remarks

* Improve resource permit number assertion

* Make resource permit replace_with only acquire extra needed permits

* Remove obsolete drop implementation

* allocate IO budget same as CPU

* review fixes

---------

Co-authored-by: timvisee <tim@visee.me>
2025-02-20 09:05:00 +01:00
xzfc
054273c44b Pass old_indices to HNSWIndex::new (#5835) 2025-01-27 06:54:13 +00:00
xzfc
bf981e525f Split HNSWIndex::open and HNSWIndex::build (#5853)
* HNSWSearchesTelemetry::new()

* Split HNSWIndex::open and HNSWIndex::build
2025-01-24 00:09:57 +00:00
Jojii
fd4705c29d Measure payload read IO (#5773)
* Measure read io for payload storage

* Add Hardware Counter to update functions

* Fix tests and benches

* Rename (some) *_measured functions back to original
2025-01-16 14:25:55 +01:00
xzfc
694ec10f3d GraphLinks: replace trait with enum (#5651)
* GraphLinks: replace trait with enum

* Vec::with_capacity
2024-12-23 18:59:53 +00:00
Ivan Pleshkov
73259267ae GPU HNSW integration (#5535)
* gpu hnsw

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2024-12-05 00:58:49 +01:00
Jojii
73a785f145 Add HardwareCounterCell + CPU measurement for sparse vector search (#5239)
* Add HardwareCounterCell and counting for sparse plain search

* Add measurement for indexed sparse vector

* add tests for calculations

* move SegmentQueryContent higher in the call stack

* move hardware counters inside the query context

* fix clippy

* Fix applying hardware measurements and add test for this

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2024-10-17 16:24:13 +02:00
xzfc
cde39fb8a2 Move build_index out of VectorIndex (#4490)
* Move build_index out of VectorIndex

* Build index in HNSWIndex::open()

* Introduce HnswIndexOpenArgs

* Proper deletion

* Improve tests

* HNSW::open(): add warn, comment and assert

* Revert to making up the config if it does not exist
2024-06-24 14:44:34 +02:00
Andrey Vasnetsov
d4807dcc8b Api consistency update (#4533)
* rename search_params -> params

* rename multivector_config + generate schema

* upd tests
2024-06-23 23:56:42 +02:00
Arnaud Gourlay
571143ae87 Simplify MaxSim configuration (#4171)
* Simplify MaxSim configuration

* enable extension of multivectorconfig

* rename multi_vec_config to multivec_config
2024-05-06 14:19:42 +02:00
Andrey Vasnetsov
4038a0082e Faster deleted filter in proxy segments (#4148)
* [WIP] introduce internal has-id check

* fmt

* update value of the deleted_mask in proxy

* use deleted_points from the context, if present

* fmt

* move stopped flag into query context

* fmt

* segment-specific query context

* enable custom deleted mask in proxy

* remove unused HasIdConditionInternal

* fix tests

* remove debug
2024-05-06 11:51:50 +02:00
Andrey Vasnetsov
c173a9f5e5 Sparse idf dot (#4126)
* introduce QueryContext, which accumulates runtime info needed for executing search

* fmt

* propagate query context into segment internals

* [WIP] prepare idf stats for search query context

* Split SparseVector and RemmapedSparseVector to guarantee we will not mix them up on the type level

* implement filling of the query context with IDF statistics

* implement re-weighting of the sparse query with idf

* fmt

* update idf param only if explicitly specified (more consistent with diff param update

* replace idf bool with modifier enum, improve further extensibility

* test and fixes

* Update lib/collection/src/operations/types.rs

Co-authored-by: Arnaud Gourlay <arnaud.gourlay@gmail.com>

* review fixes

* fmt

---------

Co-authored-by: Arnaud Gourlay <arnaud.gourlay@gmail.com>
2024-04-29 14:54:14 +02:00
Ivan Pleshkov
224e4f600a Byte storage integration into segment (#4049)
* byte storage with quantization

raw scorer integration

config and test

are you happy fmt

fn renamings

cow refactor

use quantization branch

quantization update

* are you happy clippy

* don't use distance in quantized scorers

* fix build

* add fn quantization_preprocess

* apply preprocessing for only cosine float metric

* fix sparse vectors tests

* update openapi

* more complicated integration test

* update openapi comment

* mmap byte storages support

* fix async test

* move .unwrap closer to the actual check of the vector presence

* fmt

* remove distance similarity function

* avoid copying data while working with cow

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2024-04-18 00:42:17 +02:00
Arnaud Gourlay
316d0fa277 Introduce multi vector search benchmark (#4005)
* Introduce multi vector search benchmark

* polish bench
2024-04-12 09:04:18 +02:00