pgvector trong Sản xuất: Tìm kiếm Vector quy mô lớn & RRF lai trong PostgreSQL

Table of Contents
Trong làn sóng đầu tiên của các ứng dụng AI tạo sinh và Retrieval-Augmented Generation (RAG), các nhóm kỹ sư đã nhanh chóng áp dụng các cơ sở dữ liệu vector chuyên biệt, độc lập (như Pinecone, Weaviate, Qdrant và Milvus).
Tuy nhiên, việc chạy một cơ sở dữ liệu vector riêng biệt song song với một cơ sở dữ liệu quan hệ hiện có sẽ gây ra những rắc rối vận hành nghiêm trọng: lỗi đồng bộ hóa ghi kép, độ trễ nhất quán cuối cùng, chính sách kiểm soát truy cập trùng lặp và các giao dịch phân tán bị rollback đau đớn.
Việc phát hành pgvector (v0.7+) đã đưa PostgreSQL trở thành nền tảng thống trị cho tìm kiếm vector trong sản xuất. Bằng cách lưu trữ các embedding chiều cao trực tiếp trong các bảng PostgreSQL tiêu chuẩn, bạn giữ được các giao dịch ACID, ngữ nghĩa SQL quen thuộc, công cụ sao lưu mạnh mẽ và khả năng kết hợp các truy vấn vector với các khóa ngoại quan hệ trong một truy vấn nguyên tử duy nhất.
Trong hướng dẫn này, chúng ta sẽ phân tích các chiến lược lập chỉ mục trong sản xuất (HNSW so với IVFFlat), tối ưu hóa các tham số bộ nhớ, triển khai Tìm kiếm lai (Hybrid Search) bằng cách sử dụng Reciprocal Rank Fusion (RRF) trong SQL thuần túy và xây dựng một client Python cho sản xuất.
Tại sao nên hợp nhất trên PostgreSQL? Cái bẫy cơ sở dữ liệu kép
Hãy xem xét điều gì sẽ xảy ra khi bạn tách dữ liệu hoạt động của mình khỏi các embedding vector:
[The Dual-Database Trap]
User Action ──► Write to Primary Database (PostgreSQL)
│
▼ (CDC Pipeline / Debezium / Celery Worker)
Dual-Write Lag & Potential Desync!
▼
Write to Vector DB (Pinecone / Qdrant)
[The Unified pgvector Architecture]
User Action ──► Write to PostgreSQL (Atomic Transaction)
├── Relational Metadata (user_id, tenant_id, created_at)
└── High-Dimensional Vector (embedding vector(1536))
✓ Zero Synchronization Lag
✓ ACID Guarantees & Atomic Rollbacks
✓ Unified Row-Level Security (RLS)
Trong pgvector, các embedding vector chỉ đơn giản là một kiểu dữ liệu gốc. Nếu một giao dịch thất bại hoặc bị rollback, các embedding của bạn vẫn nhất quán 100% với các bản ghi quan hệ của bạn.
Thiết lập pgvector và các toán tử khoảng cách
Cài đặt tiện ích mở rộng và xác định kích thước chiều vector của bạn. Kích thước chiều phải khớp chính xác với mô hình embedding của bạn (ví dụ: 1.536 cho OpenAI text-embedding-3-small, hoặc 3.072 cho text-embedding-3-large):
-- Enable the vector extension
CREATE EXTENSION IF NOT EXISTS vector;
-- Create production knowledge base table
CREATE TABLE document_chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
document_id UUID NOT NULL,
tenant_id UUID NOT NULL,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}'::jsonb,
embedding vector(1536) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Chọn Metric khoảng cách phù hợp
pgvector cung cấp ba toán tử khoảng cách:
<=>Khoảng cách Cosine: Đo góc giữa các vector (giá trị từ 0 đến 2, trong đó 0 là giống hệt nhau). Metric tiêu chuẩn cho các embedding văn bản đã được chuẩn hóa.<->Khoảng cách Euclidean (L2): Đo khoảng cách không gian đường thẳng. Lý tưởng khi độ lớn quan trọng.<#>Tích vô hướng âm (Negative Inner Product): Tương đương với tích vô hướng nhân với -1. Nếu mô hình embedding của bạn tạo ra các vector đã được chuẩn hóa trước (như OpenAI hoặc Cohere), tích vô hướng về mặt toán học giống hệt với độ tương đồng cosine nhưng tính toán nhanh hơn 20% đến 30% vì nó bỏ qua bước chuẩn hóa căn bậc hai!
Các chiến lược lập chỉ mục: HNSW so với IVFFlat
Nếu không có chỉ mục, PostgreSQL thực hiện quét tuần tự chính xác trên tất cả các vector (tìm kiếm phẳng O(n)). Mặc dù chính xác 100%, các lần quét phẳng trở nên quá chậm cho sản xuất khi bảng của bạn vượt quá 50.000 vector.
pgvector cung cấp hai thuật toán lập chỉ mục Approximate Nearest Neighbor (ANN):
1. IVFFlat (Inverted File Flat)
- Chia các vector thành các cụm (danh sách) bằng cách sử dụng k-means.
- Yêu cầu điền dữ liệu vào bảng trước khi tạo chỉ mục để thuật toán phân cụm có các mẫu đại diện.
- Thời gian xây dựng vừa phải và tiêu thụ bộ nhớ thấp hơn, nhưng độ chính xác tìm kiếm giảm khi các vector mới được chèn vào.
2. HNSW (Hierarchical Navigable Small World) — Khuyến nghị cho sản xuất
- Xây dựng một đồ thị đa lớp gồm các vector được kết nối.
- Có thể được tạo trên một bảng trống và liên tục duy trì độ chính xác cao khi các hàng mới được chèn vào.
- Truy vấn tìm kiếm nhanh hơn (O(\log n)) và độ chính xác vượt trội (98%+), với chi phí sử dụng RAM cao hơn và thời gian xây dựng chỉ mục lâu hơn.
-- Production HNSW Index Configuration
CREATE INDEX idx_document_chunks_hnsw_cosine
ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
Tinh chỉnh các tham số HNSW
m: Số lượng liên kết hai chiều tối đa trên mỗi nút (mặc định: 16). Các giá trị cao hơn (ví dụ: 24–32) cải thiện độ chính xác cho các embedding chiều cao với chi phí bộ nhớ.ef_construction: Kích thước của danh sách ứng cử viên động được đánh giá trong quá trình xây dựng chỉ mục (mặc định: 64). Tăng lên 128 cải thiện khả năng kết nối đồ thị và độ chính xác của truy vấn.hnsw.ef_search: Được đặt trong thời gian chạy để kiểm soát độ chính xác của truy vấn so với độ trễ:
-- Tune per-session or per-query search depth
SET hnsw.ef_search = 100; -- Default is 40; higher values yield higher recall
Tìm kiếm lai (Hybrid Search): Kết hợp Vector dày đặc với Tìm kiếm từ khóa BM25
Tìm kiếm vector dày đặc rất tuyệt vời trong việc hiểu các từ đồng nghĩa khái niệm ("automobile" khớp với "car"). Tuy nhiên, tìm kiếm vector gặp khó khăn với các tìm kiếm từ khóa chính xác: số bộ phận, mã lỗi (ERR_404_NULL), hoặc tên riêng.
Tiêu chuẩn vàng của ngành là Tìm kiếm lai thông qua Reciprocal Rank Fusion (RRF), kết hợp tìm kiếm toàn văn (tsvector) với khoảng cách vector ngữ nghĩa:
-- Hybrid Search using Reciprocal Rank Fusion in pure PostgreSQL
WITH semantic_search AS (
SELECT id, content, RANK() OVER (ORDER BY embedding <=> '[0.012, -0.045, ...]') AS rank
FROM document_chunks
WHERE tenant_id = 'a1b2c3d4-e5f6-7890-abcd-1234567890ab'
ORDER BY embedding <=> '[0.012, -0.045, ...]'
LIMIT 20
),
keyword_search AS (
SELECT id, content, RANK() OVER (ORDER BY ts_rank_cd(to_tsvector('english', content), query) DESC) AS rank
FROM document_chunks, plainto_tsquery('english', 'database connection pooling') query
WHERE tenant_id = 'a1b2c3d4-e5f6-7890-abcd-1234567890ab'
AND to_tsvector('english', content) @@ query
LIMIT 20
)
SELECT
COALESCE(s.id, k.id) AS id,
COALESCE(s.content, k.content) AS content,
COALESCE(1.0 / (60 + s.rank), 0.0) +
COALESCE(1.0 / (60 + k.rank), 0.0) AS rrf_score
FROM semantic_search s
FULL OUTER JOIN keyword_search k ON s.id = k.id
ORDER BY rrf_score DESC
LIMIT 10;
Tích hợp Python trong sản xuất với SQLAlchemy & pgvector
# db_vector_client.py
import os
from sqlalchemy import create_engine, select, text
from sqlalchemy.orm import declarative_base, Session
from pgvector.sqlalchemy import Vector
Base = declarative_base()
class DocumentChunk(Base):
__tablename__ = 'document_chunks'
id = Column(UUID, primary_key=True)
tenant_id = Column(UUID, nullable=False)
content = Column(Text, nullable=False)
embedding = Column(Vector(1536), nullable=False)
def query_similar_chunks(tenant_id: str, query_embedding: list[float], limit: int = 5):
engine = create_engine(os.getenv("DATABASE_URL"))
with Session(engine) as session:
# Cosine distance ordering using native pgvector operator
stmt = (
select(DocumentChunk)
.filter(DocumentChunk.tenant_id == tenant_id)
.order_by(DocumentChunk.embedding.cosine_distance(query_embedding))
.limit(limit)
)
return session.scalars(stmt).all()
Các câu hỏi thường gặp
pgvector yêu cầu bao nhiêu RAM cho 1.000.000 vector?
Đối với 1.000.000 vector có 1.536 chiều, dữ liệu vector thô chiếm khoảng 6 GB dung lượng lưu trữ. Một chỉ mục HNSW với m=16 thêm khoảng 2.5 GB dữ liệu chỉ mục. Để có độ trễ truy vấn dưới 10ms tối ưu, hãy đảm bảo máy chủ PostgreSQL của bạn có đủ shared_buffers và RAM (ít nhất 16 GB đến 32 GB) để chứa toàn bộ chỉ mục HNSW trong bộ nhớ.
pgvector có thể mở rộng lên 50+ triệu vector không?
Có. Với 10 triệu đến hơn 50 triệu vector, các nhóm sản xuất sử dụng Phân vùng bảng PostgreSQL (ví dụ: phân vùng theo tenant_id hoặc created_at năm). Việc tạo các chỉ mục HNSW cục bộ trên các phân vùng riêng lẻ giúp mỗi chỉ mục đủ nhỏ để nằm gọn trong bộ đệm bộ nhớ.
pgvector so sánh với Pinecone về độ trễ như thế nào?
Khi chỉ mục HNSW nằm gọn trong RAM, pgvector mang lại độ trễ truy vấn từ 4ms đến 12ms, ngang bằng hoặc vượt trội so với các cơ sở dữ liệu vector đám mây chuyên dụng trong khi loại bỏ độ trễ truyền mạng internet giữa máy chủ API của bạn và các điểm cuối cơ sở dữ liệu của bên thứ ba.
Bạn cũng có thể thích
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles
PostgreSQL Vacuum & Bloat Index: Phát hiện, Giảm thiểu và Tinh chỉnh Tự động
Chẩn đoán và loại bỏ tình trạng phình (bloat) bảng và index trong PostgreSQL. Nắm vững các công thức tinh chỉnh autovacuum, nén dữ liệu không downtime với pg_repack, và cơ chế visibility map của MVCC.
Read more
SQLite trong Môi trường Production: Chế độ WAL, Chịu tải cao, và các PRAGMA đã được kiểm chứng
Làm chủ SQLite trong môi trường production có lưu lượng truy cập cao. Tìm hiểu về Write-Ahead Logging (WAL), tinh chỉnh busy timeout, giới hạn đọc/ghi đồng thời, và các benchmark thực tiễn.
Read moreTìm kiếm Vector ở quy mô lớn: So sánh Chỉ mục HNSW và IVFFlat trong pgvector và SQLite-vec
So sánh các thuật toán chỉ mục vector HNSW và IVFFlat trong pgvector và sqlite-vec. Phân tích độ chính xác recall, thời gian xây dựng, dung lượng bộ nhớ và độ trễ truy vấn.
Read more