diff --git a/test/collection/test_config_methods.py b/test/collection/test_config_methods.py index 748fdf7e1..784c192d3 100644 --- a/test/collection/test_config_methods.py +++ b/test/collection/test_config_methods.py @@ -83,6 +83,41 @@ def test_collection_config_from_json_with_dropped_vector_index() -> None: assert as_dict["vectorConfig"]["kept"]["vectorIndexType"] == VectorIndexType.HNSW.value +@pytest.mark.parametrize( + "multivector", + [ + {"enabled": True, "aggregation": "maxSim"}, + { + "enabled": True, + "aggregation": "maxSim", + "muvera": {"enabled": True, "ksim": 4, "dprojections": 16, "repetitions": 10}, + }, + ], +) +def test_collection_config_to_dict_keeps_multivector(multivector: Dict[str, Any]) -> None: + """A multi-vector index must round-trip in the shape the server accepts, or it is recreated as a regular index.""" + schema = _schema_with_vector_config( + { + "colbert": { + "vectorizer": {"none": {}}, + "vectorIndexType": "hnsw", + "vectorIndexConfig": {**HNSW_CONFIG, "multivector": multivector}, + }, + "regular": { + "vectorizer": {"none": {}}, + "vectorIndexType": "hnsw", + "vectorIndexConfig": HNSW_CONFIG, + }, + } + ) + + as_dict = _collection_config_from_json(schema).to_dict() + + assert as_dict["vectorConfig"]["colbert"]["vectorIndexConfig"]["multivector"] == multivector + assert "multiVector" not in as_dict["vectorConfig"]["colbert"]["vectorIndexConfig"] + assert "multivector" not in as_dict["vectorConfig"]["regular"]["vectorIndexConfig"] + + def test_collection_config_from_json_missing_vector_index_config_raises() -> None: """A non-dropped vector missing its vectorIndexConfig must fail fast, not parse as None.""" schema = _schema_with_vector_config( diff --git a/weaviate/collections/classes/config.py b/weaviate/collections/classes/config.py index 390578756..945bce0c8 100644 --- a/weaviate/collections/classes/config.py +++ b/weaviate/collections/classes/config.py @@ -2137,6 +2137,11 @@ def to_dict(self) -> Dict[str, Any]: out["sq"] = {**out.pop("quantizer"), "enabled": True} elif isinstance(self.quantizer, _RQConfig): out["rq"] = {**out.pop("quantizer"), "enabled": True} + if self.multi_vector is not None: + multi_vector = out.pop("multiVector") + out["multivector"] = {"enabled": True, "aggregation": multi_vector["aggregation"]} + if "encoding" in multi_vector: + out["multivector"]["muvera"] = multi_vector["encoding"] return out