Groongaを使うとドリルダウン検索は簡単です

全文検索エンジンGroonga Advent Calendar 2013の18日目の記事です。

Groongaを囲む夕べ4で発表したスライドにて、Milkodeにおけるドリルダウンの使い方を紹介してなかなか評判が良かったので記事にしてみます。

ドリルダウンって?

データ集計や分析で用いる手法の一つで、集計範囲を一段階絞ってより詳細な集計を行うこと。

例えば内部でMilkodeを利用しているmruby Code Searchで検索すると、マッチしたレコードの中からパッケージ名や拡張子名、ディレクトリ名でさらに絞り込むことが出来ます。これがドリルダウンです。

drilldown-example

Amazonや価格.comといったサイトでもよく使われていますね。

Groongaでドリルダウンを使うには?

GroongaのRubyバインディングであるRroongaで説明しますがGroongaでも基本は同じです。

下はRroongaのテーブルを検索して、その結果を"suffix"カラムでドリルダウンする例です。

# Rroongaのテーブルを検索
result = table.select {|record| ... }

# 結果に対してgroupメソッドを呼ぶ
drilled = result.group("suffix")   # "suffix"カラムにドリルダウン!!

# 先頭を取得
r = drilled.first

# マッチ数とキーを取得
p [r.n_sub_records, r.key] #=> [356, "md"]

groupメソッドがドリルダウンの本体です。[356, "md"]は拡張子"md"のレコードが356個あることを示しています。

Milkodeでの書き方

MilkodeではUtil::drilldownというメソッドになりました。実際はワンライナーですが分解すると以下のようになります。

# ドリルダウン結果を配列で返す(マッチ数、降順)
# column .. カラム名
# num .. 取得したい結果の数
def self.drilldown(result, column, num = nil)
  drilled = result.group(column).map {|record|
    [record.n_sub_records, record.key]
  }.sort_by {|a|
    a[0]
  }.reverse
  num ? drilled[0, num] : drilled
end

整理するとやっていることは

  1. 検索結果をドリルダウン
  2. n_sub_records(マッチ数), key(拡張子など) の配列を作る
  3. マッチ数でソート
  4. 降順に並べる
  5. 必要な数だけ抜き出す

です。

引っかかったこと

Milkodeの場合ですが、

  • 拡張子(suffix)カラムがtextカラムだったためドリルダウン対象に出来なかった。
  • ドリルダウンしたかったのでやむなく1.4でstringカラムに変更
  • データベースの再生成(milk rebuild --all)が必要になってしまった。

将来的にドリルダウンしたいものはカラム種類に気を付けましょう。

まとめ

大切なことはこれだけです。

  • Rroonga(Groonga)でドリルダウンしたい時はselectで検索した後にgroupを呼ぶ
  • ドリルダウン結果に対してn_sub_recordsでマッチ数、keyでドリルダウンしたカラムの値を取得
  • ドリルダウンしたい要素のカラム種類には気をつける

参考文献