
MongoDB × Elasticsearch × Monstache での部分一致検索
-
2021年2月5日
こんにちは。tech blog 編集長の N です。
今回はポケコロツインの1月中旬頃のアップデートで、「ココロノート」に新たに導入された部分一致検索についてご紹介いたします。
ポケコロツインとは
ポケコロツインは「世界一かわいいをつくれるデザイナー」がプロデュースしたふたご着せ替えアプリです。
『ポケコロツイン』は二人のアバター「ココロン」を着せかえたり、二人の動きに癒やされたり・・・。CCPサービスの一つとして、これまで以上にアバターの可愛らしい動きや、表情、世界の表現にこだわりました。
ココロノートとその問題点
ココロノートとは、自分が思ったことを自由に投稿できる、ポケコロツイン内での交流の場(いわゆる掲示板)です。
投稿の公開範囲を 自分のみ・フレンドまで・全体 から選ぶことができます。
従来のココロノートの検索機能では、前方一致検索しか実装されていませんでした。
例えば、ペットを飼っている人の話題を探したいと考えて「ペット」でタイトル検索を行った場合、タイトル文頭に「ペット」と入っているものだけがヒットする状態でした。そこで、タイトルのどの部分に検索ワードが入っていてもヒットするように、部分一致検索の導入を行いました。
部分一致検索の導入
ココロノートのデータは MongoDB に保存しています。
MongoDB でも全文一致検索は提供されていますが、日本語の索引検索機能がありません。そのため、全てのココロノートのデータをフルスキャンしなければなりません。
しかし、ココロノートのデータはすでに 2020 年 12 月時点で 50 万件を超えており、パフォーマンスに影響が出てしまい、フルスキャンでの検索は現実的ではありませんでした。
そのため、高速な索引検索が行える Elasticsearch を採用しました。
Elasticsearch
Elasticsearch とは、分散型の全文検索・分析エンジンです。
索引型検索方式を採用しているのが特徴で、データは json 形式で保存します。
Elasticsearch のメリットとして以下が挙げられます。
- 日本語に対応している
- オープンソース部分は無料
- 処理を分散させることができる
索引型検索方式とは
索引型検索方式とは、文章を単語単位に分割し、その単語から文章を探し出す検索方式のことです。
例として、以下の2文があったとします。
ID | 文章 |
---|---|
1 | 先週、吉祥寺で財布を落としました。 |
2 | 警察署まで財布を取りに行きました。 |
これらの文章を Elasticsearch に保存すると、本文はそのまま保存されます。
一方、それとは別に転置インデックスが作成されます。
単語 | ID |
---|---|
先週 | 1 |
吉祥寺 | 1 |
財布 | 1, 2 |
落とす | 2 |
警察署 | 2 |
… | … |
表のように抽出された単語と、その単語が出現する文章のIDをセットにした転置インテックステーブルが作成されます。
このようなインデックスを作り、高速に文章検索をすることができます。
こうしてElasticsearchを導入する方針は決まりましたが、MongoDB のデータをどのように Elasticsearch にリアルタイムで同期するかという課題が挙げられました。
本来であれば、追加・更新・削除のタイミングで Elasticsearch のデータを更新すれば問題ありません。
しかし、MongoDBのTTL indexによる自動削除を行なっていたため、完全に同期させる機能の実装はコストが高く難しい状態でした。
そこで、Monstache を採用することにしました。
Monstache
Monstache とは、MongoDB のデータを Elasticsearch に同期するデーモンです。
MongoDB の Replica Set の Oplog を読み取り、リアルタイムで同期します。これにより、TTL indexを考慮しての実装が不要になりました。
投稿保存時のイメージ図
Elasticsearch には、MongoDB に保存したデータと同じデータが保存されるため、あとは Elasticsearch で検索すれば、目的のデータを得ることができます。
これで、実装コストを抑えての部分一致検索を実装できました。
今後の課題
1. Elasticsearch の単語分割の調整
日本語の解析に Kuromoji Analysis Plugin を利用していますが、「これ」「ん」などの意味のない単語インデックスを作成してしまうため、チューニングが必要です。
2. 固有名詞の辞書作成・登録
アイテム名などでヒットさせるためです。
特殊な名前のアイテムなどは、デフォルト設定ではうまく転置インデックスを作成してくれないため、手動で辞書登録が必要になります。
3. Elasticsearch のローリングアップデートの仕組みを考える必要がある
Elasticsearch ではマッピング定義が作り直せないためです。
前述の固有名詞の辞書を更新する場合、全てのデータを入れ直す必要があります。
以上、MongoDB × Elasticsearch × Monstache での部分一致検索の紹介でした。