HAYASHI Kentaro
hayas****@clear*****
2013年 3月 29日 (金) 10:52:30 JST
林です。 今日は肉の日ですね。 まずはじめに、利用事例の記事を書いてくれる人募集のお知らせです。 これまでも、groonga.orgにて利用事例 http://groonga.org/ja/users/ を 紹介してきましたが、それとは別に、 http://gihyo.jp/ にgroonga関連の記事を書く という取り組みをはじめようかと検討しています。 まだgroongaを知らない人にもWebの連載記事を通じて知ってもらいたいというのが動機です。 (似たような動機で、毎週木曜にQiitaでのgroonga関連の情報提供もはじめました!) http://qiita.com/users/groonga 詳細は「groonga普及のための協力のお願い」を参照していただきたいと思いますが、 実際に使っているユーザーのみなさんに利用事例を書いてもらえたらいいなぁと思っています! http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-February/001186.html すでに何名かの方から応募いただいていますが、まだまだ募集中です!! groonga 3.0.2をリリースしました! http://groonga.org/ja/docs/news.html#release-3-0-2 それぞれの環境毎のインストール方法はこちらを見てください。 http://groonga.org/ja/docs/install.html 今回のリリースではデータベースのファイル形式は互換性があるのでデータベースを作りなおす必要はありません。 今回のリリースの主なトピックは2つあります。 * sub_filter() 関数のサポート * query() 関数でクエリ展開のサポート ○ sub_filter() 関数のサポート 今回のリリースではsub_filter()関数のサポートを追加しました。 どういった場合にこの関数を使うと便利なのかを具体例で紹介します。 お題は「ブログエントリの特定のコメントを抽出する」です。 この例で使用するスキーマ定義は以下の通りです。 table_create Comment TABLE_PAT_KEY UInt32 column_create Comment name COLUMN_SCALAR ShortText column_create Comment content COLUMN_SCALAR ShortText table_create Blog TABLE_PAT_KEY ShortText column_create Blog title COLUMN_SCALAR ShortText column_create Blog content COLUMN_SCALAR ShortText column_create Blog comments COLUMN_VECTOR Comment column_create Comment blog_comment_index COLUMN_INDEX Blog comments table_create Lexicon TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram column_create Lexicon comment_content COLUMN_INDEX|WITH_POSITION Comment content column_create Lexicon comment_name COLUMN_INDEX|WITH_POSITION Comment name column_create Lexicon blog_content COLUMN_INDEX|WITH_POSITION Blog content BlogテーブルにはCommentテーブルを関連づけています。 また、全文検索用のLexiconテーブルを用意しています。 例で使用するサンプルデータは以下の通りです。 load --table Comment [ {"_key": 1, "name": "A", "content": "groonga"}, {"_key": 2, "name": "B", "content": "groonga"}, {"_key": 3, "name": "C", "content": "rroonga"}, {"_key": 4, "name": "A", "content": "mroonga"}, ] load --table Blog [ {"_key": "groonga's blog", "content": "content of groonga's blog", comments: [1, 2, 3]}, {"_key": "mroonga's blog", "content": "content of mroonga's blog", comments: [2, 3, 4]}, {"_key": "rroonga's blog", "content": "content of rroonga's blog", comments: [3]}, ] 例えば、Aさんがgroongaについてコメントしたブログエントリのタイトルを抽出したいとしましょう。 Aさんのコメントは以下のようにして抽出することができます。 select Comment --output_columns _key,name,content --query "name:@\"A\"" [ [2], [ ["_key","UInt32"],["name","ShortText"],["content","ShortText"] ], [1,"A","groonga"], [4,"A","mroonga"] ] Aさんはgroongaとmroongaについてコメントしていることがわかります。 では、AさんがgroongaについてコメントしているエントリをBlogテーブルから探してみましょう。 まずは、AさんがコメントしているエントリをBlogテーブルから探してみます。 select Blog --output_columns _key --filter "comments.name @ \"A\"" [ [ [2], [["_key","ShortText"]], ["groonga's blog"], ["mroonga's blog"] ] ] "groonga's blog"と"mroonga's blog"に対してコメントしていることがわかりました。 では、AさんがgroongaについてコメントしているエントリをBlogテーブルから探してみましょう。 コメント本文に対する条件を追加して検索してみます。 select Blog --output_columns _key --filter "comments.name @ \"A\" && comments.content @ \"groonga\"" [ [ [2], [["_key","ShortText"]], ["groonga's blog"], ["mroonga's blog"] ] ] 条件を追加しているのに、結果は同じになりました。 "mroonga's blog"にはAさんがコメントしてはいますが、"groonga"ではなく"mroonga"についてです。 これは意図した結果ではありません。 いったいどういうことなのでしょうか。 実は、--filter "comment.name @ \"A\" && comment.content @ \"groonga\"" という条件を処理するときに、groongaでは以下のようにして判定しています。 1) comment.name @ \"A\"なものがあるか? => CommentテーブルにAさんのコメントがあるのでマッチ 2) comment.content @ \"groonga\"なものがあるか? => Commentテーブルに"groonga"があるのでマッチ 1)と2)ではそれぞれどれかひとつでもマッチしているかどうか、を見ています。 その結果をふまえて1)と2)両方をみたしているかで判定しているので、 Blogの"mroonga's blog"エントリが抽出されています。 やりたいのは Aさんがgroongaについてコメントしたエントリを抽出することでした。 これは、"groonga's blog"だけが抽出されるというのが期待する結果です。 具体的に言うとCommentテーブルの以下のコメントデータを含むBlogテーブルのエントリを 抽出したいわけです。 {"_key": 1, "name": "A", "content": "groonga"}, この場合にCommentテーブルのnameカラムとcontentカラムにおいて どれかひとつでもマッチしているものがあるかどうかで評価されるのは 都合が良くありません。 こういうときに使えるのが、sub_filter()関数です。 commentsのコンテキストで絞り込むことができます。 sub_filterを使うと上記目的に合致するクエリを以下のように書くことができます。 select Blog --output_columns _key \ --filter 'sub_filter(comments, "name @ \\"A\\" && content @ \\"groonga\\"")' 実行結果は以下のようになります。 [ [ [1], [["_key","ShortText"]], ["groonga's blog"], ] ] これで、意図した通り、Aさんがgroongaについてコメントしているエントリのみを 抽出することができました。 ○ query() 関数でクエリ展開のサポート 今回のリリースでは、query()関数でのクエリ展開をサポートしました。 selectコマンドの--queryではクエリ展開と重みづけの指定ができます。 2.1.2のリリースでは複数のquery()関数をselectコマンドでサポートしたことで、 複数のクエリごとに異なる重みづけを指定することができるようになりました。 ただし、query()関数ではクエリ展開できなかったので、アプリケーション側で クエリ展開相当のことをやってからquery()関数に渡さないことには --queryと同じようには複数の全文検索を行うことができませんでした。 今回のリリースでは、query()関数でのクエリ展開をサポートしたことで、 --queryでできていたクエリ展開と重みづけを複数の全文検索でも利用できるようになりました。 今まではquery関数の構文は以下のようにカラムとクエリを受けつけるものでした。 query("MATCH_COLUMNS", "QUERY") 今回クエリ展開をサポートするために引数を追加し、 QueryExpanderTSVと一緒に使えるようになりました。(置換テーブルを指定することもできます。) query("MATCH_COLUMNS", "QUERY", "QueryExpanderTSV") QueryExpanderTSVによるクエリ展開については以下のドキュメントを参照してください。 http://groonga.org/ja/docs/reference/query_expanders/tsv.html 置換テーブルの例については以下のドキュメントを参照してください。 http://groonga.org/ja/docs/reference/commands/select.html#query-expansion これにより、クエリ展開と重みづけを同時に指定したいものは--queryに書かないといけない という制限が緩和されます。 例えば、以下のように置換テーブルと同等のことを書かないといけなかったクエリは select Users --match_columns "memo * 100" --query "memo:@groonga" \ --query_expander Synonyms.synonym \ --filter 'query("name * 10", "((...) OR (...) OR (...))")' こんな風に自前で展開せずにすむようになります。 select Users --match_columns "memo * 100" --query "memo:@groonga" \ --query_expander Synonyms.synonym \ --filter 'query("name * 10", "...", "Synonyms.synonym")' ○ 変更点 さて、3.0.1からの変更点は以下の通りです。 http://groonga.org/ja/docs/news.html#release-3-0-2 3.0.2リリース - 2013/03/29 -------------------------- 改良 * 2つ以上のインデックスをテーブルのキーに対して張れるようにしました。 この変更はインデックスを張ったキーへ新たなキーをロードしたときにクラッシュしないようにします。 * X + Y, X - Y, X * Y, X / Y, X % Y, X >> Y, X << Y, X | Y, X ^ Y, X & Y や X >>> Y といった演算子をサポートしました。 * load コマンドのドキュメントを追加。 * X += Y, X -= Y, X *= Y, X /= Y, X %= Y, X <<= Y, X >>= Y, X >>>= Y, X &= Y, X |= Y や X ^= Y といった演算子をサポートしました。 * -X といった演算子をサポートしました。 * --output_columns で複雑な文字列の連結をサポートしました。 例えば --output_columns '"<" + title + ">"' といったクエリを書けるようになりました。 * 開発ページにgroongaリポジトリの情報を追加しました。 * sub_filter() 関数を追加しました。 * query() 関数でクエリ展開をサポートしました。 この変更で query("MATCH_COLUMNS", "QUERY","QueryExpanderTSV") といったクエリが書けるようになりました。 * --query_expansion を --query_expander に変更しました。 --query_expansion は引き続き使えますが、非推奨となります。 修正 * snippet_html(XXX), XXX を実行すると "stack error"になる不具合を修正しました。 この不具合は --output_columns 'snippet_html(title), content' といったクエリに影響します。 [Groonga-talk (no subject)] [Hendro Wibowoさんが報告] インストールのドキュメントの誤字を修正。 [hinoさんが報告] * Travi-CIセットアップ用のスクリプトが動作しない不具合を修正した。 [groonga-dev,01248] [ongaeshiさんが報告] * メモリリークを修正した。この不具合は次の3つの条件が重なったときに発生します。 参照カラムかつそのカラムがベクター型であって、キーのサイズが25バイト以上のとき。 * --output_columns _score.GARBAGE というクエリによってクラッシュする不具合を修正した。 この不具合はGARBAGEが存在しないときに影響します。 感謝 * Hendro Wibowoさん * hinoさん * ongaeshiさん -- HAYASHI Kentaro <hayas****@clear*****>