Bạn cần tìm bài ghi chú, tài liệu vận hành hoặc nội dung trợ giúp trong sản phẩm. Trước khi thêm một search service độc lập, hãy kiểm tra khả năng của database đang dùng. SQLite FTS5 và PostgreSQL full-text search đều có thể là điểm bắt đầu, nhưng phù hợp với hai cách vận hành khác nhau.
Đây là đánh giá dựa trên tài liệu, không phải trải nghiệm triển khai hay benchmark của AeDev. Ví dụ PostgreSQL tham chiếu bản 17; khả năng FTS5 phụ thuộc thư viện SQLite được đóng gói trong môi trường của bạn. Nguồn được đối chiếu ngày 22/10/2026.
So bằng yêu cầu sản phẩm
Một ứng dụng ghi chú chạy cục bộ quan tâm việc tìm kiếm khi mất mạng và cách cập nhật dữ liệu trên thiết bị. Một cổng tài liệu nhiều người dùng lại cần kiểm soát quyền, đồng thời hóa ghi và phục hồi cùng dữ liệu server. Cả hai có thể hiển thị một ô tìm kiếm giống nhau, nhưng chi phí vận hành phía sau khác nhau.
| Tiêu chí | SQLite FTS5 | PostgreSQL full-text search |
|---|---|---|
| Nơi chạy | Nhúng cùng ứng dụng và file SQLite | Trong hệ thống PostgreSQL đang vận hành |
| Tổ chức tìm kiếm | Virtual table FTS5 | tsvector, tsquery và cấu hình text search |
| Bảo trì dữ liệu | Cần bảo đảm bảng tìm kiếm khớp nguồn | Cần bảo đảm biểu thức/tập vector khớp dữ liệu |
| Phân quyền | Ứng dụng quản lý phạm vi dữ liệu | Kết hợp điều kiện phân quyền trong truy vấn server |
| Điểm cần kiểm tra | Bản build có FTS5, tokenizer, đồng bộ | Cấu hình ngôn ngữ, truy vấn, chỉ mục, vận hành DB |
Không có hàng nào trong bảng là một phép đo tốc độ. Dữ liệu, cách chia từ, cách xếp hạng và workload thực tế mới quyết định trải nghiệm của người dùng.
Bắt đầu bằng một tập dữ liệu nhỏ
FTS5 dùng virtual table. Một ví dụ độc lập để thử trong SQLite có hỗ trợ extension này:
CREATE VIRTUAL TABLE notes_search USING fts5(title, body);
INSERT INTO notes_search(title, body) VALUES
('Khôi phục đăng nhập', 'Kiểm tra phiên đăng nhập và thiết bị'),
('Sao lưu dữ liệu', 'Khôi phục dữ liệu từ bản sao lưu');
SELECT rowid, title, bm25(notes_search) AS score
FROM notes_search
WHERE notes_search MATCH 'đăng nhập'
ORDER BY score;
Với bm25() của FTS5, giá trị nhỏ hơn được dùng cho kết quả phù hợp hơn. Không lấy con số này để so trực tiếp với điểm xếp hạng của một engine khác. Nếu muốn biểu diễn phần trăm phù hợp trên UI, bạn cần tự định nghĩa và kiểm chứng ý nghĩa của cách chuyển đổi đó.
PostgreSQL có thể chuyển văn bản thành tsvector và chuỗi tìm thành tsquery. Ví dụ tập dữ liệu tạm dùng cấu hình simple:
WITH notes(id, title, body) AS (
VALUES
(1, 'Khôi phục đăng nhập', 'Kiểm tra phiên đăng nhập'),
(2, 'Sao lưu dữ liệu', 'Khôi phục dữ liệu từ bản sao lưu')
), documents AS (
SELECT id, title,
to_tsvector('simple', title || ' ' || body) AS document
FROM notes
)
SELECT id, title
FROM documents
WHERE document @@ plainto_tsquery('simple', 'đăng nhập');
Hai ví dụ thể hiện cách viết truy vấn, không tạo ra phép so sánh hiệu năng. Khi đưa vào ứng dụng, dùng parameter của driver thay vì ghép trực tiếp chuỗi người dùng vào SQL. Cú pháp tìm kiếm và giới hạn đầu vào cũng cần được thống nhất với giao diện.
Tiếng Việt cần bộ ca kiểm tra riêng
Đừng hiểu hỗ trợ Unicode thành hiểu ngôn ngữ tiếng Việt. Thử cặp có dấu/không dấu, chữ “đ”, tên sản phẩm có dấu gạch nối và cụm như “đăng nhập”. Xác định sản phẩm muốn khớp từng từ, toàn bộ cụm hay một phần chuỗi, rồi mới đánh giá cấu hình tokenizer.
Cấu hình simple trong ví dụ PostgreSQL không phải một bộ phân tích ngôn ngữ tiếng Việt hoàn chỉnh. Tương tự, tokenizer mặc định của FTS5 có quy tắc Unicode riêng, không tự đáp ứng mọi yêu cầu bỏ dấu hoặc đồng nghĩa. Nếu chuẩn hóa văn bản trước khi lập chỉ mục, truy vấn cũng phải đi qua quy tắc tương ứng và vẫn giữ bản gốc để hiển thị.
Tạo một danh sách câu hỏi tìm kiếm từ công việc thật: người dùng thường nhớ tên chức năng, mã lỗi hay một đoạn tiêu đề? Với mỗi truy vấn, ghi vài kết quả mong đợi. Bộ dữ liệu nhỏ nhưng có chủ đích hữu ích hơn việc đo một từ khóa duy nhất rồi kết luận engine nào tốt hơn.
Đừng bỏ quên đồng bộ và quyền đọc
Nếu lưu nội dung nguồn ở bảng khác, cần có cơ chế cập nhật chỉ mục khi tài liệu đổi hoặc bị xóa. Một kết quả tìm kiếm trỏ tới dữ liệu đã xóa là lỗi sản phẩm dù truy vấn chạy nhanh. Trước khi thêm trigger hay bảng vector lưu sẵn, hãy xác định nơi nào chịu trách nhiệm duy trì dữ liệu đó.
Với tìm kiếm server, lọc tenant và quyền đọc trong cùng quy trình truy vấn. Đừng chỉ lọc danh sách cuối sau khi đã gửi snippet của tài liệu riêng tư cho client. Cũng cần quyết định backup chỉ mục hay dựng lại từ nguồn; quyết định này phụ thuộc cách lưu và khả năng phục hồi của ứng dụng.
Chọn thế nào cho bước đầu?
Nếu dữ liệu chủ yếu ở thiết bị, FTS5 giúp bạn thử khả năng tìm kiếm trong cùng môi trường SQLite. Hãy kiểm tra bản build, giới hạn tài nguyên và đường cập nhật dữ liệu trước. Nếu nguồn dữ liệu đã ở PostgreSQL trên server, thử full-text search tại đó thường giúp đánh giá nhu cầu mà chưa phải thêm một hệ thống đồng bộ riêng.
Khi có yêu cầu phức tạp về ngôn ngữ, gợi ý, phân tích nhiều trường hoặc workload vượt khả năng đã đo, lúc đó mới có cơ sở đánh giá một search service khác. Đó là quyết định tiếp theo dựa trên kết quả kiểm chứng, không phải kết luận rằng một trong hai lựa chọn luôn đủ dùng.


