12/08/2018, 15:49

Full-text search đơn giản trong Ruby on Rails với gem search_cop

Như các bạn đã biết về full-text search thì đây là một cách để tăng tốc độ thực hiện câu query, với những ai chưa rõ full-text search là gì thì có thể tham khảo thêm ở đây: Giới thiệu về full-text search. Trong bài viết này mình sẽ hướng dẫn các bạn một cách dùng gem để hỗ trợ sử dụng full-text ...

Như các bạn đã biết về full-text search thì đây là một cách để tăng tốc độ thực hiện câu query, với những ai chưa rõ full-text search là gì thì có thể tham khảo thêm ở đây: Giới thiệu về full-text search. Trong bài viết này mình sẽ hướng dẫn các bạn một cách dùng gem để hỗ trợ sử dụng full-text seach thay vì viết query trực tiếp trong model. Tuy nhiên khi sử dụng thì các bạn cần lưu ý là phải đánh index trước. 1. Installation : Thêm dòng sau vào trong gem file: gem "search_cop" và chạy lệnh bundle install trong terminal.
2. Usage Để sử dụng được gem này, trước tiên các bạn cần kích hoạt bằng cách include SearchCop trong model và xác định các thuộc tính mà bạn dự định sẽ tìm kiếm dựa vào nó.

class Book < ActiveRecord::Base
include SearchCop

search_scope :search do
attributes :title, :description, :stock, :price, :created_at, :available
attributes comment: ["comments.title", "comments.message"]
attributes author: "author.name"
# ...
end

has_many :comments
belongs_to :author
end

Ngoài ra bạn cũng có thể viết nhiều search_scope:

search_scope :admin_search do
  attributes :title, :description, :stock, :price, :created_at, :available

  # ...
end

search_scope :user_search do
  attributes :title, :description

  # ...
end

Sau đó ta gọi đến SearchCop trong controller như sau:

Book.search("stock > 0")
# ... WHERE books.stock > 0

Book.search("price > 10 stock > 0")
# ... WHERE books.price > 10 AND books.stock > 0

Book.search("Harry Potter")
# ... WHERE (books.title LIKE '%Harry%' OR books.description LIKE '%Harry%' OR ...) AND (books.title LIKE '%Potter%' OR books.description LIKE '%Potter%' ...)

Book.search("available:yes OR created_at:2014")
# ... WHERE books.available = 1 OR (books.created_at >= '2014-01-01 00:00:00' and books.created_at <= '2014-12-31 00:00:00')

Trong trường hợp bạn muốn search từ thuộc tính của các model khác, chúng ta sẽ thực hiện như sau:

class Book < ActiveRecord::Base
 # ...

 belongs_to :author

 search_scope :search do
   attributes author: "author.name"
 end

 # ...
end

Mặc định SearchCop sẽ sử dụng eager_load. Trong trường hợp bạn không muốn sử dụng eager_load một cách tự động, bạn có thể xác định một scope:

class Book < ActiveRecord::Base
 # ...

 search_scope :search do
   # ...
   scope { joins(:author).eager_load(:comments) } # etc.
 end

 # ...
end

SearchCop sẽ bỏ qua việc tự động load các quan hệ và sử dụng scope đã được định nghĩa. Bạn cũng có thể sử dụng scope cùng với aliases để thực hiện các câu lệnh joins và search phức tạp với các bảng/models được join:

class Book < ActiveRecord::Base
 # ...

 search_scope :search do
   attributes similar: ["similar_books.title", "similar_books.description"]

   scope do
     joins "left outer join books similar_books on ..."
   end

   aliases similar_books: Book # Tell SearchCop how to map SQL aliases to models
 end

 # ...
end

Với quan hệ nhiều nhiều ta có thể thực hiện như sau:

class Book < ActiveRecord::Base
 # ...

 has_many :comments
 has_many :users, :through => :comments

 search_scope :search do
   attributes user: "users.username"
 end

 # ...
end

3. Một số lưu ý: - Bạn cần phải đánh index trước khi sử dụng fulltext-search - Nếu đã có index, bạn cần thêm dòng options :attributes_name, :type => :fulltext vào trong search_scope Ngoài ra các bạn có thể vào link dưới đây để đọc thêm. Link tham khảo: https://github.com/mrkamel/search_cop

0