Redmineでもっと高速に全文検索する方法 - 2017-09-25 - ククログ

ククログ

株式会社クリアコード > ククログ > Redmineでもっと高速に全文検索する方法

Redmineでもっと高速に全文検索する方法

Redmineで高速に全文検索する方法で紹介したプラグインの新しいバージョンをリリースしてさらに高速化しました。

v0.6.0での変更点

  • 検索結果のハイライトにPGroonga/Mroongaの機能を使用するようにしました

    • 複数キーワードごとに色分けしないようになりました
  • クエリー構文が使えるようになりました

  • 類似チケットの表示をするようにしました

類似チケット

Groongaの類似文書検索の機能を使って類似チケットを表示するようになりました。

例えば、あるソフトウェアのサポートをしているときに似た問い合わせが過去にあれば、その似た問い合わせが類似チケットとして表示されることを期待しています。 現在の実装では、チケットのトラッカー、起票者、担当者、カテゴリなどのメタデータを一切考慮していないので精度はそこそこです。 クリアコード社内で運用しているRedmine1に入れてみたところ類似チケットの検索には15msくらいしかかかっていないのでRedmineの性能に影響はないと考えてデフォルトでONにしてあります。

なぜ高速化したか

元のRedmineの全文検索では、最大で以下の9つのテーブルを検索し、検索時に全件取得してキャッシュしていました。

  • チケット

  • ニュース

  • 文書

  • 更新履歴

  • Wikiページ

  • メッセージ

  • プロジェクト

  • 添付ファイル

  • チケットのコメント

redmine_full_text_search v0.4.0 までは既存のコードをなるべく活かしていたので、クエリの実行数は同じで全件取得していたのも同じでした。 つまり、上記全てのテーブルから検索すると1回のクエリで100msだとしても 9 * 100ms = 900ms と約1秒かかってしまうことになります。 v0.5.0 では、検索対象のレコードを1つのテーブルにまとめてGroongaの機能を直接使用して全文検索のために実行するクエリを1つにしました。 また、limit と offset を使用して一度に取得するレコード数を減らし、Redmineのキャッシュを使用するのをやめました。

ベンチマーク

  • 環境

    • Google Compute Engine

    • n1-standard-2 (vCPUx2, メモリー7.5GB)

    • OS Debian GNU/Linux stretch

    • Ruby 2.3.3p222

    • Redmine 3.4.2

    • Passenger 5.0.30-1+b1

    • MariaDB 10.1.26-0+deb9u1

    • Mroonga 7.06-1

    • PostgreSQL 9.6.4-0+deb9u1

    • PGroonga 2.0.1-1

redmine_full_text_searchのバージョンはv0.4.0とv0.6.2を使用しました。 内部ネットワークからMechanizeで特定のユーザーでログインして表にあるクエリーで検索しました。 以下にMariaDB(Mroonga)の場合とPostgreSQL(PGroonga)の場合についてそれぞれの測定結果を示します。

データは、以下のメーリングリストのアーカイブを使用しました。 メーリングリストごとにプロジェクトを作成しました。 メールからチケットを作成し、In-Reply-Toで返信だと判断できる場合は、見つかったチケットへのコメントとして登録するようにしました。

これで31142チケットと72392コメントのデータベースを作成しました。redmine_full_text_search v0.6.2向けのテーブルには103537件レコードが存在します。 Wikiやドキュメント等チケット以外のデータはありません。

測定結果の単位は全てミリ秒です。

MariaDB

Redmine v0.4.0 v0.6.2
query 1st 2nd 1st 2nd 1st 2nd
cgi リーク duration 1804.86 56.0048 1028.55 62.8551 140.443 138.351
view_runtime 27.8059 29.7982 30.5287 26.2161 61.5869 55.7791
db_runtime 1758.66 5.93903 969.221 7.09439 64.5651 63.6323
groonga duration 1687.73 82.2862 1053.66 124.609 119.136 115.352
view_runtime 18.7162 19.5571 25.1116 21.4028 42.1369 39.2488
db_runtime 1611.95 5.80468 923.49 12.0304 63.7171 62.6385
mroonga score duration 1712.8 38.6372 1043.22 50.2505 134.332 115.884
view_runtime 19.4748 18.8583 20.4314 21.4807 42.9837 41.9256
db_runtime 1678.16 5.84049 998.232 5.45167 64.2949 61.54
pgrooga score duration 1675.0 25.8263 907.864 38.1889 72.0365 72.458
view_runtime 10.8129 10.5722 12.1855 13.2947 12.3002 12.2505
db_runtime 1653.34 5.25172 877.303 5.14269 52.3137 52.2138
ruby duration 1876.77 1240.81 2858.95 1576.22 182.263 182.67
view_runtime 17.2178 17.4677 20.9058 21.6165 44.5798 46.555
db_runtime 683.701 9.14142 1324.75 19.6118 108.922 106.341
segv duration 1734.57 97.6753 1221.78 125.179 207.27 128.385
view_runtime 51.7349 22.1543 33.8267 31.1135 104.215 49.5876
db_runtime 1610.52 6.07189 1056.77 6.53569 87.9873 62.8314
segv make duration 1815.31 68.4352 958.573 72.8359 119.899 148.094
view_runtime 22.0608 32.7035 35.3729 27.96 42.5002 67.0567
db_runtime 1769.95 5.81216 880.271 6.27881 64.3565 62.977
メモリーリーク duration 1665.0 49.0786 962.625 54.4098 151.751 119.179
view_runtime 21.1638 25.3095 25.1169 23.1611 73.9769 47.4756
db_runtime 1626.61 5.58291 909.367 5.83328 65.4596 60.8111
メモリリーク duration 1668.5 49.7472 1005.86 56.3724 111.954 111.491
view_runtime 22.01 22.3757 18.6613 20.756 41.0274 40.3688
db_runtime 1620.18 5.67121 947.36 5.73328 60.8254 59.7722
ライトニングトーク カンファレンス 開催 duration 1730.69 39.2599 950.232 48.4056 122.699 117.899
view_runtime 18.879 20.1971 24.7018 21.0985 43.9869 42.6021
db_runtime 1697.25 5.37024 901.403 5.60327 65.7128 63.2021
発表者 募集 duration 1540.63 41.1723 1026.68 46.5856 116.767 114.665
view_runtime 18.8667 18.5547 20.2438 19.4315 42.4205 42.7707
db_runtime 1505.5 5.52283 982.723 5.2658 62.3322 60.5112
勉強会 会議 duration 1535.28 39.5411 948.463 47.6093 114.435 137.902
view_runtime 17.7493 19.1658 19.8384 19.5605 41.9521 40.7409
db_runtime 1501.66 5.67893 904.492 5.73054 61.676 60.6336

平均と標準偏差は以下の通りです。

Redmine v0.4.0 v0.6.2
1st 2nd 1st 2nd 1st 2nd
平均 duration 1703.93 152.37 1163.87 191.96 132.75 125.19
view_runtime 22.21 21.39 23.91 22.26 49.47 43.86
db_runtime 1559.79 5.97 972.95 7.53 68.51 64.76
標準偏差 duration 97.12 328.76 516.86 418.29 33.65 25.04
view_runtime 9.66 5.57 6.41 4.36 21.41 12.19
db_runtime 275.78 0.98 117.69 4.05 14.46 12.87

MariaDBの場合はほぼ想定通りの測定結果でした。 プラグインなしの場合は、DBアクセスに初回1500ms以上かかっていたのが2回目は5ms前後になっていてキャッシュが効いています。 プラグインv0.4.0の場合は、DBアクセスに初回1000ms前後にかかってており、2回目は5ms前後になっていました。 プラグインv0.6.2の場合は、DBアクセスに初回、2回目ともに50-100ms程度かかっており、初回の検索から速いのでキャッシュしなくても十分な速度が出ています。

プラグインなしの場合とv0.6.2の場合を比較すると、初回の検索で約24倍高速になっています。

db_runtimeの標準偏差を見ると、v0.6.2のとき最も値が小さくなっており、安定して高速に動作することがわかります。

PostgreSQL

Redmine v0.4.0 v0.6.2
query 1st 2nd 1st 2nd 1st 2nd
cgi リーク duration 5432.23 5708.34 91.9298 91.6952 205.405 207.645
view_runtime 24.3255 26.9705 31.3033 37.1955 39.1355 50.9562
db_runtime 5385.85 5660.76 29.0279 29.6823 145.829 144.418
groonga duration 5060.77 5071.71 669.003 647.418 185.603 182.977
view_runtime 24.3327 20.2376 26.1071 40.4994 30.0942 30.011
db_runtime 4933.86 4929.92 560.77 522.823 146.799 144.304
mroonga score duration 5177.38 5167.46 69.7063 64.5032 181.835 181.996
view_runtime 20.2529 20.5412 26.1367 23.6614 29.0306 28.7275
db_runtime 5139.11 5127.81 22.2003 21.8169 144.434 143.932
pgrooga score duration 5037.87 5056.32 46.4337 43.408 153.975 159.449
view_runtime 11.5761 11.7345 15.6785 14.6403 12.8356 12.9991
db_runtime 5013.34 5031.37 14.6134 14.7022 134.023 138.259
ruby duration 3542.06 3402.16 19749.8 19558.4 238.018 222.578
view_runtime 18.2419 18.4601 18.6485 26.2439 43.0062 29.8173
db_runtime 1511.17 1508.25 18214.4 17921.3 184.03 182.523
segv duration 5270.42 5333.98 522.433 443.14 384.031 190.565
view_runtime 28.5796 26.4264 43.9667 33.4644 90.3281 35.4176
db_runtime 5104.6 5174.81 351.514 309.031 283.627 144.746
segv make duration 5691.51 5691.54 153.903 145.227 190.858 201.922
view_runtime 27.0135 27.8609 44.5491 40.7997 32.3304 43.489
db_runtime 5613.84 5617.51 66.682 64.3612 148.758 147.865
メモリーリーク duration 5789.28 5752.14 75.0013 72.5004 195.717 200.674
view_runtime 23.1544 21.7764 20.2103 21.5645 41.4241 45.2702
db_runtime 5740.95 5709.43 33.8974 31.4955 141.669 143.453
メモリリーク duration 5749.46 5792.81 105.487 102.567 196.678 187.858
view_runtime 23.1136 22.6125 21.9238 23.339 37.9664 35.4135
db_runtime 5696.29 5738.85 57.3894 54.1745 143.913 142.159
ライトニングトーク カンファレンス 開催 duration 5842.91 5811.98 63.857 66.4787 187.346 185.818
view_runtime 20.0885 22.1672 22.3308 23.4369 30.5955 29.236
db_runtime 5804.88 5770.79 22.9653 23.6612 146.704 146.915
発表者 募集 duration 5154.93 5152.25 74.2416 73.2 183.645 181.342
view_runtime 20.5156 19.2945 27.7632 29.5588 31.441 30.5509
db_runtime 5114.81 5112.4 24.3069 23.246 143.74 141.939
勉強会 会議 duration 5028.9 5064.46 65.7615 78.8453 180.065 182.6
view_runtime 19.6628 18.504 21.4198 33.3649 29.5505 30.3836
db_runtime 4989.92 5025.62 24.977 24.7126 142.494 143.389

平均と標準偏差は以下の通りです。

Redmine v0.4.0 v0.6.2
1st 2nd 1st 2nd 1st 2nd
平均 duration 5231.48 5250.43 1807.30 1782.28 206.93 190.45
view_runtime 21.74 21.38 26.67 28.98 37.31 33.52
db_runtime 5004.05 5033.96 1618.56 1586.75 158.84 146.99
標準偏差 duration 590.01 633.07 5413.33 5362.64 56.54 15.34
view_runtime 4.26 4.25 8.84 7.84 17.67 9.38
db_runtime 1096.48 1107.02 5006.48 4927.30 39.38 10.96

PostgreSQLの場合は、プラグインなしのときは初回、2回目ともにDBアクセスに約5秒かかっているのでキャッシュが効いていないことがわかります。 v0.4.0の場合もキャッシュが効いておらず、初回、2回目ともにDBアクセスに約1.5秒かかっています。プラグインなしと比較して、約3倍高速になりました。 v0.6.2ではRedmineのキャッシュを使用しないようにしたので、キャッシュの影響はありません。初回、2回目ともにDBアクセスに約0.15秒かかっています。 プラグインなしと比較すると、約33倍高速になりました。v0.4.0と比較すると約10倍高速になっています。

db_runtimeの標準偏差を見ると、v0.6.2のとき最も値が小さくなっており、安定して高速に動作することがわかります。

MariaDBとPostgreSQLの比較

redmine_full_text_search v0.6.2の場合、MariaDBとPostgreSQLのdb_runtimeの平均を比較するとMariaDBの方が約2.3倍高速という結果でした。 これは、MroongaとPGroongaでGroonga上のテーブル定義やインデックス定義に違いがあるためではないかと考えています。

まとめ

今後は、機能を充実させつつMariaDBとPostgreSQLのどちらを使っても快適に検索できるようにしていきたいです。 やりたいことについてはプロジェクトのissuesも見てください。

  1. チケット数は約4000件