三日で作る Groonga 関数
hotpepsi@twitter
Agenda
 filter で呼べる関数を自作する
 ただし三日くらいで
背景
 しょぼいサーバでスループットを上げ
たい
 更新中も検索を止めたくない
 検索されるものは全部 Groonga につっ
こむ
処理したい内容
 親子関係を持つテーブルがある
 親と子の個数の比は 1:n
 ある条件で子テーブルを検索し、合致
する親テーブルを取得したい
 具体的には : 商品 (1) : 在庫・価格 (n)
SQL の場合
 子テーブルに親テーブルを JOIN
 検索結果を親のキーで DISTINCT
 Groonga の場合、素直にはできない
 ※ ドリルダウンすれば 2 度引きで可能
Groonga の場合
 子テーブルで検索する
 重複するキーを filter で捨てる
 filter で使える関数を自作する必要があ
る
自作する関数の仕様
 引数として親のキー( _key )をとる
 格納済かどうかを返す
 Int32 distinct(ShortText parent_key)
雛形
 test/unit/fix/fixtures/modules/string.c に
ある str_len を参考にする
 自作の関数を登録する :grn_proc_create
 grn_proc_create(ctx, "str_len",
strlen("str_len"), GRN_PROC_FUNCTION,
func_str_len, NULL, NULL, 0, NULL);
とりあえず版 登録 proc.c
...
grn_proc_create(ctx, "distinct", 8, GRN_PROC_FUNCTION,
func_distinct, NULL, NULL, 0, NULL);
...
とりあえず版 関数 proc.c
static grn_obj *func_distinct(grn_ctx *ctx, int nargs, grn_obj
**args, grn_user_data *user_data) {
int result = 0;
grn_obj *obj;
if (nargs == 1) {
grn_obj *item_key = args[0];
result = _distinct(GRN_TEXT_VALUE(item_key),
GRN_TEXT_LEN(item_key));
if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
GRN_UINT32_SET(ctx, obj, result);
}
}
return obj;
}
とりあえず版 中身 distinct.cc
#include <string>
#include <set>
typedef std::set<std::string> Map;
static Map _map; // 格納済キーの保存庫
extern "C" int _distinct(const char *name, size_t length) {
std::string _key(name, length); // std::string に変換
Map::iterator it = _map.find(_key); // キーを探す
if (it != _map.end()) return 0; // 格納済なら 0 を返す
_map.insert(key); // 格納する
return 1;
}
適当にビルドしてみる
 lib/ に distinct.cc を追加して make
 よくわからないエラー
 ../lib/.libs/libgroonga.so: undefined
reference to `__cxa_begin_catch‘
 g++ 経由でリンクしないと駄目
正式なやり方
 configure.ac に AC_PROG_CXX を追加
 lib/Makefile.am の
libgroonga_la_SOURCES に distinct.cc
を追加
 autoreconf で configure を再生成
autoreconf への道
 色々更新が必要
 autoconf-2.67
 automake-1.11.1
 libtool-2.2.6b
 激しく遠い道のりなので以下略
手抜き
 Makefile.in に追記
 .SUFFIXES に .cc を追加
 CCLD を gcc から g++ に変更
 ビルドルールに .cc.o を追加
デモ
 商品テーブル item
 ShortText 型 description
 3 件
 在庫テーブル stock
 item 型 i
 Time 型 date
 Int32 型 price
 9 件
distinct なし
 select --table stock --output_columns
i._key,price
 → i._key が重複する
distinct あり
 select --table stock --filter
"distinct(i._key)" --output_columns
i._key,price
 → i._key が重複しない
end of file

三日で書くGroonga関数