BloGroonga

2017-04-29

Groonga 7.0.2リリース

今日は肉の日ですね!

Groonga 7.0.2をリリースしました!

それぞれの環境毎のインストール方法: インストール

変更内容

今回のリリースでは、特定の条件下で reindex コマンドを使うとデータを失ってしまう不具合を修正しています。

主な変更点は以下の通りです。

  • reindexコマンドの実行によりデータが失われてしまう不具合を修正しました
  • Ubuntu 17.04 (Zesty Zapus)をサポートしました
  • 永続キャッシュをサポートしました
  • [in_records] 既存のテーブルを条件のパターンとして指定できるようになりました

reindexコマンドの実行によりデータが失われてしまう不具合を修正しました

今回のリリースでは、特定の条件下でreindexコマンドを使うとデータが失われてしまう不具合を修正しました。

インデックスだけが壊れてしまった場合、reindexを使って復旧することができます。しかし、今回見つかった不具合の発生条件を満たすと、無事だったデータを消してしまいます。

この不具合は、reindexコマンドが追加されたGroonga 5.1.0からの潜在的な不具合した。

テーブルにデータカラムがなくインデックスカラムのみある場合、そのテーブルは語彙表として使っていると判断し、テーブルのキーを全部消してから作り直すようにしていましたが、そのせいでデータを消してしまっていました。

例えば、次のようにすると問題を再現することが可能です。

> table_create User TABLE_HASH_KEY ShortText
[[0,1490948112.512871,0.004843950271606445],true]
> table_create Comment TABLE_NO_KEY
[[0,1490948112.517823,0.004474639892578125],true]
> column_create Comment user COLUMN_SCALAR User
[[0,1490948112.522444,0.00609898567199707],true]
> column_create User comment COLUMN_INDEX Comment user
[[0,1490948112.528664,0.009341239929199219],true]
> load --table Comment
> [
> {"user":"Mike"}
> ]
[[0,1490948112.538067,0.0004284381866455078],1]

> select User
[[0,1490948112.538533,0.0002899169921875],[[[1],[["_id","UInt32"],["_key","ShortText"],["comment","UInt32"]],[1,"Mike",1]]]]
> select Comment
[[0,1490948112.53886,4.744529724121094e-05],[[[1],[["_id","UInt32"],["user","User"]],[1,"Mike"]]]]

> reindex
[[0,1490948112.538933,0.02556586265563965],true]

> select User
[[0,1490948112.564538,5.91278076171875e-05],[[[0],[["_id","UInt32"],["_key","ShortText"],["comment","UInt32"]]]]]
> select Comment
[[0,1490948112.564621,3.457069396972656e-05],[[[1],[["_id","UInt32"],["user","User"]],[1,""]]]]

reindexした後の User テーブルと Comment テーブルのデータが失われていることがわかります。

Ubuntu 17.04 (Zesty Zapus)をサポートしました

今回のリリースでは、今月リリースされたUbuntu 17.04 (Zesty Zapus)をサポートしました。 PPA経由でインストールできます。

また、Ubuntu 12.04は4/28にEOLとなったため、サポートをやめています。

永続キャッシュをサポートしました

今回のリリースでは、永続キャッシュと呼ばれる仕組みをサポートしました。

GroongaのキャッシュはGroongaを終了すると消えてしまいます。再び起動しなおした場合、再度キャッシュを作り直すまでにはタイムラグが発生します。 永続キャッシュを使うと、そのタイムラグを短縮することができます。

groongaコマンドの場合

groongaコマンド実行時に --cache-base-path オプションを指定します。

このオプションには永続キャッシュを保存するパスを指定します。例えば、--cache-base-path=/dev/shm/groonga-cache を指定すると、 /dev/shm 直下に永続キャッシュファイルができます。この例だと次の2つのファイルが作成されます。

  • /dev/shm/groonga-cache.keys
  • /dev/shm/groonga-cache.values
groonga-httpdの場合

groonga-httpdの設定ファイル(/etc/groonga/groonga-httpd.conf)に以下の設定を追加します。

http {
  ...
  groonga_cache_base_path /dev/shm/groonga-httpd-cache;
  ...
}

serverやlocationディレティブごとに指定することもできます。ここで指定した永続キャッシュはワーカー間で共通です。従来のキャッシュの場合には、ワーカー毎にキャッシュを保持していました。永続キャッシュでは共通なので、あるワーカーではキャッシュされていたので速いけど、ほかのワーカーではキャッシュされていなかったので遅い、というようなことが起きなくなります。また、キャッシュ数の設定をワーカー毎にしなくてすむようになります。

注意事項について
  • メモリーファイルシステム上のパス(例:/dev/shm/xxxx)を必ず指定してください。ハードディスクなどディスクIOが遅い場合には、永続キャッシュを使用しても、その読み込みに時間がかかってしまうため、キャッシュを永続化する利点が薄れてしまいます。

  • 永続キャッシュにおいて、キャッシュ数の制御がまだ行えません。cache_limitは従来のキャッシュのみサポートしています。永続キャッシュのデフォルト設定値は100です。

  • 永続キャッシュを開けない場合は自動的に再作成するので問題ありませんが、クラッシュした場合はキャッシュファイルを削除してください。

[in_records] 既存のテーブルを条件のパターンとして指定できるようになりました

今回のリリースでは、既存のテーブルを条件のパターンとして指定するための in_records をサポートしました。 in_records を使うと複数のクエリーを1つのクエリーへとまとめることができるかもしれません。 これは、既存のテーブル内の各レコードがそれぞれ条件のパターンになる(複数の条件を指定できる)からです。

例えば、ログから特定のパターンのレコードを抽出することを考えてみましょう。 ログには、ユーザーとそれに紐づくタグ、時刻が記録されているとします。 サンプルとなるスキーマとデータは以下を使うことにします。

table_create Users TABLE_HASH_KEY ShortText
table_create Tags TABLE_HASH_KEY ShortText

table_create Reports TABLE_NO_KEY
column_create Reports user COLUMN_SCALAR Users
column_create Reports tag COLUMN_SCALAR Tags
column_create Reports day COLUMN_SCALAR Time

table_create Logs TABLE_NO_KEY
column_create Logs user COLUMN_SCALAR Users
column_create Logs tag COLUMN_SCALAR Tags
column_create Logs time COLUMN_SCALAR Time

load --table Reports
[
{"user": "alice", "tag": "tag1", "day": "2017-04-18 00:00:00"},
{"user": "alice", "tag": "tag1", "day": "2017-04-19 00:00:00"},
{"user": "david", "tag": "tag2", "day": "2017-04-20 00:00:00"},
{"user": "david", "tag": "tag3", "day": "2017-04-21 00:00:00"}
]
  
load --table Logs
[
{"user": "alice", "tag": "tag1", "time": "2017-04-18 11:22:33"},
{"user": "alice", "tag": "tag1", "time": "2017-04-20 11:22:33"},
{"user": "bob",   "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag1", "time": "2017-04-19 11:22:33"},
{"user": "david", "tag": "tag2", "time": "2017-04-20 11:22:33"}
]

Logs がログを記録しているテーブルです。特定のログに tag がつけられています。 特定のユーザーとタグがつけられているある日のログのみを抽出したい、というのを実現しようとすると、クエリはどんどん複雑になっていきます。 けれども今回追加された in_records を使うと条件のパターンを既存のテーブルへとまとめることができるのでクエリーを1つにすることができます。

select Logs \
  --filter 'in_records(Reports, \
                       user, "==", "user", \
                       tag, "==", "tag", \
                       time_classify_day(time), "==", "day")'

上記の例では条件のパターンを Reports に保存された4つのレコードで表現しています。 サンプルでは Reports テーブルしか使っていませんが、ここに指定しているテーブルを替えるだけで、条件のパターンのバリエーションを簡単に切り替えることもできます。

さいごに

7.0.1からの詳細な変更点は7.0.2リリース 2017-04-29を確認してください。

それでは、Groongaでガンガン検索してください!