fix(db): use global fact-type partial vector indexes - #3535
fix(db): use global fact-type partial vector indexes#3535Sanderhoff-alt wants to merge 1 commit into
Conversation
aebcf8f to
37ae077
Compare
Replace per-bank vector indexes with three indexes shared by all banks. Each index is partial on one fact_type: world, experience, or observation. Drop legacy per-bank and unfiltered global indexes during migration. Keep Oracle unchanged because its partitioned global index is not partial. Remove vector-index DDL from bank creation, import, and deletion paths. Make reconciliation validate the migration-owned global layout. Update lifecycle, migration, and vector-index health tests for the new contract. Preserve go client go.mod/go.sum across regeneration so go mod tidy keeps pinned dependency versions instead of resolving testify to @latest, which broke verify-generated-files whenever upstream published a release.
37ae077 to
98ea4bb
Compare
|
Closing this — it was superseded by #3561 (merged) and #3541. WhyThe two approaches this PR explored were the global fact-type index layout (#3535) and the per-bank-by-size layout that #3561 shipped. The evidence in #3485 settled it in favor of per-bank-by-size:
#3561 keeps the per-bank layout but earns indexes by size ( #3541 (still open) complements it by enabling Closing to avoid two competing layouts in the tree. Happy to reopen if a multi-bank benchmark shows the global layout is needed. |
Summary
This change replaces PostgreSQL per-bank vector indexes with three global fact-type partial vector indexes. The indexes cover all banks while keeping a separate ANN index for each fact type:
world,experience, andobservation.The goal is to remove bank-count-dependent planning overhead without restoring the old unfiltered-global-index post-filter path that caused filtered ANN recall regressions.
Closes #3485
Background
The previous layout created three vector indexes for every bank. As the number of banks grew, PostgreSQL had to consider an increasingly large index catalog for parameterized recall queries. Planning time therefore grew with bank count, and end-to-end recall latency could degrade approximately linearly even when each bank contained relatively few memories.
The target layout is:
fact_typefact_typebank_idpost-filterDesign
The migration creates these canonical indexes:
idx_mu_emb_worldidx_mu_emb_experienceidx_mu_emb_observationFor pgvector they are HNSW indexes using the existing cosine operator class. The backend abstraction remains intact for pgvectorscale and vchord. ScaNN keeps its existing unfiltered global-index path because it does not use the PostgreSQL partial-index layout.
The migration removes legacy per-bank and stale unfiltered indexes, then uses concurrent DDL inside an Alembic autocommit block. A short lock timeout makes a busy deployment fail quickly and retry idempotently instead of waiting indefinitely. Bank creation, archive import, and bank deletion no longer issue vector-index DDL.
Backend Switches
A populated deployment that changes vector backend must use:
The command checks the migration-owned layout and rebuilds only missing, invalid, or unexpected indexes. PostgreSQL ANN indexes use
DROP INDEX CONCURRENTLYandCREATE INDEX CONCURRENTLYon a raw autocommit connection. Startup reconciliation rebuilds an empty table automatically and fails closed with the command above in the error message when data is present.Downgrading removes the global indexes and recreates the prior per-bank layout for existing banks. Upgrading is idempotent and removes both named legacy indexes and catalog-discovered per-bank indexes.
Recall Correctness
Every recall arm retains its
fact_typepredicate. Semantic ANN arms over-fetch by 5x, with a minimum of 100 candidates, before trimming and reranking. The existingef_search=200setting remains in effect.The global layout can still encounter the filtered-ANN under-return shape documented in #2645: a small bank may be underrepresented when
bank_idis applied after scanning a large shared index. On pgvector 0.8+, connection setup detectspg_extension.extversionand enables:20000is explicitly pinned to the pgvector upstream default. Older pgvector versions continue to use the existing over-fetch, fact-type predicate, and reranking safeguards. The scan budget is intentionally not increased until a multi-bank benchmark demonstrates that a higher value is necessary.Backend Compatibility
Oracle is unchanged. Oracle 23ai uses its existing partitioned global vector index and does not support PostgreSQL-style partial vector indexes; the new migration is dispatched only for PostgreSQL.
Verification
The following areas are covered by the updated tests:
ruff,ruff format, andty check hindsight_apipass. Focused migration, vector-index, health, and link-utils tests pass. The repository lint hook's ESLint phase requires the separately installed@eslint/jspackage and could not run in this worktree.Validation on the repository pg0 instance confirmed
pgvector 0.8.5. A real asyncpg pool connection initialized by the new setup path reportedhnsw.iterative_scan = relaxed_orderandhnsw.max_scan_tuples = 20000. This validates parameter wiring and the #2645 regression guard; it is not a substitute for a recall benchmark across bank sizes.Baseline Validation
Before merge, the benchmark suites should be run on both
origin/mainand this branch under the same PostgreSQL/pgvector version, dataset, warm-up, and concurrency settings:./scripts/benchmarks/run-longmemeval.sh./scripts/benchmarks/run-locomo.sh./scripts/benchmarks/run-perf-test.shResults should be compared between baseline and branch rather than evaluating this branch in isolation. The performance run should include multiple banks with strongly different sizes and report small-bank recall, planning time, execution time, and tail latency. LongMemEval and LoCoMo should be checked for end-to-end quality or latency regressions.
The default
run-perf-test.sh --suite recallsetup creates one bank, so a multi-bank fixture or equivalent data setup is required for the #2645 filtered-ANN scenario. The multi-bank run should also be used to decide whether the explicit20000scan budget should be increased.