現在、Elasticsearchと格闘中です。実験的に扱っているので、まだ本稼働に使ったりとかそういうことでもないのですが、とりあえずRailsで使う際に得られた知見をメモ的に書いておこうと思います。主に自分用です。体系的に書けそうになったらまた書きます。
今回は、カタカナでの検索のメモです。
ちなみに使っているプログラミング言語はRubyで、アプリケーションはRailsで作っていますので、それが前提です。
gemは、elasticsearch-railsとelasticsearch-modelを入れています。
Elasticsearch、日本語くらいでググるとkuromojiを使ったサンプルがよく出てきます。形態素解析でいろんなキーワードに分割されるので、検索の際の速度は上がるのですが、読み仮名(カタカナ)のような情報は区切りが判別しづらいので、tokenizerとしてkuromoji_tokenizerでは対応できません。例えば、「イオンモールオカヤマ」という文字列を解析させると、「イオン」「モールオカヤマ」の2つに分割されてしまい、「オカヤマ」で検索してもヒットしませんでした。
こういう場合は、nGramを使うのが定石のようです。nGramは、キーワードの文字列の長さをほぼ固定して分割していく方式で、色んなパターンにヒットするようになる代わりに、インデックス情報が膨らむようです。しかし、カタカナだけの場合など区切りがわかりにくい場合は、これが適しているとのことです。
では、elasticsearch-modelを使ったサンプルコードを載せてみます。
class Shop < ActiveRecord::Base
include Elasticsearch::Model
index_name [Rails.application.engine_name, Rails.env].join('_')
settings index: {
analysis: {
tokenizer: {
kuromoji_user_dict: {
type: :kuromoji_tokenizer
},
ngram_tokenizer: {
type: 'nGram',
min_gram: '2',
max_gram: '3',
token_chars: ['letter', 'digit']
}
},
filter: {
# 指定した品詞を除外する
pos_filter: {
type: :kuromoji_part_of_speech,
stoptags: ['助詞-格助詞-一般', '助詞-終助詞']
},
greek_lowercase_filter: {
type: :lowercase,
language: :greek,
},
},
analyzer: {
kuromoji_analyzer: {
type: :custom,
tokenizer: :kuromoji_user_dict,
filter: [:kuromoji_baseform, :pos_filter, :greek_lowercase_filter, :cjk_width]
},
ngram_analyzer: {
tokenizer: :ngram_tokenizer,
filter: [:cjk_width]
}
}
}
} do
mapping do
indexes :name,
type: 'string',
index: :analyzed,
analyzer: :kuromoji_analyzer
indexes :yomigana,
type: 'string',
index: :analyzed,
analyzer: :ngram_analyzer
end
end
end
settingsのところで、tokenizerを2つ設定しています。そして、analyzerも2つ設定しています。
これらのanalyzerを、mappingのところでindexを作る際に利用しています。
kuromoji_analyzerは、普通の日本語の文字列に対して、
ngram_analyzerは、ヨミガナに対して使っています。
こうすることで、通常の日本語でも検索できるし、ヨミガナでも検索できるようになりました。
