[お知らせ] 2016年9月29日(肉の日)にMySQLとPostgreSQLと日本語全文検索3というイベントが開催されます。今回の事例紹介はMySQL InnoDBの全文検索機能です。Groongaをストレージエンジンとして採用しているMroongaの紹介もありますよ。
はじめに
高速な全文検索を実現するためのソフトウェアとして、Groongaがあります。この記事を書いている時点の最新バージョンは6.0.8です。
Groongaにアクセスするプロセスが1つのときには問題になりませんが、複数のプロセスからGroongaにアクセス(例えば複数のgroongaコマンドで同じデータベースを開く)するようになったときには、ちょっと注意しないといけないことがあります。
今回はその「ちょっと注意しないといけない」ポイントについて説明します。
スキーマを変更する場合
Groongaのデータベースは複数のプロセスで共有可能なようになっています。そのため複数のプロセスからデータを更新することに何ら問題はありません。
しかし、スキーマの変更となると事情が変わってきます。
例えば、同じGroongaのデータベースを複数のクライアントからアクセスしスキーマの変更を行うケースを考えます。
あらかじめ、以下のスキーマでデータベースを構築してあるとしましょう。
table_remove User
table_create User TABLE_PAT_KEY UInt32
column_create User first_name COLUMN_SCALAR ShortText
column_create User last_name COLUMN_SCALAR ShortText
load --table User
[
{"_key":1, "first_name":"Taro", "last_name":"Maruwa"},
{"_key":2, "first_name":"Hanako", "last_name":"Yamada"}
]
groongaコマンドを使って、データベースにアクセスすることにします。
プロセスAでは、スキーマの変更はしません。一方プロセスBではスキーマを変更するものとします。
プロセスA
プロセスAではスキーマを変更しません。定義されているテーブルとカラムのリストを確認してみましょう。
table_list
とcolumn_list
で定義を確認します。
% groonga testdb/db
> table_list
[[0,1474006053.211516,0.0006153583526611328],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[256,"User","testdb/db.0000100","TABLE_PAT_KEY|PERSISTENT","UInt32",null,null,null]]]
> column_list User
[[0,1474006056.986597,0.0002224445343017578],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[256,"_key","","","COLUMN_SCALAR","User","UInt32",[]],[258,"first_name","testdb/db.0000102","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]],[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]]]]
プロセスB
プロセスBではスキーマの定義を変更します。
具体的には、last_name
のカラムの型をShortText
からLongText
に変更します。そのために、一旦User
テーブルからlast_name
カラムを削除して、再度カラムを作りなおします。
% groonga testdb/db
> column_remove User last_name
[[0,1474006068.331246,0.002974987030029297],true]
> column_create User last_name COLUMN_SCALAR LongText
[[0,1474007443.677316,0.004316091537475586],true]
> column_list User
[[0,1474007451.995359,8.463859558105469e-05],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[256,"_key","","","COLUMN_SCALAR","User","UInt32",[]],[258,"first_name","testdb/db.0000102","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]],[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","LongText",[]]]]
column_list
で現在のカラムを参照すると、last_name
カラムの型がLongText
に変更されていることがわかります。
[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","LongText",[]]
再びプロセスA
さて、プロセスAではプロセスBのスキーマ定義変更はどのように見えているでしょうか。
プロセスAに戻って確認してみましょう。
プロセスBがテーブルを削除した時点では、カラムが消えているだけなので特に問題がありません。
> column_list User
[[0,1474006125.018618,9.870529174804688e-05],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[256,"_key","","","COLUMN_SCALAR","User","UInt32",[]],[258,"first_name","testdb/db.0000102","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]]]]
しかし、カラムが再作成されたあとはどうでしょうか。column_list
で定義を確認してみます。
> column_list User
[[0,1474007459.899354,9.703636169433594e-05],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[256,"_key","","","COLUMN_SCALAR","User","UInt32",[]],[258,"first_name","testdb/db.0000102","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]],[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]]]]
注目すべきは、last_name
の型です。プロセスBでLongText
型で作成したはずのlast_name
カラムが、何故かShortText
型になってしまっています。これでは、プロセスBでカラムを再作成する前の状態ですね。
[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]]
古いlast_nameの定義を参照したままになってしまっていることがわかりました。
古い定義が参照されたままになる問題への対策
古い定義を参照したままになっているのが問題なので、再度データベースを開き直します。
具体的にはプロセスAを実行しているgroongaコマンドを一旦終了します。
> quit
[[0,1474010060.188753,3.24249267578125e-05],true]
% groonga testdb/db
> column_list User
[[0,1474010067.628873,0.0002775192260742188],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[256,"_key","","","COLUMN_SCALAR","User","UInt32",[]],[258,"first_name","testdb/db.0000102","var","COLUMN_SCALAR|PERSISTENT","User","ShortText",[]],[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","LongText",[]]]]
再度データベースを開き直したので、期待通りにlast_name
カラムはLongText
型になっています。
[257,"last_name","testdb/db.0000101","var","COLUMN_SCALAR|PERSISTENT","User","LongText",[]]
groongaコマンドを終了したくない場合には、database_unmapコマンドを実行する方法もあります。
このコマンドを実行すると、それまでキャッシュされた情報を一旦破棄するからです。
まとめ
groongaコマンドを利用して複数のプロセスからGroongaにアクセスするときに、スキーマの変更を伴う場合に注意するべきポイントを説明しました。
変更したスキーマ定義が反映されていないときには、複数のプロセスでアクセスしたりしていないか確認してみてください。
もし、上記の状況になったら、groongaコマンドを一旦終了するか、database_unmapコマンドを実行するなどしてデータベースを開き直すことで解決できます。