Rroongaで全文検索する際には、Groonga::Tableクラスのselectメソッドを使い、rubyの配列をselectするような感覚で条件に一致するレコードを検索できる。
Groonga["Hoges"].select do |hoge|
hoge.title =~ /hello/
end
コードの表面上はArray#selectと同じように見えるが、裏側の動作原理は全く異なる。
Array#selectは配列の要素を1つ1つ走査して、それぞれの要素に対してブロックを呼び出して条件を満たすか否かを評価し、条件をみたす要素のみをピックアップする。
一方で、rroongaの場合はGroonga::Table#selectに渡されるブロックは一度しか実行されず、このブロックの実行によってGroongaの全文検索索引を使った問合せを構築し、Groongaのデータを検索する。
↑の例だと hoge.title が Groonga::ColumnExpressionBuilder のインスタンスになっており、=~などの演算子が定義されていて、=~が呼び出されると内部でGroonga用の問合せ式を構築する、という具合である。
ExpressionBuilder で検索条件を作る
Groonga::Table#selectをブロック付きで呼び出す場合、ブロックのreturnする値はGroonga::ExpressionBuilderでなければならない。
ExpressionBuilderは、ExpressionBuilderのサブクラスに対して何らかの演算子を適用することで得ることができる。基本的には、先の例のhoge.titleのようにカラム値を表す ColumnExpressionBuilder を出発点として、値の一致・不一致であったり、大小比較などの演算子を適用して、最終的に評価したい条件に対応する ExpressionBuilder を組み上げていく。
ExpressionBuilderのインスタンスは、意味合いとしてはGroongaの検索に使われるgrn_expr(ぐるん式)に相当する。
RroongaでExpressionBuilderを組み立てる際のポイントとしては、Rubyの文法の制限上、左辺値に ExpressionBuilder が来るように気をつけなければいけない点である。
例えば、Hogesテーブルのtitleカラムの値が"hage"であるようなレコードを検索するときには
Groonga["Hoges"].select do |hoge|
hoge.title == "hage"
end
と書くことはできる一方で、
Groonga["Hoges"].select do |hoge|
"hage" == hoge.title
end
と書くことはできない。前者は ColumnExpressionBuilder に対して == 演算子を呼び出して、「カラム値が"hage"である」というExpressionBuilderを生成して返している。
一方後者は、"hage"というStringに対して==演算子を呼び出して、それがhoge.titleと等価であるかを比較し、Rubyの真偽値を返している。
同様に、hoge.numberという整数型のカラムがあったとして、「hoge.number の値の2倍が10である」という条件で検索しようとする場合には
Groonga["Hoges"].select do |hoge|
(hoge.number * 2) == 10
end
とは書けるが、以下のようには書けない。
# 2 * hoge.number で error
Groonga["Hoges"].select do |hoge|
(2 * hoge.number) == 10
end
# 10 == (...) で error
Groonga["Hoges"].select do |hoge|
10 == (hoge.number * 2)
end
ExpressionBuilderで使える演算子一覧
| 演算子 | 処理内容 |
|---|---|
| | | 論理和 |
| & | 論理積 |
| == | 等価比較 |
| != | 不等価比較 |
| % | 数値の除算の剰余 |
| * | 数値の積 |
| + | 数値の和 |
| - | 数値の差 |
| / | 数値の除算の商 |
| < | 大小比較(数値の大小、および文字列の辞書順(?)比較) |
| <= | 大小比較 |
| > | 大小比較 |
| >= | 大小比較 |
| =~ | 部分一致比較。右辺値が正規表現の場合には正規表現検索。 |
| match(query) | Groongaのクエリ式を使った検索条件指定 |
| prefix_search(prefix) | 前方一致検索 |
| suffix_search(suffix) | 後方一致検索 |
| similar_search(document) | 類似文書検索 |
| term_extract(document) | 単語抽出検索 |