Implementation:Neuml Txtai PGVector ANN
| Knowledge Sources | |
|---|---|
| Domains | Vector_Search, Database |
| Last Updated | 2026-02-09 17:00 GMT |
Overview
PGVector is a PostgreSQL-backed approximate nearest neighbor (ANN) index that uses the pgvector extension for scalable vector similarity search with HNSW indexing.
Description
The PGVector class inherits from ANN and provides a persistent vector index stored in a PostgreSQL database using the pgvector extension. It leverages SQLAlchemy for database interaction and supports three vector storage modes: full-precision 32-bit float vectors (VECTOR), half-precision 16-bit vectors (HALFVEC), and binary bit vectors (BIT) for scalar quantization. Search uses max inner product for float vectors and hamming distance for bit vectors, both with HNSW indexes for approximate nearest neighbor retrieval.
The class manages database connections, schema creation, table initialization, and HNSW index construction. Configuration parameters control the HNSW graph structure (m, ef_construction), table naming, schema, precision, and quantization settings.
Usage
Use PGVector when you need a production-grade, networked ANN index backed by PostgreSQL. It is ideal for environments that already use PostgreSQL, need transactional guarantees, or require multi-process concurrent access to the same vector index. The quantization option reduces storage and can improve throughput at the cost of recall accuracy.
Code Reference
Source Location
- Repository: Neuml_Txtai
- File: src/python/txtai/ann/dense/pgvector.py
- Lines: 1-323
Signature
class PGVector(ANN):
"""
Builds an ANN index backed by a Postgres database.
"""
def __init__(self, config):
super().__init__(config)
if not PGVECTOR:
raise ImportError('PGVector is not available - install "ann" extra to enable')
# Database connection
self.engine, self.database, self.connection, self.table = None, None, None, None
# Scalar quantization
quantize = self.config.get("quantize")
self.qbits = quantize if quantize and isinstance(quantize, int) and not isinstance(quantize, bool) else None
Import
from txtai.ann.dense import PGVector
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| config | dict | Yes | Index configuration dictionary containing backend settings, dimensions, and optional pgvector-specific keys such as url, table, schema, m, efconstruction, precision, and quantize
|
Outputs
| Name | Type | Description |
|---|---|---|
| self.engine | sqlalchemy.Engine | SQLAlchemy database engine connected to PostgreSQL |
| self.database | sqlalchemy.orm.Session | Active SQLAlchemy session for query execution |
| self.table | sqlalchemy.Table | SQLAlchemy table object representing the vectors table |
| self.config | dict | Updated configuration with offset and build metadata
|
Key Methods
load(self, path)
Initializes the database connection and table objects for an existing pgvector index. Calls initialize() to set up the session and verify the table exists.
index(self, embeddings)
Recreates the vectors table, inserts all embeddings as rows with sequential index ids, creates an HNSW index on the embedding column, and records build metadata including HNSW settings (m, ef_construction).
append(self, embeddings)
Inserts new embeddings starting from the current offset. Each embedding is prepared according to the active precision/quantization mode before insertion.
delete(self, ids)
Deletes rows from the vectors table matching the given index ids using a SQL WHERE IN clause.
search(self, queries, limit)
Executes a similarity query for each input query vector. Uses max_inner_product for float vectors or hamming_distance for bit vectors, ordered by score with the specified limit. Returns [(id, score)] per query.
count(self)
Returns the count of rows in the vectors table via a SQL COUNT query.
save(self, path)
Commits the current database session and connection.
close(self)
Closes the database session and disposes of the SQLAlchemy engine.
initialize(self, recreate=False)
Connects to the database, sets the schema, creates the vectors table (with optional drop/recreate), and configures the pgvector extension.
connect(self)
Establishes a new database connection using the configured URL (from settings or ANN_URL environment variable), creates the SQLAlchemy engine with StaticPool, and initializes the pgvector extension.
Usage Examples
Basic Usage
import numpy as np
from txtai.ann.dense import PGVector
# Configuration for PGVector backend
config = {
"backend": "pgvector",
"dimensions": 384,
"pgvector": {
"url": "postgresql://user:pass@localhost:5432/vectors",
"table": "embeddings",
"m": 16,
"efconstruction": 200
}
}
# Create and build the index
ann = PGVector(config)
embeddings = np.random.rand(1000, 384).astype(np.float32)
ann.index(embeddings)
# Search for similar vectors
queries = np.random.rand(1, 384).astype(np.float32)
results = ann.search(queries, limit=5)
# results: [[(id, score), ...]]
# Append new data
new_embeddings = np.random.rand(50, 384).astype(np.float32)
ann.append(new_embeddings)
# Persist changes
ann.save("/unused/path")
# Count records
print(ann.count()) # 1050
# Cleanup
ann.close()
Half-Precision Usage
config = {
"backend": "pgvector",
"dimensions": 384,
"pgvector": {
"url": "postgresql://user:pass@localhost:5432/vectors",
"precision": "half"
}
}
ann = PGVector(config)