Full-text search sử dụng gem search_cop
Bài đăng này đã không được cập nhật trong 6 năm
Giới thiệu
Về cơ bản thìfull-text search
là một cách để tăng tốc độ tìm kiếm và chất lượng kết quả. Bạn có thể tìm hiểu thêm qua loạt bài viết sau: https://kipalog.com/posts/Full-Text-Search--Tu-Khai-Niem-den-Thuc-Tien--Phan-1.
Trong bài viết này mình sẽ tập trung vào công dụng của full-text search
bằng cách xây dựng một demo dựa trên framework Ruby On Rails
và gem search_cop
.
Về gem search_cop
, nó là một thư viện hỗ trợ việc sử dụng full-text search
cho ứng dụng Rails mà không cần quan tâm đến database sử dụng là gì (MySQL, PostgreSQL) hay bạn sẽ không cần phải sử dụng search server của bên thứ 3 (Elasticsearch, Solr). Khi sử dụng, ta chỉ việc viết những câu query string hoặc query dạng hash đơn giản và gem sẽ tự động sinh và tối ưu query tương ứng với database.
Xây dựng demo
Để bắt đầu, chúng ta thêm vào Gemfile các dòng sau
gem 'search_cop'
gem "faker" //để tạo dữ liệu mẫu
Tiếp theo chúng ta tạo một model Article chính là đối tượng search bằng câu lệnh
rails generate model Article title:string content:string author:string
Câu lệnh trên sẽ sinh ra một file migration, thêm dòng sau
add_index :articles, [:title, :content, :author], type: :fulltext // đánh index tương ứng cho các trường
Tiếp theo là thực hiện fake dữ liệu
// tạo 10000 bản ghi có dữ liệu ngẫu nhiên
require 'faker'
100000.times.each do
Article.create!(
title: Faker::Lorem.sentence,
content: Faker::Lorem.paragraph,
author: Faker::Lorem.word
)
end
Cuối cùng chạy các lệnh sau để tạo cơ sở dữ liệu
rails db:migrate
rails db:seed
Thêm scope search cho model
class Article < ApplicationRecord
include SearchCop //để sử dụng các phương thức trong gem
// khai báo scope search
search_scope :search do
attributes all: [:title, :content, :author] //khai báo tập các field muốn search
options :all, type: :fulltext, default: true //định nghĩa chúng ta muốn sử dụng full-text search
end
end
Tạo một search controller
class SearchController < ApplicationController
before_action :get_q, only: [:search_by_full_text, :search_by_like]
def index;end
def search_by_full_text
@articles = Article.search(q) // gọi tới scope search ta định nghĩa ở trên
@found = @articles.count // số bản ghi tìm được
@all = Article.count // tổng số bản ghi
render :search_result
end
def search_by_like
@articles = Article.where("title LIKE ? OR content LIKE ? OR author LIKE ?",
"%"+q+"%", "%"+q+"%", "%"+q+"%") // tìm kiếm bằng LIKE
@found = @articles.count
@all = Article.count
render :search_result
end
private
attr_reader :articles, :q
def get_q
@q = params[:q]
end
end
Định nghĩa các routes
Rails.application.routes.draw do
get "/search", to: 'search#index'
post "/search_by_full_text", to: 'search#search_by_full_text'
post "/search_by_like", to: "search#search_by_like"
root 'search#index'
end
Tạo các view tương ứng
index.html.erb
<div class="form-group col-md-offset-4" style="margin-top: 120px; margin-bottom: 120px;">
<%= form_tag "/search_by_full_text", class: "form-inline" do %>
<%= text_field_tag :q, nil, placeholder: 'Search Full-text', class: "form-control input-lg" %>
<%= submit_tag :search, class: "btn btn-lg btn-primary" %>
<% end %>
</div>
<div class="form-group col-md-offset-4">
<%= form_tag "/search_by_like", class: "form-inline" do %>
<%= text_field_tag :q, nil, placeholder: 'Search LIKE', class: "form-control input-lg" %>
<%= submit_tag :search, class: "btn btn-lg btn-primary" %>
<% end %>
</div>
searchresult.html.erb
<div class="container">
<h2><%= @found %> / <%= @all %></h2>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>CONTENT</th>
<th>AUTHOR</th>
</tr>
</thead>
<tbody>
<% @articles.each do |article| %>
<tr>
<td><%= article.id %></td>
<td><%= article.title %></td>
<td><%= article.content %></td>
<td><%= article.author %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
Chạy server và ta có kết quả như sau:
Thử submit từng form và so sánh kết quả. Với từ khóa là 'quis'
Kết quả sử dụng full-text search
Kết quả sử dụng LIKE search
Đầu tiên, ta thấy được số kết quả sử dụng full-text search ít hơn (25103 so với 35545 trong 117665 bản ghi), đó là do cơ chế tính điểm cho kết quả từ đó lọc ra được các kết quả phù hợp nhất. Cũng chính vì vậy mà thứ tự kết quả cũng đã được sắp xếp theo độ liên quan khác với kết quả của search LIKE cho kết quả theo thứ tự.
Tiếp đó là về hiệu năng
Câu truy vấn Article Load đầu tiên chính là query full-text search được sinh ra trong MySQL với thời gian thực hiện chỉ bằng một nửa so với query bằng LIKE.
Khi truy vấn với từ khóa mà số kết quả thỏa mãn ít (chỉ có 4 bản ghi) thì sự chêch lệch còn lớn hơn!!!
Qua bài viết, mình đã nêu ra ưu điểm vượt trội của full-text search trong trường hợp số lượng bản ghi lớn và chứa nhiều text, cùng với đó là cách sử dụng cơ bản của gem search_cop trong ứng dụng Rails. Để tìm hiểu sâu hơn bạn có thể tham khảo các tài liệu sau:
https://github.com/mrkamel/search_cop
https://kipalog.com/posts/Full-Text-Search--Tu-Khai-Niem-den-Thuc-Tien--Phan-1
Cảm ơn các bạn đã theo dõi
All rights reserved