Full text search with Searchkick
Getting Started
ติดตั้ง Elasticsearch หรือ OpenSearch สำหรับคนที่ใช้ macOS สามารถติดตั้งโดยใช้ brew ได้เลย:
1
2
3
4
5
brew install elastic/tap/elasticsearch-full
brew services start elasticsearch-full
# or
brew install opensearch
brew services start opensearch
จากนั้นเพิ่มบรรทัดเหล่านี้เข้าไปใน Gemfile:
1
2
3
4
gem "searchkick"
gem "elasticsearch" # select one
gem "opensearch-ruby" # select one
และเพิ่ม searchkick เข้าไปใน model ที่ต้องการจะค้นหา:
1
2
3
class Product < ActiveRecord::Base
searchkick
end
เข้าไปอ่าน Searchkick เพิ่มเติม ดูวิธีการใช้งานและ feature ที่มีให้ใช้
Demo
ต่อไปเราจะไปลองทำ demo ง่าย ๆ กัน:
1
rails new store
จากนั้นก็สร้างโมเดล product ซึ่งขอลัด ๆ ใช้ scaffold ไปก่อน:
1
2
3
rails g scaffold Product name detail:text
rails db:migrate
rails s
สร้างตัวอย่างข้อมูลใน:
1
Product.create(name: '', detail: '')
จากนั้นก็รันคำสั่งเพื่อเพิ่มข้อมูลเข้าไป:
1
rails db:seed
เปิด http://localhost:3000/products:
หลังจากนี้จะ implement search ให้กับ Product ก่อนอื่นก็เพิ่ม routes search:
1
2
3
4
5
6
7
Rails.application.routes.draw do
resources :products do
collection do
get 'search'
end
end
end
เพิ่ม form การ search:
1
2
3
4
<%= form_tag search_products_path, method: :get do %>
<%= text_field_tag :q %>
<%= submit_tag :search %>
<% end %>
จะได้ form มาแบบนี้:
แล้วก็ไป implement search method:
1
2
3
4
5
6
7
8
class ProductsController < ApplicationController
...
def search
@products = Product.search(params[:q])
render :index
end
...
end
ตอนนี้ทำง่าย ๆ ไปก่อน แล้วไปลองดูผลงานกัน:
มาถึงขั้นนี้แล้วก็เหมือนว่าทุกอย่างจะใช้ได้ดี ที่นี้ลองใส่ข้อมูลที่เป็นภาษาไทยลงไป:
แล้วก็ลองค้นหาดู ก็จะเห็นว่าได้ผลออกมา:
เกือบดีละ ที่นี้ลองค้นหาแค่บางส่วนของคำ:
หาไม่เจอ 😓 มันเป็นปัญหาอย่างเดียวกับที่เคยเจอตอนใช้ Thinking Sphinx เป็นเรื่องการตัดคำภาษาไทยอีกแล้ว
อัพเดท 2020: จากนั้นแก้ไข searchkick ใน model โดยการเพิ่ม mapping สำหรับภาษาไทยเข้าไป ซึ่งจะต้องกำหนดว่าจะให้ค้นหาใน column ไหนได้บ้าง อย่างในตัวอย่างคือให้ค้นหาที่ name และ detail ต่างจากเมื่อก่อนที่กำหนดแต่ teken เป็น thai ก็พอ:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Product < ApplicationRecord
searchkick merge_mappings: true,
settings: {
analysis: {
analyzer: {
thai_analyzer: {
tokenizer: 'thai'
}
}
}
},
mappings: {
properties: {
name: {
type: 'keyword',
fields: {
analyzed: {
type: 'text',
analyzer: 'thai_analyzer'
}
}
},
detail: {
type: 'keyword',
fields: {
analyzed: {
type: 'text',
analyzer: 'thai_analyzer'
}
}
}
}
}
end
จากนั้น reindex อีกครั้ง:
1
rails searchkick:reindex CLASS=Product
ลองค้นหาผลลัพท์ดู:
เป็นอันเรียบร้อย ทำให้ค้นการแบบตัดคำภาษาไทยได้แล้ว 😉
Conclusion
Elasticsearch เป็น search engine ที่ดี และ Searchkick ก็ทำให้มันใช้ง่าย ๆ กับ rails model และตอนนี้ก็หาวิธีการให้ค้นหาภาษาไทยได้อย่างมีประสิทธิภาพได้แล้ว เพราะงั้นงานต่อไปได้ใช้อย่างแน่นอน
อัพเดท 2020: Elasticsearch ไม่สามารถค้นหาภาษาไทยที่เป็นทับศัพท์ได้ น่าจะเพราะการตัดคำนั่นแหละ หากจะเลือกใช้ก็อย่าลืมดูเรื่องนี้ด้วย