Schedule icon
Webhook icon
Query icon
Script icon
Docker icon
Log icon
If icon
SlackIncomingWebhook icon
Loop icon
Set icon

pgvector HNSW Index Bloat & Rebuild Maintenance Gate

Audit pgvector HNSW index bloat and recall loss, execute non-blocking concurrent rebuilds with lock timeout guards, and track build metrics in Kestra KV.

Categories
AIData

How it works

Hierarchical Navigable Small World (HNSW) indexes in pgvector construct multi-layer graphs to deliver low-latency approximate nearest neighbor (ANN) vector search. Under continuous updates and deletes in PostgreSQL, base table dead tuples accumulate through Multi-Version Concurrency Control (MVCC). While VACUUM cleans table heap pages, HNSW index graphs can suffer from unlinked edges, stale routing paths, and index bloat where index relation size outgrows table storage. This fragmentation forces vector similarity queries to traverse dead nodes, increasing disk I/O blocks read from disk (pg_statio_user_indexes.idx_blks_read) and degrading recall@k accuracy.

This workflow automates HNSW index health evaluation and concurrent remediation:

  1. Catalog Inspection: Queries pg_class, pg_index, pg_am, pg_namespace, pg_stat_user_tables, and pg_statio_user_indexes (io.kestra.plugin.jdbc.postgresql.Query). It identifies all HNSW indexes (amname = 'hnsw'), extracts vector distance operators (<=>, <#>, <->), measures index size versus table size ratios, and calculates table dead tuple churn.
  2. ANN Performance & Recall Benchmark: Executes a sample vector probe directly in PostgreSQL (io.kestra.plugin.jdbc.postgresql.Query). It compares top-k results from an exact sequential scan (enable_indexscan = off) against approximate HNSW index scans (enable_indexscan = on), computing actual recall@k and query execution latency in milliseconds.
  3. Maintenance Decision Gate: Evaluates catalog statistics and benchmark metrics using Python (io.kestra.plugin.scripts.python.Script). An index is flagged for rebuild if its bloat ratio exceeds bloat_ratio_threshold, table dead tuple ratio exceeds dead_tuple_ratio_threshold_pct, ANN latency exceeds ann_latency_threshold_ms, or recall drops below min_recall_threshold.
  4. Slack Operational Alerting: Dispatches degraded index summaries and recall metrics to Slack (io.kestra.plugin.slack.notifications.SlackIncomingWebhook).
  5. Concurrent Reindex with Lock Timeout Guard: Executes REINDEX INDEX CONCURRENTLY in an isolated session configured with lock_timeout via JDBC URL options (options=-c lock_timeout=...). This acquires a weak ShareUpdateExclusiveLock, permitting concurrent reads and writes during the rebuild while aborting safely if lock contention occurs.
  6. KV Telemetry & Post-Build Validation: Queries post-rebuild relation sizes, verifies index validity (indisvalid), calculates duration and storage reduction percentages, and writes atomic JSON telemetry to Kestra KV under pgvector_hnsw_rebuild_{index_name} (io.kestra.plugin.core.kv.Set).

What you get

  • Automated Bloat & Churn Detection: Identifies bloated vector index graphs before query latency spikes breach production service level objectives (SLOs).
  • Recall Drift Detection: Measures ground-truth recall@k degradation against exact vector scans to prevent stale retrieval in Retrieval-Augmented Generation (RAG) pipelines.
  • Non-Blocking Rebuilds: Executes REINDEX INDEX CONCURRENTLY so production vector searches and application writes remain online.
  • Lock Timeout Protection: Prevents maintenance tasks from queueing behind long-running analytical queries or blocking OLTP transactions.
  • Auditable KV Telemetry: Tracks index build duration, reclaimed storage, and bloat reduction in Kestra KV for historical trend analysis.

Who it's for

  • AI engineers maintaining pgvector backends for RAG pipelines and vector search APIs.
  • Database administrators (DBAs) and Platform engineers managing PostgreSQL clusters with high vector ingestion churn.
  • SRE and Data Ops teams establishing automated Day 2 database maintenance and health gates.

Why orchestrate this with Kestra

  • Hybrid SQL and Script Orchestration: Seamlessly coordinate PostgreSQL catalog inspection, in-database recall benchmarking, and Python telemetry processing within a single unified pipeline.
  • Zero-Dependency Execution: Perform vector recall audits directly inside PostgreSQL without exporting embeddings to external benchmark runners.
  • Built-in KV State Tracking: Store per-index rebuild history, reclaimed megabytes, and durations directly in Kestra namespace KV without external databases.
  • Deterministic Scheduling and Webhooks: Run maintenance during scheduled off-peak windows or trigger ad-hoc evaluations following batch embedding ingestion.

Prerequisites

  • PostgreSQL 15+ cluster with the pgvector extension installed and enabled (CREATE EXTENSION IF NOT EXISTS vector;).
  • Database user with permissions to query catalog tables (pg_class, pg_index, pg_stat_user_tables, pg_statio_user_indexes) and execute REINDEX INDEX CONCURRENTLY.
  • Network connectivity from the Kestra worker to the PostgreSQL host.

Secrets

  • POSTGRES_PASSWORD: Password for the PostgreSQL database user.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook URL for alerting on index degradation and rebuild completions.
  • PGVECTOR_MAINTENANCE_WEBHOOK_KEY: Secret authentication key for the inbound webhook trigger.

Quick start

  1. Store your credentials in Kestra Secrets:
    • Set POSTGRES_PASSWORD with your PostgreSQL password.
    • Set SLACK_WEBHOOK_URL with your Slack incoming webhook endpoint.
    • Set PGVECTOR_MAINTENANCE_WEBHOOK_KEY with a random secure token.
  2. Configure the flow inputs:
    • postgres_url: JDBC URL pointing to your PostgreSQL instance (e.g. jdbc:postgresql://postgres.internal:5432/vectors).
    • target_schema: Target schema containing vector tables (default: public).
    • target_table: Name of your vector embedding table (e.g. documents).
    • vector_column: Name of your embedding column (e.g. embedding).
  3. Run an initial test with dry_run: true to inspect index bloat and measure recall without executing rebuilds.
  4. Enable the off_peak_schedule trigger to run weekly automated maintenance at 03:00 UTC.

How to extend

  • Dynamic HNSW Parameter Retuning: Combine with ALTER INDEX ... SET (ef_construction = ...) to tune graph construction density during periodic off-peak rebuilds.
  • Multi-Table Sweeps: Extend the scan query and loop to iterate over all vector tables across multiple microservice databases.
  • PagerDuty & Opsgenie Integration: Replace or augment the Slack notification task with io.kestra.plugin.pagerduty.notifications.PagerDutyAlert for high-severity recall drops.
  • Grafana & Prometheus Metrics Export: Export reclaimed gigabytes and ANN search latencies to Prometheus using io.kestra.plugin.core.http.Request to visualize vector index health over time.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.