Phản biện về PGVector
(alex-jacobs.com)- Phần mở rộng Postgres pgvector hỗ trợ tìm kiếm độ tương đồng vector, nhưng khoảng cách giữa mức demo và môi trường vận hành thực tế là rất lớn
- Cả chỉ mục IVFFlat và HNSW đều có ưu và nhược điểm rõ rệt; đặc biệt HNSW gặp vấn đề về mức sử dụng bộ nhớ lên đến vài GB khi tạo chỉ mục và thời gian build dài
- Tìm kiếm thời gian thực và cập nhật chỉ mục về mặt cấu trúc vốn đã khó, và khi chèn/cập nhật liên tục sẽ phát sinh tranh chấp khóa và suy giảm hiệu năng
- Do chiến lược lọc (Pre/Post) và giới hạn của query planner, sẽ xuất hiện sự cân bằng thiếu ổn định giữa độ chính xác tìm kiếm và tốc độ
- Các chức năng do cơ sở dữ liệu vector chuyên dụng (Pinecone, Weaviate, v.v.) cung cấp phải được tự triển khai thủ công, và kết quả là độ phức tạp vận hành cùng chi phí tăng lên
Tổng quan về các giới hạn của pgvector
- pgvector là một extension bổ sung khả năng tìm kiếm độ tương đồng vector cho Postgres; nó hoạt động tốt trong các demo đơn giản nhưng gặp vấn đề về khả năng mở rộng trong môi trường vận hành
- Nhiều bài blog chỉ đề cập đến cài đặt và ví dụ truy vấn đơn giản, còn các vấn đề về hiệu năng, bộ nhớ và quản lý chỉ mục khi vận hành thì hầu như không được nhắc tới
Vấn đề trong việc lựa chọn chỉ mục
- pgvector cung cấp hai loại chỉ mục là IVFFlat và HNSW
- IVFFlat: cấu trúc dựa trên cụm, tốc độ tạo chỉ mục nhanh nhưng việc thiết lập số lượng cụm ảnh hưởng lớn đến hiệu năng và độ chính xác
- Không thể tái phân bổ cụm nên cần tái dựng chỉ mục định kỳ
- HNSW: cấu trúc đồ thị nhiều lớp, mang lại độ chính xác và hiệu năng ổn định nhưng mức sử dụng bộ nhớ khi tạo chỉ mục rất cao và tốc độ chậm
- IVFFlat: cấu trúc dựa trên cụm, tốc độ tạo chỉ mục nhanh nhưng việc thiết lập số lượng cụm ảnh hưởng lớn đến hiệu năng và độ chính xác
- Khi tạo chỉ mục cho hàng triệu vector, có thể cần hơn 10GB RAM, đây là mối đe dọa trực tiếp đến độ ổn định của DB đang vận hành
Khó khăn của tìm kiếm thời gian thực
- Dữ liệu mới cần phải có thể được tìm kiếm ngay sau khi chèn, nhưng do cấu trúc cập nhật chỉ mục nên rất khó phản ánh theo thời gian thực
- IVFFlat: vector mới được thêm vào cụm hiện có, theo thời gian sẽ phát sinh mất cân bằng cụm → cần rebuild định kỳ
- HNSW: khi chèn sẽ cập nhật đồ thị, gây ra tranh chấp khóa và tải bộ nhớ
- Trong quá trình tái dựng chỉ mục, rất khó duy trì tính nhất quán dữ liệu và đảm bảo tính liên tục của dịch vụ
- Trong môi trường vận hành, cần nhiều chiến lược lách vấn đề như staging table, chỉ mục kép, build offline, eventual consistency
Giới hạn của lọc và query planner
- Khi kết hợp lọc metadata như
status,user_id,categoryvới tìm kiếm vector, việc chọn Pre-filter hay Post-filter ảnh hưởng lớn đến hiệu năng- Pre-filter phù hợp với bộ lọc có tính chọn lọc cao, nhưng sẽ chậm khi dữ liệu lớn
- Post-filter nhanh hơn nhưng có khả năng bỏ sót kết quả sau khi lọc
- Query planner của Postgres không hiểu mô hình chi phí của độ tương đồng vector, thông tin thống kê không chính xác nên tạo ra kế hoạch thực thi kém hiệu quả
- Kết quả là cần các giải pháp tạm thời như CTE, partitioning, viết lại truy vấn, và điều này kém hiệu quả khi mở rộng quy mô
So sánh với cơ sở dữ liệu vector chuyên dụng
- Pinecone, Weaviate, OpenSearch k-NN, v.v. mặc định cung cấp tự động chọn chiến lược lọc, tìm kiếm hybrid, indexing thời gian thực, mở rộng theo chiều ngang
- Trong pgvector, các chức năng này phải tự triển khai, dẫn đến độ phức tạp vận hành và gánh nặng bảo trì
- pgvectorscale của Timescale cung cấp StreamingDiskANN, build chỉ mục tăng dần, cải thiện lọc, v.v., nhưng
- không được hỗ trợ trên AWS RDS và vẫn tồn tại gánh nặng cài đặt, quản lý extension bổ sung
Chi phí và các cân nhắc vận hành
- Cơ sở dữ liệu vector chuyên dụng là dịch vụ trả phí, nhưng nếu tính đến việc overprovision hạ tầng Postgres, quản lý chỉ mục và thời gian kỹ sư, thì trên thực tế có thể rẻ hơn
- Ví dụ, Turbopuffer bắt đầu từ $64/tháng và mang lại sự đơn giản trong vận hành cùng khả năng mở rộng
Kết luận và khuyến nghị
- pgvector rất xuất sắc về mặt kỹ thuật nhưng có nhiều ràng buộc trong môi trường vận hành
- Những điểm cốt lõi cần cân nhắc khi xây dựng hệ thống vận hành
- Độ phức tạp của quản lý chỉ mục và nhu cầu bộ nhớ cao
- Giới hạn của query planner dẫn đến lọc kém hiệu quả
- Chi phí của indexing thời gian thực và sự suy giảm chất lượng
- Sự đơn giản hóa quá mức trong các tài liệu blog
- Lý do tồn tại của cơ sở dữ liệu vector chuyên dụng và hiệu quả của chúng
- Kết luận lại, độ phức tạp vận hành lớn hơn sự đơn giản của việc tích hợp với Postgres, và với phần lớn đội ngũ, sử dụng cơ sở dữ liệu vector chuyên dụng là lựa chọn thực tế hơn
5 bình luận
Dù vậy, với truy vấn kết hợp (embedding + SQL truyền thống) thì vẫn không gì bằng pg_vector.
Tôi nghĩ rằng để hệ sinh thái trở nên lành mạnh hơn thì cũng cần có nhiều ý kiến phản biện đối với những lời tung hô vạn năng.
Tôi đồng ý. Với các tổ chức vốn đã dùng Postgres tốt từ trước và bắt đầu VectorDB với lượng dữ liệu nhỏ, pgVector rõ ràng là một lựa chọn rất tốt, nhưng khi lưu lượng truy cập tăng lên, đặc biệt là write traffic, thì có vẻ những vấn đề mà tác giả bài gốc nêu ra sẽ trở thành nút thắt cổ chai.
Đúng vậy. Vì không có gì là hoàn hảo cả. Tôi nghĩ có thể chấp nhận kiểu nói như “còn có việc cấp bách khác”, nhưng không nên chấp nhận “mức hiện tại cũng đã đủ rồi”.
Ý kiến trên Hacker News
Chúng tôi tại Discourse đã dùng pgvector trong môi trường production trên hàng nghìn cơ sở dữ liệu
Nó được dùng cho phần lớn pageview, và tính năng Iterative Scans được thêm từ phiên bản 0.8.0 để cải thiện các vấn đề lọc trước/sau
Với một dịch vụ đơn lẻ thì vector DB chuyên dụng có thể dễ hơn, nhưng đó không phải là lời giải vạn năng
Dùng halfvec (float 16 bit) để lưu trữ, và bit (binary vectors) cho index để vừa tối ưu chi phí lưu trữ vừa đảm bảo hiệu năng
Chúng tôi dùng Vespa để thực hiện tìm kiếm kiểu map-reduce ở cấp node
Để làm điều tương tự với Postgres có lẽ sẽ cần sharding và logic ứng dụng phức tạp
Việc reindex hoặc phi chuẩn hóa metadata có lẽ sẽ luôn mất nhiều thời gian
Dù vậy vector DB cũng không phải vạn năng, và những hệ thống hỗ trợ lọc quan hệ như Vespa hiệu quả hơn nhiều
Nhưng iterative scan không phải giải pháp căn cơ mà gần với biện pháp tạm thời hơn
Cần hiểu các tham số như ef_search, max_search_tuples, và planner không thực sự hiểu đầy đủ cost model của tìm kiếm vector có lọc
Cuối cùng đây là chuyện bạn có đủ khả năng tinh chỉnh query planner thông minh hay sẽ dùng một dịch vụ chuyên xử lý việc đó
Phương pháp được mô tả trong bài báo của Microsoft đã được Timescale triển khai trong pgvectorscale
Cách này có thể hiệu quả hơn lọc trước/sau đơn thuần
Chúng tôi ở VectorChord đã giải quyết hầu hết các vấn đề của pgvector được nhắc trong bài blog
Dùng IVF + quantization để hỗ trợ cập nhật nhanh hơn 15 lần so với HNSW của pgvector
Với 16 vCPU, 32GB bộ nhớ có thể index 100 triệu vector 768 chiều trong 20 phút
Có thể reindex mà không mất dữ liệu bằng
CREATE INDEX CONCURRENTLYCũng hỗ trợ lọc trước/sau và tìm kiếm lai dựa trên BM25
Xem thêm tại blog VectorChord
Có thể xem trường hợp liên quan trong blog này
Việc build index dùng nhiều bộ nhớ, nhưng có thể kiểm soát bằng
maintenance_work_memViệc rebuild index có thể xử lý bằng
REINDEX CONCURRENTLY, và cập nhật HNSW về mặt khái niệm tương tự như cập nhật B+treeBài này cho cảm giác như tác giả chưa đọc kỹ tài liệu Postgres
maintenance_work_memthì việc index sẽ chậm hơnB+tree chỉ đụng tới log H page, còn HNSW phải sửa hàng nghìn vector
Để rebuild nó, bạn phải chuẩn bị dung lượng DB hơn gấp đôi, và nó cũng ảnh hưởng đến các workload khác
REINDEX CONCURRENTLYcũng mất nhiều thời gianDù độ phức tạp chèn HNSW thấp, chi phí hằng số của nó lớn nên trên thực tế vẫn là gánh nặng
maintenance_work_mem, việc chiếm RAM cỡ GB trong nhiều giờ khi đang vận hành là rất rủi roREINDEX CONCURRENTLYcũng dùng thêm 2–3 lần dung lượng đĩa và ảnh hưởng hiệu năngCuối cùng vấn đề không phải là Postgres thiếu tính năng, mà là độ phức tạp vận hành rất cao
Vector DB chuyên dụng tự động xử lý những việc này, nên với các team nhỏ sẽ hiệu quả hơn nhiều
Việc Turbopuffer có giá khởi điểm từ 64 USD/tháng giải thích vì sao pgvector lại phổ biến
Nếu 64 USD nghe đắt thì dùng pgvector, còn nếu thấy rẻ thì có lẽ use case của bạn đã đủ phức tạp để vector DB chuyên dụng phù hợp hơn
Tôi đã thấy khá nhiều khách hàng GCP dùng pgvector HNSW trong production
Nhưng thực tế chỉ khả thi ở quy mô từ 0 đến 10 triệu vector
Cần tính đến ETL, overhead vận hành, các vấn đề nhất quán, v.v.
Nếu cần transaction, tìm kiếm lai và độ trễ thấp thì AlloyDB + ScaNN là lựa chọn tốt hơn
(Để tham khảo thì tôi từng tạo ra ScaNN ở GCP và hiện đang dẫn dắt AlloyDB Semantic Search)
Nguyên tắc mặc định của tôi là YAGNI
Giảm số lượng dịch vụ xuống mức thấp nhất có thể, và chỉ thêm cái mới khi thật sự gặp vấn đề
Nếu Postgres là đủ thì cứ dùng, còn nếu không thì lúc đó bạn sẽ biết chính xác mình cần gì
Những thứ như ghi vector thời gian thực, kết hợp bộ lọc SQL với tìm kiếm tương đồng nghe có vẻ nhỏ nhặt nhưng thực tế là tính năng thiết yếu
Khi quy mô tăng lên, những ràng buộc này sẽ bộc lộ thành vấn đề chí mạng
Khi dùng mô hình vector embedding, nó rất hữu ích ngay cả khi không có dataset quy mô lớn
Ví dụ như tìm kiếm tài liệu hay tìm kiếm thông tin sản phẩm
Tôi muốn một giao diện kiểu file system, nơi khi ghi tài liệu vào thì index được cập nhật tự động
Vì vậy những dịch vụ như Amazon S3 Vectors(liên kết) rất đáng chú ý
Tôi tò mò về trải nghiệm sử dụng thực tế
Có thể tham khảo tutorial liên quan trong bài này
Những vấn đề được nhắc tới thực ra đã được giải quyết, và tôi thích dùng PGVector hơn
Nếu Postgres có thể thay Kafka để xử lý 100.000 sự kiện mỗi giây, thì PGVector cũng hoàn toàn có thể thay các vector DB chuyên dụng như Chroma
Liên kết tham khảo
Hầu hết các use case của pgvector là dataset nhỏ kiểu “chatbot dựa trên tài liệu kỹ thuật”
Dữ liệu không thay đổi thường xuyên, không có multi-tenancy nên vấn đề lọc cũng ít hơn
Trong khi đó Chroma hỗ trợ SPANN, SPFresh, tìm kiếm lai, và là mã nguồn mở Apache 2.0 hoàn chỉnh
Với mô hình tính phí theo mức sử dụng, chi phí cũng có thể chỉ khoảng 1 USD/tháng
Redis Vector Sets mà tôi phát triển suốt 1 năm qua giải quyết các vấn đề này
Nó tự triển khai HNSW nên hỗ trợ cập nhật thời gian thực, và khi xóa thì bộ nhớ cũng được thu hồi ngay
Hỗ trợ tốc độ chèn hàng trăm nghìn ops/giây, tìm kiếm 50.000 ops/giây
Mặc định hỗ trợ quantization nên cũng rất hiệu quả về bộ nhớ
Mọi thứ được trình bày chi tiết trong tài liệu README
Hiện tại tính năng replication cũng đã được kiểm thử hoàn chỉnh