Bài toán tìm kiếm dữ liệu sao cho thật nhanh và chính xác nhất luôn là vấn đề muôn thuở của các developer. Tùy mục đích, tùy bài toán và tài nguyên cho phép mà chúng ta có thể lựa chọn những công cụ và phương pháp khác nhau.
Ví dụ khi bạn thao tác với một tập dữ liệu nhỏ thì bạn có thể sử dụng toán tử LIKE trong sql, nhưng khi dữ liệu trở nên nhiều hơn thì LIKE không còn là phương pháp tối ưu nữa. Lúc đó bạn có thể chuyển sang sử dụng những module hỗ trợ fulltext search có trong cơ sở dữ liệu đang sử dụng. Tuy nhiên những module này cũng chỉ là giải pháp tạm thời vì chúng có thể không cung cấp được hết các tính năng mạnh mẽ khác so với công cụ fulltext khác đang có mặt trên thế giới.
Elasticsearch và Apache Solr là hai thư viện rất mạnh mẽ và được cộng đồng sử dụng rất phổ biến, tuy nhiên chúng lại yêu cầu một phần cứng khá "khiêm tốn" không dễ dàng để tiếp cận cho những bạn nào phát triển dự án với mức kinh phí cũng khiêm tốn.
Redisearch ra đời dựa trên redis, nó cung cấp một cỗ máy tìm kiếm rất mạnh mẽ cùng với mức "tiêu thụ" tài nguyên ít nhất mà bạn có thể dễ dàng tích hợp vào trong dự án của mình. Cho những bạn chưa biết thì redis là một cơ sở dữ liệu dạng key-value mà dữ liệu được lưu trữ trong bộ nhớ truy cập ngẫu nhiên (RAM) cho tốc độ truy xuất rất nhanh nên thường được sử dụng để làm bộ nhớ đệm (cache). Tuy là nhỏ bé nhưng nó cũng không kém phần mạnh mẽ so với hai đàn anh đi trước. Trong bài viết này chúng ta hãy xem redisearch có thể làm được những gì nhé.
Việc cần làm đầu tiên là cần phải tạo một index để có thể tìm kiếm. Index như là một cách để khai báo cho cỗ máy tìm kiếm biết dữ liệu của bạn nên được xử lý như thế nào cho tối ưu nhất.
Tạo index rất đơn giản trong redisearch, ví dụ tôi tạo một index phục vụ cho việc tìm kiếm bài viết gồm có ba trường dữ liệu là title, content và created_at tương ứng với tiêu đề, nội dung và ngày tạo bài viết.
FT.CREATE article ON HASH PREFIX 1 article: SCHEMA title TEXT WEIGHT 5.0 content TEXT created_at NUMERIC SORTABLE
Index của tôi có tên là article
, ở trường title
tôi đặt WEIGHT = 5
để kết quả tìm kiếm trường dữ liệu title
sẽ ưu tiên hơn so với content
, created_at
là SORTABLE để có thể sắp xếp thứ tự kết quả tìm kiếm. Nếu không khai báo SORTABLE thì bạn sẽ không thể sắp xếp được kết quả tìm kiếm.
Được rồi, sau khi tạo xong index thì chúng ta sẽ tìm hiểu cách tìm kiếm dữ liệu nhé.
Trước khi đến với cú pháp tìm kiếm, bạn cần biết một vài nguyên tắc tìm kiếm của redisearch:
hello world
thì đơn giản là bạn đang tìm kiếm những đoạn có chứa cả hai từ hello
và (AND) world
.hello world
thì bạn phải đặt nó trong dấu nháy kép (""). Ví dụ "hello world".hello
hoặc world
(OR) thì ngăn cách chúng bằng dấu |. Ví dụ hello|world
.-
. Ví dụ tìm kiếm có chứa hello
nhưng không chứa world
thì là hello -world
. Bạn cũng có thể kết hợp NOT nhiều từ bằng cách kết hợp với OR, ví dụ tìm kiếm trong trường title không chứa từ hello
hoặc world
: -@title:(hello|world).@filed:query
. Ví dụ @title:hello world
.[min max]
.{tag1 | tag2 | ...}
%text
.Còn một vài nguyên tắc nữa các bạn có thể xem thêm tại Search Query Syntax.
Và cuối cùng là một bảng cheatsheet thần thánh để so sánh một số lệnh tìm kiếm dữ liệu giữa SQL và redisearch:
Đầu tiên chúng ta hãy thêm một ít dữ liệu vào redis bằng cách sử dụng luôn index article
đã tạo ở trên. Để cho đơn giản và dễ nhìn tôi sẽ thêm một vài dữ liệu nhỏ nhẹ cho mọi người dễ quan sát.
HSET article:1 url "url-1" title "bài viết số một" content "nội dung của bài viết số một" created_at 1630245601
HSET article:2 url "url-2" title "bài viết số hai" content "nội dung của bài viết số hai" created_at 1630245602
HSET article:3 url "url-3" title "bài viết số ba" content "nội dung của bài viết số ba" created_at 1630245603
Tìm tất cả record có chứa từ bài viết
:
FT.SEARCH article "bài viết"
Tìm tất cả record mà content có chứa từ nội dung
:
FT.SEARCH article "@content:nội dung"
Tìm tất cả record mà title có chứa từ bài viết
và content không chứa từ số một
:
FT.SEARCH article "@title:bài viết -@content:số một"
Tìm tất cả record mà title có chứa từ số một
hoặc số hai
và content không chứa từ số ba
, sắp xếp theo thứ tự giảm dần của created_at:
FT.SEARCH article "@title:(số một | số hai) -@content:số ba" SORTBY created_at DESC
Stop words là một thuật ngữ chỉ cách mà redisearch sẽ bỏ qua một số từ quá phổ biến nhưng lại không mang lại giá trị trong tìm kiếm ví dụ như a, is, the... Những từ này nếu được đánh index sẽ chiếm nhiều không gian lưu trữ đồng thời làm ngốn lượng CPU trong lúc tìm kiếm dữ liệu.
Bởi vì redisearch được tạo ra cho tất cả người dùng thế nên họ chỉ tích hợp mặc định một số từ tiếng anh để loại bỏ Stop Words. Tuy vậy, bạn hoàn toàn có thể dịch nghĩa nó về tiếng Việt để thêm vào từ điển, hoặc bạn cũng có thể thêm những từ mà bạn không muốn sử dụng để tìm kiếm.
Stop Words được khai báo lúc tạo index. Ví dụ dưới đây tôi đang thêm 2 từ "thì", "là" vào Stop Words ở index article:
FT.CREATE article STOPWORDS 2 thì là ON HASH PREFIX 1 article: SCHEMA title TEXT WEIGHT 5.0 content TEXT created_at NUMERIC SORTABLE
Chú ý: Vì Stop Words phải được thêm ở lúc tạo index thế nên nếu các bạn đã có index từ trước thì bắt buộc phải xóa trước khi thêm lại. Sử dụng lệnh FT.DROPINDEX
để xóa index, mặc định khi xóa index thì dữ liệu của index sẽ không bị xóa. Sau đó thì chúng ta tiến hành tạo lại index như bình thường.
Nếu như không muốn dùng Stop Words nữa thì đặt STOPWORDS 0
ở lệnh tạo index.
Tokenization và Escaping được hiểu là trình mã hóa kí tự đầu vào và mã hóa kí tự trong lúc truy vấn dữ liệu. Dữ liệu khi được đưa vào redisearch phải qua một bước xử lý ví dụ như loại bỏ các khoảng trắng, các kí tự đặc biệt... Dưới đây là một số quy tắc Tokenization của redisearch:
hello-world...1
sẽ được mã hóa thành [hello world 1].hello-world
vào redisearch thì phải sửa lại đoạn text thành hello\-world
, khi đó lúc tìm kiếm thì cũng phải dùng hello\-world
để tìm kiếm.Đó là một số nguyên tắc của trường dữ liệu TEXT, đối với dữ liệu dạng TAG sẽ có một ít sự khác biệt mà tôi sẽ nói ở bài viết sau.
Highlighting API cho phép chúng ta thao tác với vùng dữ liệu được tìm thấy trong redisearch như chèn thêm kí tự để làm nổi bật kết quả...
Để bao bọc kết quả tìm kiếm, ví dụ như một thẻ mở/đóng xung quanh nó chúng ta sử dụng tùy chọn HIGHLIGHT
:
FT.SEARCH article "bài viết" HIGHLIGHT TAGS <b> </b>
Kết quả tìm kiếm nếu có tìm được ở tất cả các trường dữ liệu sẽ được chèn vào trong thẻ <b> </b>
. Nếu muốn chỉ định trường cụ thể sử dụng HIGHLIGHT chúng ta sử dụng thêm tùy chọn FIELDS:
FT.SEARCH article "bài viết" HIGHLIGHT FIELDS 1 title TAGS <b> </b>
Ngoài ra, redisearch còn hỗ trợ chúng ta hiển thị ngữ cảnh của nội dung mà chúng ta đang tìm kiếm nằm ở đâu. Ví dụ nguyên văn một câu "estacks là blog chia sẻ lập trình" thì khi tìm kiếm với từ "blog", redisearch sẽ hiển thị "...estacks là blog chia sẻ lập trình...".
FT.SEARCH article "bài viết" SUMMARIZE FIELDS 1 content
Bạn cũng có thể kết hợp cả HIGHLIGHT và SUMMARIZE trong một truy vấn.
Qua bài viết này tôi hy vọng mọi người nắm được công cụ redisearch được dùng để làm gì, nó có phù hợp hay cần thiết với các bạn trong các dự án sắp tới không và các câu lệnh cơ bản để bắt đầu. Hãy không ngừng học thêm những công cụ mới để có nhiều cách giải quyết vấn đề hơn nữa!
Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.
Bình luận (0)