Sử dụng Gem Chewy để đánh index và query data trong Ruby on Rails

Như chúng ta đã biết Elasticsearch là một search engine được xây dựng để hoạt động như một server cloud theo cơ chế của RESTful. Elasticsearch phát triển bằng ngôn ngữ Java từ Lucene Apache. ELASTIC-SEARCH có thể tích hợp được với tất cả các ứng dụng sử dụng các loại ngôn ngữ sau:

  • Java
  • JavaScript
  • Groovy
  • .NET
  • PHP
  • Perl
  • Python
  • Ruby

Chewy là một Gem khá mạnh hỗ trợ việc đánh index và query data với những điểm mạnh sau:

  1. Multi-model indexes: Cho phép index ở nhiều model có liên hệ với nhau

  2. Every index is observable by all the related models: Tự động reindex khi change trong model và các model có liên hệ

  3. Bulk import everywhere: Hỗ trợ việc đánh index với dữ liệu lớn. Có thể đánh index ở bất cứ đâu, công việc cần làm là nhóm những phần tử thay đổi vào cùng một block và đánh index cho chúng cùng một lúc.

  4. Powerful querying DSL: Hỗ trợ tối đa các query chainable, mergable and lazy

CÀI ĐẶT

Thêm dòng sau vào trong Gemfile:

gem 'chewy'

Chạy lệnh sau để cài đặt:

bundle install

Hoặc chạy lệnh sau trong không gian project.

gem install chewy

SETTINGS

Chạy lệnh sau để tạo các file settings cho Chewy:

rails g chewy:install

Setting khi không sử dụng môi trường:

# config/initializers/chewy.rb
Chewy.settings = {host: 'localhost:9250'}

Setting khi sử dụng môi trường:

# config/chewy.yml
# separate environment configs
test:
  host: 'localhost:9250'
  prefix: 'test'
development:
  host: 'localhost:9200'

CÁCH ĐÁNH INDEX CHO MODEL

Để hoàn thành việc đánh index cho model về cơ bản sẽ có những bước sau:

  1. Tạo file chứa các khai báo index tương ứng với model nằm trong namespace chewy /app/chewy/users_index.rb
class UsersIndex < Chewy::Index

end
  1. Thêm một hoặc nhiều kiểu mapping
class UsersIndex < Chewy::Index
  define_type User
end
  1. Khai báo các kiểu đánh index tương ứng cho từng field.
class UsersIndex < Chewy::Index
  settings analysis: {
    analyzer: {
      email: {
        tokenizer: 'keyword',
        filter: ['lowercase']
      }
    }
  define_type User.active.includes(:country, :badges, :projects) do
    field :first_name, :last_name
    field :email, analyzer: 'email'
    field :projects do
      field :title
      field :description
    end
    field :rating, type: 'integer'
end
  1. Tự động đánh index cho những bản ghi thay đổi trong model
class User < ActiveRecord::Base
  update_index('users#user') { self } 
end

Ngoài ra có thể thay đổi cài đặt mặc định khi đánh index bằng options sau

  define_type User do
    default_import_options batch_size: 100, bulk_size: 10.megabytes, refresh: false

    field :name
  end

Đánh index với khai báo nested

  define_type User do
    field :projects do
      field :title
      field :description
    end
  end

CÁC LỆNH CƠ BẢN CỦA INDEX MODEL

Lấy ra các type của index model

UsersIndex::User # => UsersIndex::User
UsersIndex.type_hash['user'] # => UsersIndex::User
UsersIndex.type('user') # => UsersIndex::User
UsersIndex.type('foo') # => raises error UndefinedType("Unknown type in UsersIndex: foo")
UsersIndex.types # => [UsersIndex::User]
UsersIndex.type_names # => ['user']

Các toán tử có thể dùng cho model index

    UsersIndex.delete # Xóa index nếu nó tồn tại
    UsersIndex.delete!

    UsersIndex.create
    UsersIndex.create! # Tạo index

    UsersIndex.purge
    UsersIndex.purge! # Xóa index sau khi tạo

    UsersIndex::User.import # Thêm index với 0 điều kiện sẽ mặc định cho tất cả data hiện có
    UsersIndex::User.import User.where('rating > 100') # Impot index với điều kiện

    UsersIndex.import # Import với tất cả các type
    UsersIndex.import user: User.where('rating > 100') # Import với điều kiện
    UsersIndex.reset! # Reset lại index

Đánh index với điều kiện

define_type User, delete_if: :deleted_at
define_type User, delete_if: -> { deleted_at }
define_type User, delete_if: ->(user) { user.deleted_at }

INDEX QUERY VÀ FILTERS QUERY

Chewy cung cấp những câu query khá tiện ích và mềm dẻo. Ví dụ:

scope = UsersIndex.query(term: {name: 'foo'})
  .filter(range: {rating: {gte: 100}})
  .order(created: :desc)
  .limit(20).offset(100)

scope.to_a # => Đổi kết quả về dạng mảng
scope.map { |user| user.email }
scope.total_count # => Trả về tổng số lượng records

scope.per(10).page(3) # Kết hợp với kaminari để phân trang
scope.explain.map { |user| user._explanation }
scope.only(:id, :email) # Trả về object với hai attributes id và email

scope.merge(other_scope) # Thêm điều kiện với một scope khác. 

Một số câu lệnh xóa

UsersIndex.delete_all
UsersIndex::User.delete_all
UsersIndex.filter{ age < 42 }.delete_all
UsersIndex::User.filter{ age < 42 }.delete_all

Một số cách filters đơn giản

UsersIndex.filter{ name == 'Fred' } 
UsersIndex.filter{ age <= 42 }
UsersIndex.filter{ s('doc["num"] > 1') } 
UsersIndex.filter{ q(query_string: {query: 'lazy fox'}) } 
UsersIndex.filter{ ~name == 'Name' } 
UsersIndex.filter{ ~(name == 'Name') } 

UsersIndex.filter{ ~(age > 42) & (age <= 50) }

UsersIndex.filter{ name(cache: true) == 'Name' }
UsersIndex.filter{ name(cache: false) == 'Name' }

UsersIndex.filter{ name(cache: 'name_regexp') =~ /Name/ }

UsersIndex.filter{ name(cache: true) =~ /Name/ }

KẾT LUẬN

Trên đây mình chỉ giới thiệu những cài đặt cơ bản và dễ sử dụng của Chewy nhưng sức mạnh của Chewy không chỉ dừng lại ở đó. Để tìm hiểu sâu hơn về nó các bạn có thể tìm hiểu ở Đây Thanks you for reading !!!