現在、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は、ヨミガナに対して使っています。
こうすることで、通常の日本語でも検索できるし、ヨミガナでも検索できるようになりました。