diff --git a/src/arcadedb/core.py b/src/arcadedb/core.py index c233326..0b9b9d0 100644 --- a/src/arcadedb/core.py +++ b/src/arcadedb/core.py @@ -1545,11 +1545,16 @@ def create_vector_index( below the corpus makes the build re-read vectors from the documents. Set an absolute count only to bound a build on a deliberately small heap. - mutations_before_rebuild: Per-index override for mutations threshold - before triggering a graph rebuild (maps to Java metadata key - "mutationsBeforeRebuild"; uses GlobalConfiguration default if None). - Typical ranges: 100–300 for freshness-heavy workloads; 300–800 for - write-heavy workloads and larger graphs. + mutations_before_rebuild: Floor of the rebuild threshold (maps to Java + metadata key "mutationsBeforeRebuild"; the engine default, 100, if + None). The graph is rebuilt after max(this, min(graph size x + arcadedb.vectorIndex.rebuildGraphRatio, arcadedb.vectorIndex. + maxPendingMutations)) changes (defaults 0.2 and 50000), so any + value below the ratio term has no effect: at 100000 vectors the + threshold is 20000 whether this is 100 or 800. Raise it above that + term to rebuild less often. To rebuild sooner, lower + rebuildGraphRatio (a database-scope setting); with the ratio at 0 + the threshold is exactly this value. pq_subspaces: Number of PQ subspaces (M). Requires quantization="PRODUCT". pq_clusters: Clusters per subspace (K). Requires quantization="PRODUCT". In current ArcadeDB engine builds, this should not exceed the diff --git a/tests/test_vector_index_introspection.py b/tests/test_vector_index_introspection.py index 89a254d..0efb182 100644 --- a/tests/test_vector_index_introspection.py +++ b/tests/test_vector_index_introspection.py @@ -229,3 +229,31 @@ def test_without_product_quantization_it_raises(self, temp_db): with pytest.raises(arcadedb.ArcadeDBError): index.find_nearest_approximate([0.9, 0.1, 0.0], k=1) + + +class TestRebuildThreshold: + """``mutations_before_rebuild`` is the FLOOR of the rebuild threshold (#110). + + The engine rebuilds after max(mutations_before_rebuild, min(graph size x rebuildGraphRatio, maxPendingMutations)) + changes; with the defaults (ratio 0.2, cap 50000) a 1000-vector graph gives 200 for any floor up to 200. The + vectors are distinct and nonzero (cosine is the default similarity). + """ + + ROWS = [ + (f"v{i}", [1.0 + i % 10, 1.0 + i // 10 % 10, 1.0 + i // 100]) + for i in range(1000) + ] + + @pytest.mark.parametrize("floor, expected", [(10, 200), (100, 200), (5000, 5000)]) + def test_the_threshold_is_the_larger_of_the_floor_and_the_ratio_term( + self, temp_db, floor, expected + ): + _make_type(temp_db) + _insert(temp_db, self.ROWS) + index = temp_db.create_vector_index( + "Doc", "embedding", dimensions=3, mutations_before_rebuild=floor + ) + + stats = index.get_stats() + assert stats["totalVectors"] == len(self.ROWS) + assert stats["effectiveMutationsThreshold"] == expected