Elasticsearch / Ruby / Rails / RSpec
セッティングをテストする
まずは正しくセッティングされていることをテストします.
最初にインデックスの再作成を行います.
spec/models/recipe_spec.rb
require 'rails_helper'
describe Recipe do
before :all do
Recipe . __elasticsearch__ . create_index! force: true
Recipe . __elasticsearch__ . refresh_index!
end
end
続いて取得したセッティングのトークナイザとアナライザの確認を行います.
spec/models/recipe_spec.rb
describe Recipe do
...
context "with settings" do
let ( :settings ) { Recipe . __elasticsearch__ . client . indices . get_settings [ Recipe . index_name ] }
let ( :analysis ) { settings [ "settings" ][ "index" ][ "analysis" ] }
context "with tokenizer" do
subject { analysis [ "tokenizer" ]}
it do
should eq ({ "ngram_tokenizer" =>
{ "max_gram" => "3" ,
"type" => "nGram" ,
"min_gram" => "2" ,
"token_chars" => [ "letter" , "digit" ]}})
end
end
context "with analyzer" do
subject { analysis [ "analyzer" ]}
it { should eq ({ "ngram_analyzer" => { "tokenizer" => "ngram_tokenizer" }}) }
end
end
end
ここではN-gramのトークナイザとアナライザが設定されていることを確認しています.
マッピングをテストする
続いてマッピング設定をテストします.
spec/models/recipe_spec.rb
describe Recipe do
...
context "with mappings" do
subject { Recipe . __elasticsearch__ . client . indices . get_mapping index: Recipe . index_name }
it do
should eq ({
"recipes" => {
"mappings" => {
"recipe" => {
"properties" => {
"id" => { "type" => "long" },
"title" => { "type" => "string" ,
"analyzer" => "ngram_analyzer" },
"description" => { "type" => "string" ,
"analyzer" => "ngram_analyzer" },
"url" => { "type" => "string" ,
"analyzer" => "ngram_analyzer" }
}
}
}
}
})
end
end
end
ちょっとネストが深いですが, title/description/urlフィールドにそれぞれN-gramアナライザが設定されていることを確認しています.
検索機能をテストする
最後に検索機能のテストをします.
まずは検索用のテストデータをインポートします.
spec/models/recipe_spec.rb
describe Recipe do
...
describe ".search" do
before :all do
Recipe . delete_all
Recipe . create ( title: "ミックス赤玉で豚玉を作ってみた" , description: "業務スーパーで買ったのは卵(ミックス赤玉)だけですが、豚玉炒めを作りました。" , url: "http://gsrecipe.com/2014/08/09/butatama/" )
Recipe . create ( title: "パルメザンチーズで濃厚カルボナーラ" , description: "業務スーパーのパルメザンチーズ(200g入り!)と卵でカルボナーラを作りました。" , url: "http://gsrecipe.com/2014/08/10/carbonara/" )
Recipe . create ( title: "ミックス赤玉で卵焼き" , description: "またまた卵ですが業務スーパーのミックス赤玉で卵焼きを作りました。" , url: "http://gsrecipe.com/2014/08/13/tamagoyaki/" )
Recipe . create ( title: "パプリカを使った野菜たっぷりスープ" , description: "業務スーパーの冷凍パプリカを使って野菜スープを作りました。我が家の恒例朝食メニューです。" , url: "http://gsrecipe.com/2014/08/14/vegesoup/" )
Recipe . __elasticsearch__ . import
Recipe . __elasticsearch__ . refresh_index!
end
end
end
ここではDBに作成したRecipeデータをElastisearchにインポートしています.
また, 最後のrefresh_index!
では強制的にインデックスを更新しています.
Elastisearchでのインデックス更新は非同期なので, 確実にインデックスを更新したい場合はこのようにrefresh_index!
メソッドを実行する必要があります.
続いて更新したインデックスから検索できるかテストします.
spec/models/recipe_spec.rb
describe Recipe do
...
describe ".search" do
...
context "when query is 'ミックス赤玉'" do
let ( :query ) { "ミックス赤玉" }
let ( :records ) { Recipe . search ( query ). records }
subject { records }
it { should have ( 2 ). items }
context "with titles" do
subject { records . map ( & :title ) }
it { should match_array [ "ミックス赤玉で豚玉を作ってみた" , "ミックス赤玉で卵焼き" ] }
end
end
end
end
実行してみると
$ bundle exec rspec spec/models/recipe_spec.rb -f d
Recipe
with settings
with tokenizer
should eq {"ngram_tokenizer"=>{"max_gram"=>"3", "type"=>"nGram", "min_gram"=>"2", "token_chars"=>["letter", "digit"]}}
with analyzer
should eq {"ngram_analyzer"=>{"tokenizer"=>"ngram_tokenizer"}}
with mappings
should eq {"recipes"=>{"mappings"=>{"recipe"=>{"properties"=>{"id"=>{"type"=>"long"}, "title"=>{"type"=>"string", "analyzer"=>"ngram_analyzer"}, "description"=>{"type"=>"string", "analyzer"=>"ngram_analyzer"}, "url"=>{"type"=>"string", "analyzer"=>"ngram_analyzer"}}}}}}
.search
when query is 'ミックス赤玉'
should have 2 items
with titles
should contain exactly "ミックス赤玉で豚玉を作ってみた" and "ミックス赤玉で卵焼き"
Finished in 2.12 seconds (files took 1.14 seconds to load)
5 examples, 0 failures
ということで無事Elasticsearchでの検索機能をテストできました.