Hướng dẫn full-text search mongodb

Nội dung bài viết

Video học lập trình mỗi ngày

Đầu tiên chúng ta thống nhất với nhau là hiểu khái niệm Full text search là gì? này trước rồi mới tới việc thực hành. Full text search đơn giản chỉ là một hình thức nâng cao việc tìm kiếm dữ liệu trong database mà thôi.

Một người bình thường họ có thể mất nhiều steps để tìm ra một chuỗi cần thiết thì dẫn đến việc lâu và chậm, dẫn đến chản nản..., nếu người đó biết được khái niệm và thực hành về Fulltext search thì việc đó trở nên đơn giản hơn bao giờ hết. Và bài viết này tôi sẽ hướng dẫn về điều đó với Mongodb.

Full text search Mongodb

Đương nhiên để hiểu về Full text search in mongodb thì trước tiên điều kiện tiên quyết là bạn đã cài đặt và sử dụng mongodb rồi. Nếu bạn chưa biết thì có thể theo những hướng dẫn trong blogs này đã viết or có thể vào trang chủ của mongodb

  • Cách cài đặt và tạo user quản lý database với mongodb
  • Cách kết nối mongodb với nodejs tốt nhất

Ok, xem như xong chúng ta sẽ đi tới thực hành. Đầu tiên giả sử bạn đã xong xuôi mọi chuyện và bạn sẽ insert data vào trong DB:

> use test
switched to db test
> db.players.insertMany([
... {"name": "cr7", "description": "ghi ban bang hai chan va bang dau"},
... {"name": "m10", "description": "ghi ban chan trai va chan phai"},
... {"name": "Haaland", "description": "ghi ban chan trai"},
... {"name": "M3p", "description": "ghi ban chan phai"},
... {"name": "greenwood", "description": "ghi ban bang dau"}
... ])

Trên đó là tôi insert một số cầu thủ đang hot với 2 khai báo: {name: '', description: ''}. Tôi nói nhanh thôi, nên không đi sâu vào chi tiết.

> db.players.find()
{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6251"), "name" : "m10", "description" : "ghi ban chan trai va chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6252"), "name" : "Haaland", "description" : "ghi ban chan trai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6253"), "name" : "M3p", "description" : "ghi ban chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau" }
>

OK tìm kiếm xong, như vậy là insert thành công. Tiếp đến sử dụng Full text search bằng cách sử dụng $text. Trước tiên khai báo index, nếu không bạn sẽ bị text index required for $text query như thế này:

> db.players.find({ $text:{ $search: 'ghi ban'} })
Error: error: {
"ok" : 0,
"errmsg" : "text index required for $text query",
"code" : 27,
"codeName" : "IndexNotFound"
}
>

Chúng ta khai báo index như sau để sử dụng Full text search trong Mongodb. Code như sau:

> db.players.createIndex({ "name": "text", "description": "text" });
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}

OK, xem như xong về index mongodb. Chúng ta chạy lại câu lệnh trên thì sẽ tìm thấy những documents có chứa giá trị tìm kiếm là ghi bàn.

> db.players.find({ $text:{ $search: 'ghi ban'} })

{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6253"), "name" : "M3p", "description" : "ghi ban chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6252"), "name" : "Haaland", "description" : "ghi ban chan trai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6251"), "name" : "m10", "description" : "ghi ban chan trai va chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau" }

Giờ tìm kiếm chan va bang dau thì chũng ta cũng nhận được hết 4 documents.

> db.players.find({ $text:{ $search: 'chan va bang dau'} })

{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6251"), "name" : "m10", "description" : "ghi ban chan trai va chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6253"), "name" : "M3p", "description" : "ghi ban chan phai" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6252"), "name" : "Haaland", "description" : "ghi ban chan trai" }
>

Vì khi chúng ta tìm nó tìm kiếm toàn văn bản cho nên nhận lệnh khớp các từ có trong cụm từ tìm kiếm trên. chan, va, bang, dau.

Giờ chúng ta muôn chỉ tìm kiếm đúng chính xác là chan va bang dau thôi thì chúng ta chỉ thấy cr7 là có thể. Làm như sau:

> db.players.find({ $text:{ $search: '\"chan va bang dau\"'} })
{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau" }
>

Chú ý dấu / là nó phân biệt chúng ta tìm không phải là JSON cho nên nó tìm kiếm cụm từ một cách chính xác.

Tiếp theo chúng ta chỉ tìm những cầu thủ chi ghi bàn bằng đầu thôi. Tìm kiếm như sau

> db.players.find({ $text:{ $search: 'bang dau'} })
{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau" }
{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau" }
>

Chúng ta nhận thấy mục đích chúng ta bị sai bởi vì muốn tìm cầu thủ chỉ ghi bằng đầu thôi mà có một document ghi bằng chân nữa. Chúng ta sẽ thay lại như sau:

> db.players.find({ $text:{ $search: 'bang dau -chan'} })
{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau" }
>

-chan chính là giá trị tìm kiếm mà chúng ta không muốn tìm kiếm. Rất hay khải không?

Ngoài ra có một tiện ích đó là khi chúng ta tìm kiếm thì chỉ muốn giá trị đúng nhất, như elasticsearch làm được. Lúc đó bạn sẽ sử dụng $meta.

> db.players.find({ $text:{ $search: 'chan phai dau'}}, {score: {$meta: 'textScore'}})
{ "_id" : ObjectId("61e8def4cfc05da9225c6251"), "name" : "m10", "description" : "ghi ban chan trai va chan phai", "score" : 1.5357142857142856 }
{ "_id" : ObjectId("61e8def4cfc05da9225c6254"), "name" : "greenwood", "description" : "ghi ban bang dau", "score" : 0.625 }
{ "_id" : ObjectId("61e8def4cfc05da9225c6252"), "name" : "Haaland", "description" : "ghi ban chan trai", "score" : 0.625 }
{ "_id" : ObjectId("61e8def4cfc05da9225c6253"), "name" : "M3p", "description" : "ghi ban chan phai", "score" : 1.25 }
{ "_id" : ObjectId("61e8def4cfc05da9225c6250"), "name" : "cr7", "description" : "ghi ban bang hai chan va bang dau", "score" : 1.125 }
>

{score: {$meta: 'textScore'}} sẽ có nhiệm vụ sắp xếp những cụm từ chính xác theo điểm số score. Các bạn có thể nhìn lại như trên, tôi đã làm. Để ý thì thấy thứ tự nhảy lung tung cho nên chúng ta cần sắp xếp lại. Thì dùng sort() thôi.

MongoDB full text search vietnamese

Có một câu hỏi có nhiều bạn cũng thắc mắc về sử dụng Text search trong MongoDB về tìm kiếm có dấu ở VN. Thì cơ bản nó cung giống chung nhau cả thôi. Chủ yếu là khi các bạn insert data như thế nào? Các bạn phải chuyển về mẫu số chung như "Giàu", "giaU" thì cũng bằng giau mà thôi.

OK hết nhé! Nhớ đọc link ref trong bài mà tôi đã giới thiệu.