Mroongan((‘note:と’))nPGroonga¶ ↑
: subtitle
Groongaを使って\nMySQLとPostgreSQLで日本語全文検索
: author
須藤功平
: institution
クリアコード
: content-source
MySQLとPostgreSQLと日本語全文検索
: date
2016-02-09
: allotted-time
25m
: theme
groonga
Mroonga・PGroonga¶ ↑
* Mroonga(むるんが) * (('wait'))MySQLに\n 高速日本語全文検索機能を追加する\n プロダクト * PGroonga(ぴーじーるんが) * (('wait'))PostgreSQLに\n 高速日本語全文検索機能を追加する\n プロダクト
すごい!使いたい!¶ ↑
* (('wait'))インストールして! * え。。。組み込みじゃないの。。。\n (('note:(MariaDBにはMroongaは組み込まれています!)')) * (('wait'))パッケージあるから簡単だよ! * クラウドサービスで使えない。。。 * (('wait'))(('note:(クラウドサービスに入っていれば…!)')) * (('note:HerokuのPostgreSQLにPGroonga入れて!とお願いだ!'))
使いたい!?¶ ↑
# blockquote HerokuのPostgreSQLで\n PGroongaを使えるなら\n Herokuを使いたい!\n#herokujp
((‘tag:center’)) ↑と思うならtweet!n (Herokuの人が観測します。)
高速?¶ ↑
((‘tag:center’)) ベンチマーク!
* 対象:Wikipedia日本語版 * レコード数:約185万件 * データサイズ:約7GB * メモリー4GB・SSD250GB(('note:(ConoHa)'))
((‘note:github.com/groonga/wikipedia-search/issues/4’))
((‘tag:center’)) ((‘note:(他人のベンチマークは参考程度)’))n ((‘note:(検討時はちゃんと実際の環境でベンチマークをとろう!)’))
速さ:検索1¶ ↑
((‘tag:center’)) キーワード:テレビアニメn ((‘note:(ヒット数:約2万3千件)’))
# RT delimiter = [|] InnoDB ngram | 3m2s InnoDB MeCab | 6m20s Mroonga:((*1*)) | 0.11s pg_bigm | 4s PGroonga:((*2*)) | 0.29s
速さ:検索2¶ ↑
((‘tag:center’)) キーワード:データベースn ((‘note:(ヒット数:約1万7千件)’))
# RT delimiter = [|] InnoDB ngram | 36s InnoDB MeCab:((*1*)) | 0.03s Mroonga:((*2*)) | 0.09s pg_bigm | 2s PGroonga:((*3*)) | 0.17s
速さ:検索3¶ ↑
((‘tag:center’)) キーワード:PostgreSQL OR MySQLn ((‘note:(ヒット数:約400件)’))
# RT delimiter = [|] InnoDB ngram | N/A(エラー) InnoDB MeCab:((*1*)) | 0.005s Mroonga:((*2*)) | 0.028s pg_bigm | 0.185s PGroonga:((*3*)) | 0.063s
速さ:検索4¶ ↑
((‘tag:center’)) キーワード:日本n ((‘note:(ヒット数:約63万件)’))
# RT delimiter = [|] InnoDB ngram | 1.3s InnoDB MeCab | 1.3s Mroonga:((*1*)) | 0.21s pg_bigm:((*2*)) | 0.84s PGroonga | 1s
速さ:検索まとめ¶ ↑
* Mroonga・PGroonga * (('wait'))安定して速い * InnoDB FTS MeCab・pg_bigm * (('wait'))ハマれば速い * InnoDB FTS ngram * (('wait'))安定して遅い
使いたい!?¶ ↑
# blockquote HerokuのPostgreSQLで\n PGroongaを使えるなら\n Herokuを使いたい!\n#herokujp
((‘tag:center’)) ↑と思うならtweet!n (Herokuの人が観測します。)
速さ:データロード¶ ↑
((‘tag:center’)) 約185万件・約7GB・SSD
# RT delimiter = [|] InnoDB ngram | 6m51s InnoDB MeCab | 6m22s Mroonga:((*3*)) | 5m45s pg_bigm:((*1*)) | 5m14s PGroonga:((*2*)) | 5m22s
((‘note:MySQLはbinlog有効、PostgreSQLはWAL有効’))n ((‘note:InnoDBはどっちも同じ処理’))n ((‘note:pg_bigmとPGroongaもどっちも同じ処理’))
速さ:インデックス作成¶ ↑
((‘tag:center’)) 約185万件・約7GB・SSD
# RT delimiter = [|] InnoDB ngram | 3h06m58s InnoDB MeCab | 2h41m55s Mroonga:((*1*)) | 22m24s pg_bigm | 3h43m23s PGroonga:((*2*)) | 54m34s
((‘note:MySQLはbinlog有効、PostgreSQLはWAL有効’))n ((‘note:バルクインデックス作成’))n ((‘note:=データ投入後インデックス作成’))
速さ:ロードまとめ¶ ↑
* (('wait'))データロードは大差ない * (('wait'))インデックス作成は大差 * Mroonga・PGroongaは分単位 * InnoDB・pg_bigmは時間単位
使いたい!?¶ ↑
# blockquote HerokuのPostgreSQLで\n PGroongaを使えるなら\n Herokuを使いたい!\n#herokujp
((‘tag:center’)) ↑と思うならtweet!n (Herokuの人が観測します。)
サイズ:データ¶ ↑
# RT delimiter = [|] InnoDB ngram | 10GB InnoDB MeCab | 10GB Mroonga | 8.2GB pg_bigm:((*2*)) | 5.1GB PGroonga:((*1*)) | 4.3GB
((‘note:InnoDBはどっちも同じ’))n ((‘note:pg_bigmとPGroongaはどっちも同じはずだけど…’))
サイズ:インデックス¶ ↑
# RT delimiter = [|] InnoDB ngram | 12GB InnoDB MeCab:((*1*)) | 6GB Mroonga:((*1*)) | 6GB pg_bigm:((*3*)) | 7GB PGroonga | 10GB
((‘note:InnoDBは一時ファイル(何十GB単位)を作る’))n ((‘note:PGroongaは元データ(8GB)のコピーもLZ4圧縮して持っている’))
サイズ:まとめ¶ ↑
* データサイズ * PostgreSQLは元データより小さめ * InnoDBは元データより大きめ * インデックスサイズ * InnoDB MeCabは小さめ\n (('note:(ヒント:形態素解析ベースの方が小さくなる)')) * Mroonga・pg_bigmはN-gramなのにInnoDB MeCabと同じくらい
高速?¶ ↑
ベンチマークでn 確認
Mroonga・PGroonga¶ ↑
* Mroonga(むるんが) * (('wait'))MySQLに\n 高速日本語全文検索機能を追加する\n プロダクト * PGroonga(ぴーじーるんが) * (('wait'))PostgreSQLに\n 高速日本語全文検索機能を追加する\n プロダクト
実現方法¶ ↑
* Mroonga(むるんが) * (('wait'))MySQLに\n ((*Groonga(ぐるんが)*))を組み込み * PGroonga(ぴーじーるんが) * (('wait'))PostgreSQLに\n ((*Groonga(ぐるんが)*))を組み込み
Groonga¶ ↑
* (('wait'))国産の高速全文検索エンジン * 日本語バッチリ * (('wait'))ライブラリーとして使える * 組み込みやすい * (('wait'))マルチスレッド対応\n (('note:(MySQL組み込み時にうれしい)')) * (('wait'))マルチプロセス対応\n (('note:(PostgreSQL組み込み時にうれしい)'))
組み込み方針¶ ↑
* Groongaをできるだけ活かす * 使い勝手はMySQL・PostgreSQLに寄せる
((‘wait’)) ((‘tag:center’)) ↓n SQLで使えるGroonga
ポジション¶ ↑
# image # src = images/position.svg # relative_height = 100
SQLで使えるGroonga¶ ↑
* Groongaのフル機能は諦める * 速度など譲れない部分はがんばる * その分、使いやすさを重視 * (('wait'))使いやすさ1=\n MySQL・PostgreSQLとなじんでいる * (('wait'))使いやすさ2=\n MySQL・PostgreSQLの不便を解消
なじみ度:Mroonga¶ ↑
((‘tag:center’)) インデックス作成:MySQLと同じ
# coderay sql CREATE TABLE ... ( ..., FULLTEXT INDEX (column) ) ENGINE=Mroonga;
なじみ度:Mroonga¶ ↑
((‘tag:center’)) 全文検索:MySQLと同じ
# coderay sql SELECT * FROM ... WHERE MATCH(column) AGAINST('キーワード' IN BOOLEAN MODE);
不便解消:Mroonga¶ ↑
((‘tag:center’)) デフォルトOR→AND
# coderay sql -- ↓AまたはBが含まれていればマッチ AGAINST('A B' IN BOOLEAN MODE); AGAINST('+A +B' IN BOOLEAN MODE); -- ↑↓AとBが含まれていればマッチ -- ↓Mroongaの拡張 AGAINST('*D+ A B' IN BOOLEAN MODE);
不便解消:Mroonga¶ ↑
((‘tag:center’)) 重み指定
# coderay sql -- titleかcontentにAがあればマッチ -- (便利。PostgreSQLではできない。) MATCH(title, content) AGAINST('A' IN BOOLEAN MODE) -- でもtitleの方を重要視したい! -- ↓Mroongaの拡張 AGAINST('*W1:10,2:1 A' IN BOOLEAN MODE)
不便解消:Mroonga¶ ↑
((‘tag:center’)) 全文検索+ORDER LIMIT高速化
# coderay sql SELECT * FROM tweets WHERE MATCH(content) AGAINST('...' IN BOOLEAN MODE) ORDER BY timestamp DESC LIMIT 10;
ORDER LIMIT高速化¶ ↑
* なぜ速いか * (('wait'))Groongaでソートし、LIMIT件だけMySQLに返しているから * (('wait'))MySQLよりGroongaでやった方が速い\n (('note:(ヒント:カラムストア)'))
さらにORDER LIMIT高速化¶ ↑
# coderay sql SELECT * FROM tweets WHERE MATCH(content) AGAINST('...' IN BOOLEAN MODE) AND timestamp >= '2016-02-01' -- ↑今月の分だけ対象にしたい ORDER BY timestamp DESC LIMIT 10;
さらにORDER LIMIT高速化¶ ↑
* なぜ速いか * (('wait'))Groongaで((*絞り込んで*))ソートし、\n LIMIT件だけMySQLに返しているから * (('wait'))MySQLよりGroongaでやった方が速い\n (('note:(ヒント:カラムストア)')) * 場合によっては10倍以上高速化 * (('note:http://tech.gmo-media.jp/post/69542751128/mroonga-311-new-optimization'))
PGroonga¶ ↑
* Groongaのフル機能は諦める * 速度など譲れない部分はがんばる * その分、使いやすさを重視 * 使いやすさ1=\n MySQL・((*PostgreSQL*))となじんでいる * 使いやすさ2=\n MySQL・((*PostgreSQL*))の不便を解消
なじみ度:PGroonga¶ ↑
((‘tag:center’)) インデックス作成:n PostgreSQLと同じ
# coderay sql CREATE INDEX name ON texts USING pgroonga (content);
なじみ度:PGroonga¶ ↑
((‘tag:center’)) 全文検索:n PostgreSQLのtextsearchとほぼ同じ
# coderay sql SELECT * FROM ... WHERE column @@ 'キーワード';
textsearchとの違い¶ ↑
((‘tag:center’)) 構文
# coderay sql -- textsearch -- プログラムのよう '(A & B) | C' -- PGroonga(不便解消) -- Web検索エンジンのよう '(A B) OR C'
不便解消:PGroonga¶ ↑
((‘tag:center’)) Windows用バイナリーあり
* (('wait'))商用ログ管理製品\n 「VVAULT AUDIT」が採用\n (('note:http://vvault.jp/product/vvault-audit/')) * アクセスログに対して\n ユーザー名・パスを全文検索 * (('wait'))決め手:高速・省スペース
不便解消:PGroonga¶ ↑
((‘tag:center’)) JSONデータを全文検索
# coderay sql CREATE TABLE logs (record jsonb); CREATE INDEX i ON logs USING pgroonga (record); -- ログのどこかに「error」があればマッチ SELECT * FROM logs WHERE record @@ 'string @ "error"';
JSON全文検索例¶ ↑
((‘tag:center’)) 以下は全部マッチ
# coderay json {"message": "Error!"} {"tags": ["web", "error"]} {"syslog": {"message": "error!"}}
使いたい!?¶ ↑
# blockquote HerokuのPostgreSQLで\n PGroongaを使えるなら\n Herokuを使いたい!\n#herokujp
((‘tag:center’)) ↑と思うならtweet!n (Herokuの人が観測します。)
まとめ1¶ ↑
* Groonga(ぐるんが) * (('wait'))国産の高速全文検索エンジン * Mroonga(むるんが) * (('wait'))MySQLからGroongaを使える! * PGroonga(ぴーじーるんが) * (('wait'))PostgreSQLからGroongaを使える!
まとめ2¶ ↑
((‘tag:center’)) 実装方針
* (('wait'))Groongaをできるだけ活かす\n (('note:(例:速度)')) * (('wait'))MySQL/PostgreSQLっぽく使える * (('wait'))MySQL/PostgreSQLをより便利に
次回予告¶ ↑
* (('wait'))トランザクションは? * (('wait'))クラッシュしたら? * (('wait'))レプリケーションは? * (('wait'))もっと速くならないの?