Cách thêm tìm kiếm vào ứng dụng: Từ bộ lọc đơn giản đến tìm kiếm toàn văn
Để thêm tìm kiếm vào ứng dụng, hãy bắt đầu với thứ đơn giản nhất mà vẫn hoạt động: một ô tìm kiếm gọi một route trên server, lọc các dòng trong cơ sở dữ liệu bằng cách so khớp truy vấn với vài cột, cùng các bộ lọc cho những thứ như danh mục hoặc giá. Khi cách đó chưa đủ tốt — bạn cần xếp hạng độ liên quan, cắt gốc từ hoặc có rất nhiều bản ghi — hãy chuyển sang tìm kiếm toàn văn của cơ sở dữ liệu, và chỉ chuyển sang công cụ tìm kiếm được lưu trữ khi bạn cần khả năng chịu lỗi chính tả mạnh hoặc kết quả tức thì trên dữ liệu rất lớn. Dù chọn cách nào, tìm kiếm cũng phải tôn trọng quyền hạn: người dùng không bao giờ được tìm thấy những bản ghi mà họ không có quyền xem.
"Tìm kiếm" nghĩa là gì với ứng dụng của bạn
Tìm kiếm bao gồm nhiều thứ khác nhau, và đa số ứng dụng cần nhiều hơn một:
- Tìm theo từ khóa: một ô văn bản — "tìm tin đăng có nhắc đến 'vườn'".
- Bộ lọc: các lựa chọn có cấu trúc — danh mục, thành phố, khoảng giá, ngày, trạng thái.
- Sắp xếp: mới nhất, rẻ nhất, liên quan nhất.
- Tự động hoàn thành: gợi ý khi đang gõ.
- Chịu lỗi chính tả: "restuarant" vẫn tìm ra "restaurant".
Với một thư mục, bảng việc làm hay cửa hàng, bộ lọc thường quan trọng hơn ô văn bản. Hãy quyết định bạn thực sự cần những thứ nào trước khi chọn công cụ.
Các lựa chọn của bạn
| Cách làm | Hoạt động thế nào | Phù hợp với | Giới hạn |
|---|---|---|---|
| Lọc trong trình duyệt | Tải danh sách, lọc bằng JavaScript | Danh sách công khai nhỏ (vài trăm mục) | Gửi toàn bộ dữ liệu đến mọi khách truy cập; chậm với danh sách lớn |
| So khớp mẫu trong cơ sở dữ liệu | Truy vấn phía server kiểu "tên chứa đoạn văn bản", không phân biệt hoa thường | Ứng dụng nhỏ đến vừa, công cụ quản trị | Không xếp hạng; có thể chậm trên bảng lớn; không cắt gốc từ |
| Tìm kiếm toàn văn trong cơ sở dữ liệu | Postgres lập chỉ mục các từ và xếp hạng kết quả khớp | Đa số ứng dụng có nhiều nội dung | Yếu với lỗi chính tả trừ khi thêm khớp mờ |
| Khớp mờ (trigram) | Postgres so sánh các chuỗi ký tự để tìm độ tương đồng | Tên, các trường ngắn, khả năng chịu lỗi chính tả | Cần một extension và chỉ mục; phải tinh chỉnh |
| Công cụ tìm kiếm được lưu trữ | Một dịch vụ riêng lập chỉ mục dữ liệu của bạn (Algolia, Meilisearch, Typesense, Elasticsearch và các công cụ khác) | Danh mục lớn, tìm kiếm tức thì, chịu lỗi chính tả mạnh | Thêm một dịch vụ phải đồng bộ, trả phí và bảo mật |
Nếu dữ liệu của bạn đã nằm trong Postgres, tìm kiếm toàn văn tích hợp sẵn của nó là một lựa chọn trung gian mạnh. Nó tách văn bản thành các từ, rút gọn chúng về dạng gốc (để "running" khớp với "run"), bỏ qua các từ phổ biến, và có thể xếp hạng kết quả theo mức độ khớp. Với chỉ mục phù hợp, nó vẫn nhanh trên bảng lớn.
Prompt ví dụ
Khởi đầu đơn giản:
Thêm ô tìm kiếm và bộ lọc vào trang danh sách. Tìm kiếm phải khớp truy vấn với tiêu đề và mô tả, không phân biệt hoa thường. Bộ lọc: danh mục (menu thả xuống), thành phố (menu thả xuống) và giá tối đa. Thực hiện tìm kiếm trên server bằng một route API có phân trang, 20 kết quả mỗi trang. Giữ tìm kiếm và bộ lọc trên URL để kết quả có thể chia sẻ và nút quay lại hoạt động. Hiển thị trạng thái trống thân thiện khi không có gì khớp.
Nâng cấp lên tìm kiếm toàn văn:
Chuyển tìm kiếm tin đăng sang tìm kiếm toàn văn của Postgres trên tiêu đề (có trọng số cao hơn) và mô tả. Thêm chỉ mục phù hợp, xếp hạng kết quả theo độ liên quan, và giữ nguyên bộ lọc và phân trang hiện có. Không thay đổi dữ liệu hiện có.
Thêm khả năng chịu lỗi chính tả cho tên:
Thêm khớp mờ trên tên doanh nghiệp để các lỗi chính tả nhỏ vẫn tìm được kết quả. Dùng độ tương đồng trigram nếu có, kèm chỉ mục, và quay lại tìm kiếm hiện tại nếu không có.
Từng bước
- Liệt kê những gì người ta tìm kiếm. Những trường nào (tiêu đề, mô tả, thẻ, tên)? Những bộ lọc nào? Nếu có thể, hãy hỏi vài người dùng thật.
- Bắt đầu từ phía server. Thêm một route API nhận truy vấn và bộ lọc, và trả về một trang kết quả. Đừng tải mọi thứ vào trình duyệt.
- Áp dụng quyền hạn trong truy vấn. Nếu người dùng chỉ thấy bản ghi của chính họ, hoặc chỉ thấy bản đã xuất bản, điều kiện đó phải nằm trong cùng truy vấn tìm kiếm.
- Thêm phân trang ngay từ đầu — số trang hoặc "tải thêm".
- Đưa trạng thái tìm kiếm lên URL (ví dụ
?q=garden&city=leeds). Liên kết có thể chia sẻ, nút quay lại hoạt động, và công cụ tìm kiếm có thể thu thập các trang đã lọc nếu bạn muốn. - Trì hoãn tìm kiếm khi gõ. Đợi vài trăm mili giây sau khi ngừng gõ rồi mới truy vấn, để không gửi một yêu cầu cho mỗi phím bấm.
- Thêm chỉ mục khi bạn biết những cột nào được lọc và tìm kiếm.
- Nâng cấp lên tìm kiếm toàn văn, rồi khớp mờ, rồi công cụ được lưu trữ — chỉ khi cách đơn giản hơn không đáp ứng được người dùng thật.
- Kiểm thử với dữ liệu trông giống thật: hàng trăm hoặc hàng nghìn dòng, ký tự lạ, truy vấn trống, truy vấn rất dài, các ngôn ngữ khác nếu bạn hỗ trợ.
Những lỗi thường gặp
- Tải toàn bộ bảng vào trình duyệt. Ổn với 50 mục, đau đớn với 50.000, và nó để lộ mọi bản ghi — kể cả những bản người dùng không được xem.
- Tìm kiếm bỏ qua quyền hạn. Tìm kiếm là một điểm rò rỉ phổ biến: một bản ghi riêng tư hoặc bản nháp hiện ra vì truy vấn quên điều kiện "chỉ của tôi" hoặc "chỉ bản đã xuất bản".
- Xây SQL từ đầu vào thô của người dùng. Luôn dùng truy vấn có tham số. Công cụ xây bằng AI thường làm vậy, nhưng hãy kiểm tra nếu bạn thấy chuỗi bị ghép nối.
- Không có trạng thái trống. "Không có kết quả" kèm gợi ý (xóa bộ lọc, kiểm tra chính tả) giúp người ta không rời đi.
- Không có chỉ mục. Tìm kiếm chạy ổn với dữ liệu thử nghiệm và chậm dần khi dữ liệu thật tăng lên.
- Nhảy ngay sang dịch vụ tìm kiếm. Khi đó bạn phải giữ một bản sao thứ hai của dữ liệu được đồng bộ, xử lý việc xóa, và bảo mật thêm một bộ khóa khác — thường là không có lợi ích nhìn thấy được.
- Quên điện thoại. Bộ lọc phải vừa trên điện thoại; một ngăn lọc trượt lên hoặc bảng thu gọn thường tốt hơn thanh bên.
Danh sách kiểm tra
- Bạn biết những trường nào được tìm kiếm và có những bộ lọc nào
- Tìm kiếm chạy trên server và trả về kết quả có phân trang
- Truy vấn áp dụng cùng quyền hạn với phần còn lại của ứng dụng
- Đầu vào của người dùng được truyền như tham số, không bao giờ ghép vào SQL
- Trạng thái tìm kiếm nằm trên URL
- Việc gõ được trì hoãn (debounce)
- Các cột được tìm kiếm và lọc đã được lập chỉ mục
- Trạng thái trống, không có kết quả và lỗi đều rõ ràng
- Đã kiểm thử với khối lượng dữ liệu thực tế và đầu vào lộn xộn
Thêm tìm kiếm với Mythex
Trong ứng dụng xây trên Mythex, dữ liệu thường nằm trong cơ sở dữ liệu Postgres riêng của dự án, nên bạn có thể bắt đầu với các prompt ở trên: so khớp mẫu trước, rồi tìm kiếm toàn văn của Postgres khi cần xếp hạng. Nếu bạn muốn một công cụ tìm kiếm được lưu trữ, hãy dùng tài khoản và khóa của riêng bạn, lưu nó làm secret của dự án, và yêu cầu agent lập chỉ mục và truy vấn nó từ server, như mô tả trong Tích hợp bất kỳ API nào.
Tìm kiếm là lõi của nhiều ứng dụng: xem cách xây website thư mục, cách xây bảng việc làm và cách xây marketplace để biết tìm kiếm phù hợp với phần còn lại của sản phẩm như thế nào.
Câu hỏi thường gặp
Cách dễ nhất để thêm tìm kiếm vào ứng dụng là gì?
Nếu dữ liệu nằm trong cơ sở dữ liệu, một route trên server lọc các dòng bằng cách so khớp không phân biệt hoa thường trên vài cột là cách bắt đầu dễ nhất. Với một danh sách nhỏ đã được tải sẵn trong trình duyệt, lọc ngay trong trình duyệt còn đơn giản hơn.
Tôi có cần Algolia hoặc Elasticsearch để tìm kiếm không?
Thường thì chưa cần ngay từ đầu. Tìm kiếm toàn văn của Postgres xử lý tốt việc khớp từ, xếp hạng và hàng nghìn đến hàng triệu dòng. Công cụ tìm kiếm được lưu trữ đáng dùng khi bạn cần khả năng chịu lỗi chính tả mạnh, kết quả tức thì khi gõ trên dữ liệu lớn, hoặc tinh chỉnh độ liên quan nâng cao.
Tại sao tìm kiếm của tôi không tìm ra kết quả khi có lỗi chính tả?
Khớp cơ bản và tìm kiếm toàn văn tiêu chuẩn tìm các từ đúng như đã gõ (hoặc dạng gốc của chúng), nên lỗi chính tả sẽ bị bỏ sót. Bạn cần khớp mờ, chẳng hạn độ tương đồng trigram trong Postgres hoặc một công cụ tìm kiếm có khả năng chịu lỗi chính tả.
Tìm kiếm nên chạy trong trình duyệt hay trên server?
Trên server cho bất kỳ thứ gì vượt quá một danh sách công khai nhỏ. Tìm kiếm phía server có khả năng mở rộng, tôn trọng quyền hạn và không gửi toàn bộ dữ liệu của bạn đến mỗi khách truy cập.