Kouhei Sutou
kou****@clear*****
2011年 3月 30日 (水) 22:52:23 JST
須藤です。 In <4d279c40-2773-3091-9817-697a927982b3 @ api104> "[groonga-dev,00470] referenceでの検索" on Wed, 30 Mar 2011 08:52:30 +0900, "Endo Akira" <endo4****@goo*****> wrote: > p items.select{|r| > res = false > r.pisrefs.each{|p| ####### > res |= p.jan =~ '123' > } > res > } > > 以上、itemsテーブルにpisテーブルへのreferenceをvectorでいれた > つもりですが、#######のところで、 > undefined method 'each' for #<Groonga::ExpressionBuildable::ColumnValueExpressionBuilder:0x000000029e8868 > というエラーが出ます。selectの中では、挙動が変わるようで、ここから進めません。 なるほど。 selectの中(ブロック)はたしかに他のRubyの部分とは意味合いが 異なるのです。 解説の前に、これが期待する動作かなぁというコードを示しておき ます。 result = items.select{|r| r.pisrefs.jan =~ "123" } result.each do |record| p record.key.pisrefs.collect(&:jan) end 以下、解説です。 selectのブロックは「grn式(ぐるんしき)」というgroongaの式オブジェ クトを生成するもので、 各レコード毎にブロックを評価してマッチするレコードを特定する ということはしていません。 例えば、Arrayのselectでは > [1, 2, 3].select {|n| p n; n.odd?} 1 2 3 => [1, 3] となり、各要素に対してブロックを評価して目的の要素だけを返し ます。 しかし、テーブルのselectでは、 > items.select {|record| p record; record.content =~ "キーワード"} <Groonga::RecordExpressionBuilder:...> => #<Groonga::Hash ...> # ← 「キーワード」にマッチする # レコードがたくさんあるとする。 というようにブロックは常に1度しか評価されません。 これは、Rubyからgroongaを使ってもできるだけgroongaの速度を落 とさないようにするためです。すべてのレコードに対してRubyのブ ロックを評価していてはせっかくのgroongaの速度が殺されてしまう のです。Rubyのブロックを1度だけ評価して、groongaの式オブジェ クト(grn式)にし、後はgroongaが内部で検索を実行することによ り、groongaの速度とRubyの使いやすさを両立するようにしています。 で、問題はどうやってのぞみのgrn式を作るかですが、うーん、そ うですねぇ。すぐには説明できないです。。。すみません。。。 ざっくりというと、こんな感じなのですが。。。 * 条件式(真偽値を返す(Rubyの)式)を書く 例: record.name == "太郎" record.name =~ "キーワード" * eachを使わない(eachは使えない) 例: record.names.each do |name| name ... end * 条件式を連結する 例: # 東京に住んでいる太郎さんを検索 (record.name == "太郎") & (record.address =~ "東京") # 東京か大阪に住んでい人を検索 (record.address =~ "東京") | (record.address =~ "大阪") 残念ですがまとめられないので、わからないことはここで聞いても らえるといいかと思います! -- 須藤 功平 <kou****@clear*****> 株式会社クリアコード <http://www.clear-code.com/> (03-6231-7270) プログラミングが好きなソフトウェア開発者を募集中: http://www.clear-code.com/recruitment/