Skip to content

feat: add support for PolarDB for PostgreSQL HNSW - #860

Open
cxyybless wants to merge 1 commit into
zilliztech:mainfrom
cxyybless:feat/polardb-pg-hnsw
Open

feat: add support for PolarDB for PostgreSQL HNSW#860
cxyybless wants to merge 1 commit into
zilliztech:mainfrom
cxyybless:feat/polardb-pg-hnsw

Conversation

@cxyybless

Copy link
Copy Markdown

Summary

This PR adds a pgvector-compatible PolarDB for PostgreSQL HNSW client
to VectorDBBench. It is separate from the existing MySQL-compatible
PolarDB client and does not change the existing polardb* commands.

Supported features

  • HNSW index creation and search
  • PQ, SQ4, SQ8, and RaBitQ internal quantization
  • CLI command: vectordbbench polardbpghnsw
  • Streamlit configuration and result visualization
  • Optional Graph Cache readiness handling before search benchmarks
  • Reuse of the existing pgvector dependency extra

PolarDB-specific internal quantization and Graph Cache options require
PolarDB vector extension 0.8.3.1 or later.

Implementation

  • Reuse the PgVector client and HNSW configuration where behavior is
    compatible.
  • Add PolarDB-specific index options and validation without duplicating
    the PostgreSQL client implementation.
  • Build or validate Graph Cache after index creation and for search-only
    runs when requested.
  • Redact PostgreSQL connection passwords from client logs.
  • Add PolarDBPG configuration, lifecycle, CLI, and frontend tests.

Testing

  • Python 3.11.15:
    • make lint
    • existing dataset unit test
    • 76 PolarDBPG and client-resolution tests
  • Python 3.12.13:
    • make lint
    • existing dataset unit test
    • 76 PolarDBPG and client-resolution tests
    • wheel build with pip wheel --no-deps .
  • PolarDB for PostgreSQL 16.14 with vector extension 0.8.3.1:
    • full 50K x 1536D load and RaBitQ 8-bit HNSW index build
    • Graph Cache reached ready and usable=yes before search
    • Recall@100: 0.9909
    • search-only runs with Graph Cache lifecycle enabled and skipped
    • plain, PQ, SQ4, and SQ8 HNSW index creation and query smoke tests
    • verified that logs and result files do not expose the database password

@sre-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: cxyybless
To complete the pull request process, please assign xuanyang-cn after the PR has been reviewed.
You can assign the PR to them by writing /assign @xuanyang-cn in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@cxyybless

Copy link
Copy Markdown
Author

/assign @XuanYang-cn

def __init__(self, *args, drop_old: bool = False, **kwargs):
super().__init__(*args, drop_old=drop_old, **kwargs)
self.name = "PolarDBPG"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vectordb_bench/backend/clients/polardb_pg/polardb_pg.py line:69
Low ---- self.name is assigned after super().init() returns, so every log line emitted during PgVector.init (config values, create/drop table, create/drop index) and the "config must create an index" RuntimeError message still print "PgVector" for PolarDBPG runs. Consider setting self.name before delegating to the base constructor (or overriding it as a class attribute) so operators can filter PolarDBPG logs consistently.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b94d1c. PgVector.name is now a class attribute and PolarDBPgHNSW overrides it with PolarDBPG, so logs emitted by the base constructor use the correct client name. Added regression coverage for the initialization log.

Comment thread vectordb_bench/models.py Outdated
pq_nbits = "pq_nbits"

# PolarDB for PostgreSQL parameters
hnsw_quantization = "quantization"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vectordb_bench/models.py line:177
Low ---- hnsw_quantization = "quantization" duplicates the existing mongodb_quantization_type = "quantization" value, so Python's Enum makes hnsw_quantization a silent alias (CaseConfigParamType.hnsw_quantization.name == "mongodb_quantization_type", and the member is skipped when iterating the enum). The docstring says the value is the key used in CaseConfig.params and the UI, so two unrelated DBs now share the key "quantization". Nothing currently does a reverse lookup, but any future CaseConfigParamType(key) or name-based serialization cannot distinguish them. Consider a distinct value such as "hnsw_quantization".

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b94d1c. hnsw_quantization now has a distinct enum value. PolarDBPgHNSWConfig accepts both the frontend hnsw_quantization key and the CLI quantization key, preserving index-option generation. Added coverage for enum identity and frontend-to-config mapping.

Comment thread tests/test_polardb_pg.py


def test_polardb_pg_cli_help():
result = CliRunner().invoke(PolarDBPgHNSWCommand, ["--help"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/test_polardb_pg.py line:306
Medium ---- The CLI is only exercised via --help, which never builds PolarDBPgConfig/PolarDBPgHNSWConfig or reaches run(); the ~30-option plumbing (PgVectorTypedDict + HNSWFlavor1 + PolarDBPgHNSWOptions -> config constructors -> TaskConfig) is therefore untested. A test invoking the command with required options plus --dry-run would validate that wiring without a live database, since run() returns before benchmark_runner.run() when dry_run is set.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b94d1c. Added a real polardbpghnsw --dry-run test with Graph Cache and RaBitQ options. It verifies TaskConfig construction, option propagation, skipped benchmark execution, and password redaction.

# Search-only benchmarks skip optimize(), so validate and prepare the
# existing index before any search workers can start.
if not drop_old and self.case_config.graph_cache:
with self.init():

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vectordb_bench/backend/clients/polardb_pg/polardb_pg.py line:73
Low ---- For search-only runs (drop_old=False) the graph-cache readiness wait runs synchronously inside init during _pre_run, outside the case-level optimize/load timeout wrappers, and is capped only by the hard-coded _GRAPH_CACHE_TIMEOUT_SECONDS = 3600 with no CLI/frontend knob (the tests explicitly assert --graph-cache-timeout is absent). A stuck or slow cache build therefore holds the runner process for up to an hour with no way to tune it. Consider exposing the timeout (or poll interval) as an option so operators can bound search-only runs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7b94d1c. Graph Cache wait timeout is now configurable through the Pydantic config, CLI --graph-cache-timeout, and Streamlit UI, with positive-integer validation and a 3600-second default. Lifecycle, CLI, and frontend tests cover the new setting.

Add a pgvector-compatible PolarDB for PostgreSQL HNSW client to the
command-line and Streamlit interfaces. Keep it separate from the existing
MySQL-compatible PolarDB client.

Support PQ, SQ4, SQ8, and RaBitQ index options and optional Graph Cache
readiness handling. Reuse the pgvector dependency extra, add configuration
and lifecycle tests, and redact connection passwords from PgVector logs.
@cxyybless
cxyybless force-pushed the feat/polardb-pg-hnsw branch from 38b3dbe to 7b94d1c Compare August 31, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants