Làm thế nào sử dụng Elasticsearch trong rails với gem Searchkick
Tại sao lại sử dụng gem searckick khi dùng elasticsearch? Vì gem searchkick giúp cho việc tìm kiếm trở nên đơn giản hơn, cho kết quả tốt hơn, thân thiện với nhà phát triển Truy vấn giống như SQL- mà bạn không cần phải học 1 ngôn ngữ truy vấn mới Reindex không có thời gian chết Dễ dàng sử ...
Tại sao lại sử dụng gem searckick khi dùng elasticsearch? Vì gem searchkick giúp cho việc tìm kiếm trở nên đơn giản hơn, cho kết quả tốt hơn, thân thiện với nhà phát triển
- Truy vấn giống như SQL- mà bạn không cần phải học 1 ngôn ngữ truy vấn mới
- Reindex không có thời gian chết
- Dễ dàng sử dụng
- Autocomplete
- Làm việc với ActiveRecord, Mongoid, and NoBrainer
Cách cài đặt
Chúng ta thêm gem "searchkick" vào Gemfile
source "https://rubygems.org" ruby "2.2.3" ... gem "searchkick" ...
Thêm searchkick vào model bạn muốn thực hiện việc tìm kiếm
class User < ActiveRecord::Base searchkick end
Sau đó thêm data vào search index bằng cách vào rails c gõ:
User.reindex
Sử dụng kết quả trả về
Tìm kiếm trả về một đối tượng Searchkick::Results. Trả về có dạng 1 array có thể sử dụng các method như
results = User.search("hanoi") results.size results.any? results.each { |result| ... }
Mặc định, các id được tìm kiếm từ elasticsearch sẽ được tìm kiếm trong csdl. Ví dụ khi chọn User.search("hanoi") kết quả sẽ trả về các id của user.
{"_index"=>"users_development_20161221085009191", "_type"=>"user", "_id"=>"4", "_score"=>0.1486337}, {"_index"=>"users_development_20161221085009191", "_type"=>"user", "_id"=>"1", "_score"=>0.076713204}]}}>
Để lấy tất cả thông tin User về ta có thể sử dụng câu lệnh:
User.search("hanoi", load: false)
Dữ liệu trả về bản ghi có dạng
"_index"=>"users_development_20161221085009191", "_type"=>"user", "_id"=>"1", "_score"=>0.076713204, "_source"=>{"id"=>1, "email"=>"hehe@gmail.com", "name"=>"ngoc vu", "city"=>"hanoi", "created_at"=>"2016-12-19T03:06:47.000Z", "updated_at"=>"2016-12-19T03:06:47.000Z"}}]}}>
Để lấy tổng số kết quả trả về:
results.total_count
Để tìm kiếm tất cả: Sử dụng *
User.search "*"
Tùy chỉnh tìm kiếm
- Exact Matches: Tìm kiếm chính xác những gì đã nhập. Ví dụ muốn tìm city có tên là hanoi
User.search "hanoi", fields: [{city: :exact}]
- Partial Matches: Theo mặc định kết quả trả về phải phù hợp với tất cả các từ
User.search "lan hien" # lan AND hien
Ta có thể thay đổi cách tìm kiếm bằng cách:
User.search "lan hien", operator: "or" # lan OR hien
Ngoài ra có các option khác như
:word # default :word_start :word_middle :word_end :text_start :text_middle :text_end
Demo
- Ở View: Ta xây dựng giao diện tìm kiếm user đơn giản như
<%= form_tag users_path, method: :get, class: "navbar-form navbar-right", role: "search" do %> <p> <%= text_field_tag :search, params[:search], class: "form-control", placeholder: "Search...", id: "search", autocomplete: "off" %> <%= submit_tag "Search", name: nil, class: "btn btn-default" %> </p> <% end %> <div class="row"> <% @users.each do |user| %> <div class="col-sm-6 col-md-3"> <div class="thumbnail"> <%= user.email %> </div> </div> <% end %> </div>
- Ở Controller:
class UsersController < ApplicationController def index if params[:search].present? @ users = User.search(params[:search]) else @ users = User.all end end end
- Ở Model:
class User < ActiveRecord::Base searchkick text_start: [:email] end
Như vậy ta có thể tìm kiếm đơn giản:
Giờ chúng ta nâng cấp tìm kiếm sao cho thân thiện với người sử dụng:
- Autocomplete: Tự động gợi ý những gì người dùng sẽ gõ giúp cho việc tìm kiếm trở lên nhanh chóng và dễ dàng hơn
Đầu tiên xác định trường mà chúng ta định sử dụng tính năng này. giúp cho việc truy vấn trở lên nhanh chóng hơn: Ở đây mình dùng tìm kiếm trên email
class User < ActiveRecord::Base searchkick word_start: [:email] end
Reindex và tìm kiếm
User.search "lalal@gmail.com", match: :word_start
Để bắt đầu ta thêm autocomplete vào model
class User < ActiveRecord::Base searchkick word_start: [:email], autocomplete: ['name'] end
Thêm router:
Rails.application.routes.draw do resources :users do collection do get :autocomplete end end end
Thêm hàm autocomplete vào controller
class UsersController < ApplicationController ... def autocomplete render json: User.search(params[:term], { fields: ["email"], limit: 10 }).map(&:email) end end
Ở view ta thêm
<%= stylesheet_link_tag "//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css" %> <%= javascript_include_tag "//code.jquery.com/ui/1.11.2/jquery-ui.js" %> .. <script> $("#search").autocomplete({ source: "/users/autocomplete.json", minLength: 2 }); </script>
Vậy là ta đã hoàn thành autocomplete
Tham khảo
https://github.com/ankane/searchkick http://aimeeault.com/2016/02/05/how-to-use-searchkick-and-elasticsearch-in-your-rails-app-for-complex-search-indexing/
http://www.rubydoc.info/gems/searchkick/0.4.1/frames
https://github.com/ankane/searchkick