[groonga-dev,01023] Re: インデックスカラムを参照する方法を教えてください

Back to archive index

Kouhei Sutou kou****@clear*****
2012年 8月 24日 (金) 17:31:04 JST


須藤です。

In <CAP4YgqMMqUiijkyHdgwky_mzBjMhgg5AQ6zF4=Qu3jd****@mail*****>
  "[groonga-dev,01022] インデックスカラムを参照する方法を教えてください" on Fri, 24 Aug 2012 12:37:22 +0900,
  okk okk <mikke****@gmail*****> wrote:

> rroonga で保存された "Yes good" の文章からTokenMecabでトークナイズされた
> 単語 "Yes" と "good" を取得するところで悩んでいます。
> 文章は切り分けられ語彙表(lexicon)にちゃんと入っています。
> 
> 「groongaにデータを登録してからインデックスが更新されるまでの流れ」
> http://www.clear-code.com/blog/2011/10/5.html
> ”groongaのインデックスカラムでは、…”
> を参考にindex column が参照できれば、切り分けられた単語を取得できると考えたのですが、
> インデックスカラムの参照方法がわかりませんでした。
> 
> インデックスカラムを参照する方法はありますでしょうか。

単語に対応する元文書を参照したいということでしょうか?
それとも、切り分けられた単語を参照したいということでしょ
うか?(後者な雰囲気を感じますが。。。)

まずは、前者から説明します。単語に対応する元文書を参照し
たい場合は以下のようにTable#selectを使うのが便利です。

  require "fileutils"
  require "groonga"

  FileUtils.rm_rf("/tmp/db")
  FileUtils.mkdir_p("/tmp/db")

  Groonga::Database.create(:path => "/tmp/db/db")

  Groonga::Schema.define do |schema|
    schema.create_table("Comments") do |table|
      table.short_text("content")
    end

    schema.create_table("Terms",
                        :type => :patricia_trie,
                        :key_type => :short_text,
                        :key_normalize => true,
                        :default_tokenizer => :token_mecab) do |table|
      table.index("Comments", "content")
    end
  end

  comments = Groonga["Comments"]
  comments.add(:content => "Yes good")

  Groonga::Context.default.match_escalation_threshold = -1
  word = "Yes"
  result_set = comments.select do |record|
    record.content =~ word
  end
  p result_set.collect(&:attributes)
  # -> [{"_id"=>1, "_key"=>{"_id"=>1, "content"=>"Yes good"}, "_score"=>1, "_nsubrecs"=>1}]

ポイントはGroonga::Context#match_escalation_threshold=で-1を
指定して完全一致しかさせないようにしているところです。これを
しないと切り分けた単語以外でもヒットしてしまいます。
↑の例だと「Ye」でもヒットしてしまいます。

match_escalation_thresholdについては以下のドキュメントが参考
になると思います。

  http://groonga.org/ja/docs/reference/commands/select.html#match-escalation-threshold
  http://groonga.org/ja/docs/spec/search.html


次に後者の説明です。切り分けられた単語を参照したい場合は
語彙表をeachして語彙表の各レコードのkeyを参照してください。

  require "fileutils"
  require "groonga"

  FileUtils.rm_rf("/tmp/db")
  FileUtils.mkdir_p("/tmp/db")

  Groonga::Database.create(:path => "/tmp/db/db")

  Groonga::Schema.define do |schema|
    schema.create_table("Comments") do |table|
      table.short_text("content")
    end

    schema.create_table("Terms",
                        :type => :patricia_trie,
                        :key_type => :short_text,
                        :default_tokenizer => :token_mecab) do |table|
      table.index("Comments", "content")
    end
  end

  comments = Groonga["Comments"]
  comments.add(:content => "Yes good")
  comments.add(:content => "No good")

  terms = Groonga["Terms"]
  terms.each do |term|
    p term.key
    # -> "N"
    # -> "Yes"
    # -> "good"
    # -> "o"
  end

↑の例では「N」、「Yes」、「good」、「o」が切りだされた単語で
す。

語彙表のレコードのkeyを参照するのは、そこに単語が入って
いるからです。
  http://www.clear-code.com/blog/2011/10/5.htmlhttp://www.clear-code.com/blog/images/20111005_9.png
でもlexiconのkeyに"Hey"や"Hi"などが入っていますよね。

> 試行結果
> irb(main):004:0> terms = Groonga["Terms"]
> => #<Groonga::PatriciaTrie id: <276>, name: <Terms>, path:
> </tmp/tmpdb/test3.db.0000114>, domain: <ShortText>, range: (nil), flags:
> <KEY_NORMALIZE|WITH_SECTION>, encoding: <:utf8>, size: <79417>>
> irb(main):005:0> terms.columns[0]
> => #<Groonga::IndexColumn id: <277>, name: <Terms.Comments_comment>, path:
> </tmp/tmpdb/test3.db.0000115>, domain: <Terms>, range: <Comments>, flags:
> <>>
> irb(main):011:0> terms.columns[0][1]
> => 111
> 
> 転置インデックスのArrayが返ってくることを期待していましたが数値が返ってきました。
> 111 のID?の意味もよく理解していません。

実は、この111はIDではなく、指定した単語IDに関連付いてい
る文書数はいくつくらいあるかの概算値なのです。もう少し詳しく
説明します。

> irb(main):011:0> terms.columns[0][1]

の

  terms.columns

はTermsテーブル内の全カラムを配列で返します。

  terms.columns[0]

は最初のカラムという意味です。

  terms.columns[0][1]

は最初のカラムの単語IDが1の単語に関連付けられれている文書数が
いくつくらいあるかの概算値という意味です。

例としてこの状態を考えます。

  comments = Groonga["Comments"]
  comments.add(:content => "Yes good")

  terms = Groonga["Terms"]
  terms = Groonga["Terms"]
  terms.each do |record|
    p [record.id, record.key]
    # -> [1, "Yes"]
    # -> [2, "good"]
  end

このとき、単語IDが1の単語は"Yes"で単語IDが2の単語は"good"で
す。よって、以下のような意味になります。

  index = terms.column("Comments_content")
  p index[1] # <- "Yes"("Yes"の単語IDは1)に関連付けられれている文書数の概算値
  p index[2] # <- "Yes"("good"の単語IDは2)に関連付けられれている文書数の概算値

という感じなのですが、そもそも、質問をうまく受け取れていない
気もするので、お役に立てていない感があります。。。

-- 
須藤 功平 <kou****@clear*****>
株式会社クリアコード <http://www.clear-code.com/> (03-6231-7270)

groongaサポート:
  http://groonga.org/ja/support/
パッチ採用はじめました:
  http://www.clear-code.com/recruitment/




groonga-dev メーリングリストの案内
Back to archive index