読者です 読者をやめる 読者になる 読者になる

$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

ElasticsearchのAnalyzerを理解するため全文検索の仕組みをシンプルに考える

tech elasticsearch

 Elasticsearchを使おうとしているとAnalyzerという概念が出てくるが、このAnalyzerという概念は最初理解することが難しかった。全文検索の仕組みを理解すれば分かるだろうと思い、https://speakerdeck.com/johtani/elasticsearchru-men?slide=5http://www.atmarkit.co.jp/ait/articles/1111/18/news148.html の記事などを読んで勉強してみたものの、こちらもいろんな言葉が出てきて非常に混乱した。例えば転置インデックス、tf-idf、トークナイズ、ストップワードN-Gram、正規化などといった言葉が出てくる。

 いろいろ調べてみて整理すると、全文検索の技術には、なぜ検索ができるかの話以外に、類似度の話、検索を高速に行うための話、あいまいな検索に対応する話など、いろんな話題を含んでいるために理解が難しいのではと感じた。そこで、今回はなぜ検索ができるかをシンプルに自分の言葉でまとめることによって、理解を深め、Analyzerの概念も理解してみたい。

 ただし、僕自身は全文検索について専門ではないので、間違っていることがあれば指摘していただけると嬉しい。

なぜ検索できるかシンプルに考える

 自分で全文検索の仕組みをシンプルに言語化してみると、以下の3行にまとめられるのではと感じた。

  • まず文章を、前処理 -> トークン分割 -> トークンごとの後処理という3段階の処理にかけて、文章に含まれるトークン群を作る
  • 検索クエリを同じように、前処理 -> トークン分割 -> トークンごとの後処理という3段階の処理にかけて、検索クエリに含まれるトークン群を作る
  • あとは検索クエリに含まれるトークン群が、文章のトークン群に含まれているなら検索にヒットする


 これだけだとわかりづらいので例を使って考えてみる。例えば、「DVD版秒速5㌢メートルの感想ブログ」という文章があったとする。この時、全文検索をするなら、大文字小文字は関係なく検索にヒットさせたいし、半角全角も無視したい。また、助詞の「を」とかでヒットしても意味がなさそうなので省きたい。これらを満たすためには文章に対して次の処理を行いたいと思うだろう。

  • 前処理として、アルファベットは小文字化、全角文字は半角に、「㌢」などのワードも「センチ」に変換したい
  • 日本語検索ができるように、品詞単位でトークン分割したい
  • トークン分割した中から、助詞は意味なさそうなので省きたい

 文章のトークン群を作るイメージは以下のとおり。最終的に「dvd」「版」「秒速」「5」「センチメートル」「感想」「ブログ」というトークン群が得られた。

f:id:shiba_yu36:20160814121152j:plain


 次に検索クエリ側である。「秒速5センチメートル」という検索クエリも同じような処理にかけられる。これによって「秒速」「5」「センチメートル」というトークン群が得られる。この時、検索クエリの「秒速」「5」「センチメートル」は文章のトークン群の中に全て含まれる。そのため、検索にヒットする。

 別の例として、「感想 秒速5センチメートル」と検索したとする。この時ホワイトスペースの処理は別で行う必要はあるのだが、それを行うとすると「感想」「秒速」「5」「センチメートル」というトークン群が得られる。これも文章のトークン群に含まれるので、検索にヒットする。

 さらに「秒速5センチ」と検索したとする。この時「秒速」「5」「センチ」というトークン群が作られる。しかし、この時文章には「センチメートル」というトークンはあるものの、「センチ」というトークンは含まれないので検索にヒットしない。


 ここまで理解できれば、あとは前処理とトークン分割とトークンごとの後処理の組み合わせで自分の好きにトークン群を作れるということが分かる。それぞれの処理には例えば以下のようなものがある。

  • 前処理 : 辞書を使ったワード変換、HTMLタグの除去など
  • トークン分割 : 日本語の品詞での分割、N文字ごとの分割(N-gram)、ホワイトスペースでの分割など
  • トークンごとの後処理 : 必要ないトークンの除去、トークンをさらにN文字ごとに分割、漢字の読みがなをさらにトークンに追加など


 以上から、文章と検索クエリの両方共からトークン群を作り、検索クエリのトークン群が文章のトークン群に含まれていたら検索にヒットするということが分かった。もちろん応用として検索クエリのトークン群のうち一部が含まれていたらOKとか、トークンを変形させてあいまい検索にも対応するとかそのようなことも可能だろう。最後の例で「秒速5センチ」ではヒットしないと書いたが、トークン群の作り方によってはそれでもヒットさせるとかもできるだろう。

Anaylzerについて考える

 ここでElasticsearchのAnalyzerに戻って考えてみる。すると、以上で説明したものに完全に対応していることが分かる。

 Analysis and Analyzers | Elasticsearch: The Definitive Guide [2.x] | Elastic を見ると、Analyzerの中にはCharacter filters、Tokenizer、Token filtersというものがある。この説明を見ると、前処理 = Character filters、トークン分割 = Tokenizer、トークンごとの後処理 = Token filtersとなっている。図で表すと先ほどとほぼ変わらず以下のとおりである。

f:id:shiba_yu36:20160815101616j:plain

 これにより、ElasticsearchのAnalyzerは文章からトークン群を作る処理を定義するものであり、それは3つのプロセスに分かれ、プロセスごとにやることを組み合わせることでいろんなトークン群を作ることができる、と理解することが出来た。

まとめ

 今回は全文検索の仕組みについて、自分の言葉でシンプルに考えてみるということをしてみた。またまとめてみたことでAnalyzerをさらに理解することが出来た。

 僕は全文検索について専門ではないので、間違っている部分もあるかもしれない。もし間違っていたら指摘してもらえると助かります。