ククログ

株式会社クリアコード > ククログ > PostgreSQLで日本語全文検索 - LIKEとpg_bigmとPGroonga

PostgreSQLで日本語全文検索 - LIKEとpg_bigmとPGroonga

PostgreSQLアンカンファレンス@東京(2015/5/30)でPostgreSQLの日本語全文検索まわりについて紹介しようかとたくらんでいます。しかし、現時点(2015-05-25)でキャンセル待ちで、当日参加できないかもしれないので紹介しようと用意している内容をここにまとめます。

内容

この資料の目的は、PostgreSQLで使える次の3つの方法の特性を紹介し、ユーザーが適切な方法を選択するための材料を提供することです。

LIKE

LIKEのメリット・デメリットは次の通りです。

メリット

  • 標準で使える
  • インデックス作成不要(= データ更新が遅くならない)
  • データが少なければ十分速い

デメリット

  • データ量に比例して遅くなる

ユーザーがLIKEを使うかどうかの判断基準は「十分速いかどうか」(= 「データが少ないかどうか」)です。では、どのくらいなら「十分速い」のでしょうか。

「十分速い」かどうかは「検索対象のデータでの計測結果」と「要件」で判断できます。どちらもケースバイケースですが、参考情報としての計測結果なら示すことができます。

参考情報としてpg_bigmでいろんなデータを日本語検索してみよう!LIKEの結果を使ってみましょう。この記事では次の3つのデータを検索しています。

  • 青空文庫の書籍一覧データ
  • 住所データ
  • 日本版Wikipediaのタイトル一覧データ

それぞれみていきましょう。

まずは「青空文庫の書籍一覧データ」です。

このデータの特性と検索速度は次の通りです。

件数 1レコードあたりのバイト数 検索速度
11,818件 17バイト 6.673ms

6msで結果が返ってくるのであれば多くの要件で「十分速い」と言えるでしょう。つまり、このデータでは日本語全文検索の方法としてLIKEはアリということです。

次のデータは「住所データ」です。

このデータの特性と検索速度は次の通りです。

件数 1レコードあたりのバイト数 検索速度
147,769件 14バイト 70.684ms

70msで結果が返ってくるのであれば多くの要件で「十分速い」と言えるでしょう。つまり、このデータでも日本語全文検索の方法としてLIKEはアリということです。

最後のデータは「日本版Wikipediaのタイトル一覧データ」です。

このデータの特性と検索速度は次の通りです。

件数 1レコードあたりのバイト数 検索速度
2,461,588件 20バイト 943.450ms

1秒くらいで結果が返ってくるのでは、「十分速い」というのは要件次第でしょう。つまり、この規模のデータでは日本語全文検索の方法としてLIKEは使えるかもしれないし使えないかもしれない、といったところです。

これまでの結果をまとめると次の通りです。LIKEで十分かどうかを判断する場合は、実際のデータの傾向と検索時間を材料として検討します。

件数 1レコードあたりのバイト数 検索速度
11,818件 17バイト 6.673ms
147,769件 14バイト 70.684ms
2,461,588件 20バイト 943.450ms

では、LIKEでは十分速くない場合はどうしたらよいでしょうか。次のどちらかの方法を選びます。

  • pg_bigm
  • PGroonga

pg_bigm

pg_bigmのメリット・デメリットは次の通りです。

メリット

  • データ量が多くても高速
  • ストリーミングレプリケーションを使える

デメリット

  • 別途インストールしないといけない
  • インデックス作成が遅い(= データ更新が遅くなる)
  • ヒット数に比例して遅くなる

pg_bigmはデータ量が多くても高速ですが、ヒット数が多いほど遅くなる特性があります。pg_bigmが十分速いかどうかを判断するためにも、LIKEと同様に「検索対象のデータでの計測結果」と「要件」が必要です。ただし、LIKEとは注目するポイントが異なります。

それでは、検索結果例を見ながら注目するポイントを確認しましょう。なお、ここで紹介する検索結果例はPGroongaとpg_bigmのベンチマーク結果 · Issue #2 · groonga/wikipedia-searchにあります。手順もまとまっているので誰でも追試することができます。 ここで使うデータは日本語版Wikipediaの本文です。このデータの特性は次の通りです。

件数 1レコードあたりのバイト数
1,846,514件 3777バイト

注目するポイントの1つ目はインデックス作成時間です。元データのロード時間とインデックス作成時間は次の通りです。

元データのロード時間 インデックス作成時間
16分31秒 5時間56分15秒

約16分でロードできるデータのインデックス作成に約6時間かかるのは十分速いでしょうか。それとも遅いでしょうか。要件と照らしあわせて検討します。

なお、この時間はインデックス全体を1から作成する時間です。常に少量ずつ更新するという要件であればこの時間はあまり関係ありません。そのような要件の場合は、少量のデータの更新が滞らない(更新処理が溜まっていかない)くらいの速度がでていれば十分速いと判断できます。

注目するポイントの2つ目はヒット数と検索時間の関係です。

検索語 ヒット数 検索時間
「PostgreSQL」または「MySQL」 361 0.107s
データベース 17168 1.224s
テレビアニメ 22885 2.472s
日本 625792 0.556s

pg_bigmはヒット数が多くなるほど遅くなります。数百件ヒットのときは0.1秒ですが、1万7千件のときは1秒ちょい、2万2千件のときは約2.5秒となりました。なお、このデータではヒット数が増えるほど遅くなる傾向がよりわかりやすいデータになっています。というのは、このデータは1レコードあたりのデータが大きいからです。pg_bigmは1レコードあたりのデータが大きいと遅くなりやすい特性があります。

なお、検索語が2文字以下の場合はヒット数が多くても遅くなりにくいという特性があります。例では62万件ヒットしても0.5秒で結果を返しています。

このような特性があるpg_bigmなので、データによっては遅いと判断する場面も十分速いと判断する場面もあるでしょう。

PGroonga

LIKEでは遅い場合、pg_bigm以外の選択肢はPGroongaです。

PGroongaのメリット・デメリットは次の通りです。

メリット

  • インデックス作成が速い
  • データ量が多くても高速
  • ヒット数が多くても高速

デメリット

  • 別途インストールしないといけない
  • ストリーミングレプリケーション非対応
  • 使用ディスクサイズが多い

PGroongaはデータ量が多くてもヒット数が多くても速度が落ちにくく、インデックス作成も高速ですが、PostgreSQLとの連携度合いはpg_bigmほどではありません。たとえば、pg_bigmはPostgreSQL標準のストリーミングレプリケーション機能を使えますが、PGroongaは使えません。これはPostgreSQL側が連携する機能を提供していないことが原因です。今後連携できる機能が提供される見込みですが、現時点で連携できないことは事実です。

PGroongaを選ぶかどうかの基準は他の方法では遅いケースがPGroongaだと速いかどうかです。そのためには同じデータでpg_bigmと比較する必要があります。

それでは、pg_bigmと同じデータを使った場合のPGroongaの速度を確認しましょう。

まずはインデックス作成時間です。

元データのロード時間 16分31秒
PGroongaのインデックス作成時間 25分37秒
pg_bigmのインデックス作成時間 5時間56分15秒

参照しやすいようにpg_bigmのインデックス作成時間も再掲しています。

PGroongaは元データのロード時間の2倍いかないくらいの時間でインデックスを作成しています。pg_bigmと比べると1/14の時間でインデックスを構築できています。

ただし、インデックスのために使用するディスクサイズは大きいです。

元データロード直後のデータベースサイズ 4.0GiB
PGroongaの使用ディスクサイズ 14.0GiB
pg_bigmの使用ディスクサイズ 3.6GiB

ディスクサイズが小さい環境で動かす場合は問題になるかもしれません。

次は検索時間を確認しましょう。

検索語 ヒット数 PGroongaの検索時間 pg_bigmの検索時間
「PostgreSQL」または「MySQL」 368 0.030s 0.107s
データベース 17172 0.121s 1.224s
テレビアニメ 22885 0.179s 2.472s
日本 625792 0.646s 0.556s

PGroongaはpg_bigmほどヒット数の多さに影響をうけていません。62万件ヒットする場合でも0.6秒ちょいで結果を返しています。PGroongaは全体的に高速ですが、検索語が2文字以下の場合はpg_bigmの方が高速です。

PostgreSQLとの連携度合いよりも性能が大事な要件な場合で、pg_bigmでは性能が落ちやすい規模のデータではPGroongaが選択肢になるでしょう。

まとめ

PostgreSQLで日本語全文検索の方法として次の3つの方法を紹介しました。

  • LIKE
  • pg_bigm
  • PGroonga

データが少ないならLIKEで十分です。要件次第ですが、1レコード数十バイトの小さなデータなら百万件くらいまでいけるかもしれません。

データが多いならpg_bigmかPGroongaを選びます。

次のような場合はpg_bigmがよいでしょう。

  • 2文字以下での検索がほとんど
  • 1レコードあたりのデータが小さい
  • ヒット数が多くなることがほとんどない
  • ストリーミングレプリケーションを使いたい

pg_bigmで次のような問題があるならPGroongaがよいでしょう。

  • 1レコードあたりのデータが大きい
  • ヒット数が多くなるケースを考慮しないといけない
  • 更新が多くてインデックス更新速度がネックになる

ちなみに、PGroongaでもレプリケーションをする方法はあります。興味のある方はpg_shardとPGroongaを使ったレプリケーション対応の高速日本語全文検索可能なPostgreSQLクラスターの作り方を参考にしてください。

最後に、PostgreSQLの日本語全文検索に興味のある方にお願いです。この説明の中のpg_bigmとPGroongaの性能確認で参照したベンチマークをあなたの環境でも動かして結果を教えてもらえないでしょうか?同じ傾向があるか確認したいのです。ベンチマークの実行方法や必要な環境などの詳細は協力者募集:PGroongaとpg_bigmのベンチマークを実行を参照してください。