Elaticsearch gem Searchkick

Tram Ho

Searchkick là gem support search sử dụng Elasticsearch.
Searchkick support các tính năng sau:

  • stemming ví dụ tomatoes sẽ match với tomato
  • special characters ví dụ jalapeno sẽ match với jalapeño
  • extra whitespace ví dụ dishwasher sẽ match với dish washer
  • misspellings ví dụ zuchini sẽ match với zucchini
  • custom synonyms ví dụ pop sẽ match với soda

Bên cạnh đó còn có:

  • query like SQL
  • reindex without downtime
  • personalize result for each user
  • auto complete
  • “Did you mean” suggestions
  • supports manu languages
  • work with ActiveRecord, Mongoid và NoBrainer

1. Getting started:

  • Chúng ta sẽ tạo 1 project để bắt đầu tìm hiểu gem seachkick
  • Cài đặt các gem cần thiết
  • Tạo seed file
  • Thêm searchkick vào Product
  • Chạy reindex cho Product trên rails console để push data lên server Elasticsearch
  • Sau khi đã chạy xong reindex, bạn có thể dùng searchkick để search product
  • Hoặc để search tất cả product thì ta search với key word là “*”
  • Bạn có thể thấy trên log console, searchkick đã tạo 1 request dưới dạng curl sử dụng Elasticsearch DSL, chúng ta sẽ tìm hiểu kỹ thêm về Elasticsearch DSL ở bài sau
  • Trong source code tham khảo đã implement sẵn 2 service để bạn có thể thử 2 loại query cơ bản trên

2. Querying:

a. Where with specific value:

  • Searchkick nhận câu query như câu query của SQL để search.
  • Ví dụ:
  • Trong câu query, params where nhận giá trị là hash dạng key-value
  • Trong đó key là tên của attribute, value là mô tả giá trị của attribute đó
  • Searchkick sẽ thực hiện filter và chỉ search trên các product có các attribute thỏa giá trị của params where.
  • Trong ví dụ trên chỉ thực hiện trên các product có attribute in_stock là true.
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where

b. Where with range value:

  • Trong các trường hợp giá trị của attribute không phải là giá trị biết trước (như true hoặc false) mà nằm trong 1 khoảng giá trị nhất định (như từ 10 đến 20) ta sử dụng câu truy vấn với gtelte.
  • Ví dụ:
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where với gtelte

c. Where with in:

  • Trong trường hợp giá trị của attribute không nằm trong 1 khoảng liên tục (ví dụ: [1, 2, 3, 4, 5]) mà là 1 mảng rới rạc (ví dụ [1, 3, 5]) ta sử dụng câu truy vấn với in:
  • Ví dụ:
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where với in

d. Where with not:

  • Ngược lại với in ta có not, searchkick sẽ search trên các product có giá trị của attribute không nằm trong mảng giá trị cho trước:
  • Ví dụ:
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where với not

e. Where with all:

  • Tương tự với với in ta có all, searchkick sẽ search trên các product có giá trị của attribute bằng với mảng giá trị cho trước:
  • Ví dụ:
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where với not
  • Với câu truy vấn thứ nhất kết quả trả về luôn là mảng rỗng vì product.store_id không bap giờ trả về mảng

f: Where with all and array value:

  • Với lý do đã nêu ở trên, all thường được dùng với các attribute trả về mảng hơn là gia trị duy nhất.
  • Mình tạo thêm các model có quan hệ như sau
  • Khi đó ta có thể gọi product.order_ids và nhận được giá trị trả về là mảng
  • Ta thử search product theo order_ids sử dụng all như sau
  • Ví dụ:
  • Kết quả trả về luôn là mảng rỗng.

g: Where with all and search_data and search_import:

  • Nguyên nhân là vì khi thực hiện reindex, data searchkick gửi lên elasticsearch mặc định là các column của table Product.
  • Tức là searchkick chỉ gửi lên elasticsearch data về id, name, created_at, updated_at, in_stock, orders_countstore_id.
  • Do đó khi search với order_ids của product thì elasticsearch luôn trả về mảng rỗng.
  • Searchkick quy định data gửi lên elasticsearch bằng method search_data, sửa lại method này như sau và thêm scope search_import như sau
  • Thực hiện reindex cho Product
  • Chạy lại câu query với all và ta thu được kết quả
  • Chúng ta sẽ tìm hiểu về search_datasearch_import kĩ hơn ở phần sau.
  • Chú ý câu query all chỉ search trên các product có order_ids là mảng con hoặc chính là mảng tham số truyền vào.
  • Trong source code tham khảo đã implement sẵn service để bạn có thể thử query where với not

h: Where with exists:

  • Ta cũng có thể thực hiện filter trên các product có store_id với query exists: true.
  • Tuy nhiên để filter trên các product có store_id là nil thì không sử dụng query exists: true được mà phải gọi trực tiếp store_id: nil như sau
  • Trong source code tham khảo đã implement sẵn service để bạn có thể query với 2 trường hợp trên

i: Where with and:

  • Operator mặc định của where là and, record trả về phải thỏa tất cả query của where, ví dụ
  • Ta có thể viết lại với query _and như sau

j: Where with or:

  • Trong trường hợp filter các product thỏa 1 trong 2 mệnh đề thì ta sử dụng query _or như sau

k: Where with not:

  • Trong trường loại của query _not, ta chỉ có thể truyền 1 attribute thay vì nhiều attribute
  • Ví dụ _not với store_id
  • Ví dụ _not với orders_count
  • Trong trường hợp truyền nhiều attribute thì searchkick sẽ filter với attribute sau cùng
  • Ví dụ:
  • Sẽ tương đương với

3. Fields:

  • Theo mặc định, elasticsearch sẽ search trên tất cả các attribute của product, ta có thể chỉ định elasticsearch chỉ search trên 1 vài attribute thông qua option fields
  • Ví dụ:
  • Trong source code tham khảo có implement service để bạn search với fields options

4. Limit and offset:

  • Searchkick cung cấp thêm 2 option là offsetlimit có tác dụng tương tự offsetlimit trong SQL.
  • Ví dụ:
  • Searchlick sẽ bỏ qua 20 product đầu tiên trong các product tìm được và chỉ trả về 10 product.
  • Trong source code tham khảo có implement service để bạn search với limitoffset.

5. Results:

  • Method search của searchkick trả về Searchkick::Results object.
  • Ta có thể coi object này như array và gọi các method của array như sau
  • Searchkick::Result còn có thêm 2 method là tookresponse
  • Searchkick::Result còn có thêm 1 method là total_count trả về toàn bộ product search được khi chưa pagination, khác với method count, length hay size
  • Ví dụ

6. Source code

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo