##説明
searchkickとは検索エンジンの一つであるelasticsearchを簡単に扱えるようにしたGemです。これを使うことにより
- 高速検索
- 誤字訂正してくれる検索
- 部分合致検索
-自動補完
etc…
など様々な検索に関する機能を実装することが出来ます。
今回はこのsearchkickを使うために公式ドキュメントを和訳したのでそれを記しときます。
以下ドキュメントの和訳です
##Searchkickとは
searchkickとはユーザーが検索をするときの方法です。これを使うことによりより多くの人が簡単により良く検索結果を得ることが出来るようになります。
Searchkickを利用する機会
- 制御 -tomatoesをtomatoで合致するようにする
- 固有のもの ―jalapenoがjalapeñoと合致するようにする
- 余分な余白 - dishwasher が dish washer に合致するようにする
- 誤字 - zuchini が zucchini に合致するようにする
- 習慣的異名 - qtip が cotton swab に合致する
利点
- SQLの様にqueryを書けるので新しくqueryの文法を学習する必要がありません
- システムを休止することなくindexをつくることが出来ます
- 簡単に互いのUserを専用のものとして扱うことができます - 自動補完してくれます
- 意味の提案をしてくれます
- ActiveRecord や Mongoid と一緒に使うことができます
##使用方法
homebrewを使いelasticsearchをインストールします
$ brew install elasticsearch
Gemfileに以下を追記します
gem "searchkick"
検索を使いたいmodelにelasticsearchを追加します
class Product < ActiveRecord::Base
searchkick #追記
end
indexを追加する場合は以下のようにします
Product.reindex
queryは以下のように書きます
products = Product.search "2% Milk"
products.each do |product|
puts product.name
end
##Queryについて
queryはSQLの様に書きます
Product.search "2% Milk", where: {in_stock: true}, limit: 10, offset: 50
具体的なfieldを検索する
fields: [:name, :brand]
whereの使い方
where: {
expires_at: {gt: Time.now}, # lt, gte, lte also available
orders_count: 1..10, # equivalent to {gte: 1, lte: 10}
aisle_id: [25, 30], # in
store_id: {not: 2}, # not
aisle_id: {not: [25, 30]}, # not in
or: [
[{in_stock: true}, {backordered: true}]
]
}
Limit / offset の使い方
limit: 20, offset: 40
Boost by a field (フィールドによって押し上げる?)
boost: "orders_count" # give popular documents a little boost
##ページ付け
ページ付けを正しく適用させる
# controller
@products = Product.search "milk", page: params[:page], per_page: 20
# view
<%= paginate @products %>
##部分合致検索
defaultの設定では完全一致となっています
Product.search "fresh honey" # fresh AND honey
これを変えて使うには
Product.search "fresh honey", partial: true # fresh OR honey
##*Synonyms
(*一つの実体に複数の名前や値などが割り当てられる機能や状態を指すこと)
class Product < ActiveRecord::Base
searchkick synonyms: [["scallion", "green onion"], ["qtip", "cotton swab"]]
end
(注)必ずsynonymsを変更した後Product.reindexを呼んでください
##誤字
Searchkickではdefaultで誤字の修正を取り扱っています。この機能をOFFにしたい場合は以下のようにします
Product.search "zuchini", misspellings: false # no zucchini
また、edit distanceの範囲を選択することが出来ます
Product.search "zucini", misspellings: {distance: 2} # zucchini
##indexを作る
どのデータをindex化するかは search_data というメソッドを使って決めることができます。このメソッドを定義したあとに Product.reindex を呼んでください。
class Product < ActiveRecord::Base
def search_data
as_json only: [:name, :active]
# or equivalently
{
name: name,
active: active
}
end
end
Searchkickは find_in_batches を使って情報を付与することができます。associationを求める場合は search_import というスコープを使ってください。
class Product < ActiveRecord::Base
scope :search_import, includes(:searches)
end
##Reindexをする 又は Reindexしない
Reindexが必要なとき
- searchkickをインストールするとき、アップグレードするとき
- search_data メソッド変更したとき
- searchkick メソッドを変更したとき
Reindexが必要ないとき
- アプリを開始するとき
- データが追加されたり、変更されたり、削除された場合(自動的に同期されます)
##より良くデータを保ち、受け取る
Searchkickは具体的なデータからuserを探すことが出来ます。もしuserがBemとjerryの大きな猿がカートを引くアイスクリームを探そうとしたら、それは簡単に見つかるでしょう。
この手順では会話の軌跡と距離から定義されます。このデータベースは少ない容量ですが他のデータベースよりも自由に感じられるでしょう
class Search < ActiveRecord::Base
belongs_to :product
# fields: id, query, searched_at, converted_at, product_id
end
search queryを整理する必要はありません。searchkickは自動的にappleとAPPLESを同じものとして扱ってくれます
次はindexを改変しましょう。使用しているバージョンを 0.2.0 と明示しなくてはなりません((・ ・?)よくわかんない)
class Product < ActiveRecord::Base
has_many :searches
searchkick conversions: "conversions" # name of field
def search_data
{
name: name,
conversions: searches.group("query").count
# {"ice cream" => 234, "chocolate" => 67, "cream" => 2}
}
end
end
毎日最新のものに変更するためにReindexとcron jobをset upしなくてはなりません
rake searchkick:reindex CLASS=Product
##専用の結果
userの結果ごとに並び替えることができます。例えば他の結果を出す前にユーザーが以前購入した商品を表示することができます。
class Product < ActiveRecord::Base
searchkick personalize: "user_ids"
def search_data
{
name: name,
user_ids: orders.pluck(:user_id) # boost this product for these users
# [4, 8, 15, 16, 23, 42]
}
end
end
Reindexとsearchはこのようにします
Product.search "milk", user_id: 8
##自動補完
autocompleteはユーザーが何を打つのか予測して、より簡単で早い検索経験を作ります。
最初にどのfieldを主要にするか明示します。これはindexの数が増えるに連れて著しい意味を持ちます。しかしこれは酷く簡単なので心配はいりません。
class City < ActiveRecord::Base
searchkick autocomplete: ["name"]
end
Reindexとsearchはこのようにします
City.search "san fr", autocomplete: true
典型的な typeahead.jsや jQuery UIといったjqueryライブラリを使うことが出来ます。
##どのようにRailsで動かすのか
最初にcontrollerにアクションを追加します
# app/controllers/cities_controller.rb
class CitiesController < ApplicationController
def autocomplete
render json: City.search(params[:query], autocomplete: true, limit: 10).map(&:name)
end
end
このときにViewにsearch boxとjavascriptのコードを追記します
<input type="text" id="query" name="query" />
<script src="jquery.js"></script>
<script src="typeahead.js"></script>
<script>
$("#query").typeahead({
name: "city",
remote: "/cities/autocomplete?query=%QUERY"
});
</script>
##Facets(小枠)
Facetsは検索結果の集計を表示します
products = Product.search "chuck taylor", facets: [:product_type, :gender, :brand]
p products.facets
さらに高度な集計結果を表示したい場合は
Product.search "2% Milk", facets: {store_id: {where: {in_stock: true}, limit: 10}}
##強調
queryによる検索結果の強調をすることができます
bands = Band.search "cinema", fields: [:name], highlight: true
(注意)fieldsオプションが必須です
fieldsを用いて強調をみるには
bands.with_details.each do |band, details|
puts details[:highlight][:name] # "Two Door <em>Cinema</em> Club"
end
使うタグを変える場合は
Band.search "cinema", fields: [:name], highlight: {tag: "<strong>"}
##類似検索
似た要素を探すことができます
product = Product.first
product.similar(fields: ["name"])
##土地検索
(注意) 0.3.0以前のバージョンではlocationが不正確です。アップグレードしてReindexしてください
class City < ActiveRecord::Base
searchkick locations: ["location"]
def search_data
attributes.merge location: [latitude, longitude]
end
end
Reindexとsearchのやりかた
City.search "san", where: {location: {near: [37, -114], within: "100mi"}} # or 160km
Boxで仕分ける
City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}}
##Deployment
SearchkickはENV["ELASTICSEARCH_URL"]をサーバーとして使います。ただしコレが無い場合は
http://localhost:9200
がdefaultとして使用されます
###Heroku
SearchboxかBonsaiかFoundを使用してください
# SearchBox
heroku addons:add searchbox:starter
heroku config:add ELASTICSEARCH_URL=`heroku config:get SEARCHBOX_URL`
# Bonsai
heroku addons:add bonsai
heroku config:add ELASTICSEARCH_URL=`heroku config:get BONSAI_URL`
# Found
heroku addons:add foundelasticsearch
heroku config:add ELASTICSEARCH_URL=`heroku config:get FOUNDELASTICSEARCH_URL`
このときにdeployとReindexをしてください
heroku run rake searchkick:reindex CLASS=Product
##その他
作成時にはconfig/initializers/elasticsearch.rb
を初期化してください
ENV["ELASTICSEARCH_URL"] = "http://username:password@api.searchbox.io"
このときにdeployとreindexをして下さい
rake searchkick:reindex CLASS=Product
##継承
searchkickは一つのテーブルを受け続ことが出来ます
class Dog < Animal
end
このとき親と子の要素は両方Reindexしてください
Animal.reindex
Dog.reindex # equivalent
検索するためには
Animal.search "*" # all animals
Dog.search "*" # just dogs
##参照
Searchkickは0.90.0より高いelasticsearchを必要とします
ReindexはRecordの一つです
product = Product.find 10
product.reindex
古いindexの削除は
Product.clean_indices
異なったindex名を使うには
class Product < ActiveRecord::Base
searchkick index_name: "products_v2"
end
Prefixはindexの名前です
class Product < ActiveRecord::Base
searchkick index_prefix: "datakick"
end
callback機能をOFFにするには
class Product < ActiveRecord::Base
searchkick callbacks: false
end
associationの利用を望むなら
Product.search "milk", include: [:brand, :stores]
modelのロードをOFFにするには
Product.search "milk", load: false
特徴を消すには
class Product < ActiveRecord::Base
# A will not match Ä
searchkick special_characters: false
end
すべてのモデルをReindexする(Railsだけしか使えません)
rake searchkick:reindex:all
##Tireから移動するには
1,searchメソッドをtire.searchに変えて、既存のindexを呼べるようにします
Product.search "fruit"
置き換えるには
Product.tire.search "fruit", index: "products"
2.tire mapping wをsearchkickメソッドに置き換えます
class Product < ActiveRecord::Base
searchkick
end
deployとreindexをします
rake searchkick:reindex CLASS=Product # or Product.reindex in the console
4,これでsearch calls wはsearchkick callsに置き換わりました