Class: VivlioStarter::CLI::IndexCommands::ScoringEngine

Inherits:
Object
  • Object
show all
Defined in:
lib/vivlio_starter/cli/index/scoring_engine.rb

Overview

スコアリングエンジン

Constant Summary collapse

TRAIT_WEIGHTS =

語が持つ性質のボーナス。語ごとに 1 回だけ効く(出現数では増えない)。

{
  definition: 30.0,    # 「〜とは」など定義パターンに現れた
  technical: 15.0,     # カタカナ語・英字語などの専門用語らしさ
  noun_sequence: 10.0, # MeCab が拾った名詞連続
  heading: 20.0        # 見出しに現れた(現時点では未使用・主要参照仕様で使う)
}.freeze
TFIDF_SCALE =

TF-IDF のスケール係数。閾値との突き合わせではなく順位付けに使うので、 値そのものに意味はない(単調変換は順位を変えない)。

30.0

Instance Method Summary collapse

Constructor Details

#initializeScoringEngine

default_proc は使わない——読むだけでキーが生まれ、スコアを問い合わせた だけの語が terms に混ざる。登録は mark / observe でしか起きない形にする。



50
51
52
53
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 50

def initialize
  @traits = {}
  @tfidf = {}
end

Instance Method Details

#breakdown(term) ⇒ Hash?

デバッグ用: スコアの内訳

Returns:

  • (Hash, nil)

    記録の無い語なら nil



92
93
94
95
96
97
98
99
100
101
102
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 92

def breakdown(term)
  return nil unless terms.include?(term)

  {
    term:,
    total: score(term).round(2),
    tfidf: @tfidf.fetch(term, 0.0).round(2),
    traits: @traits.fetch(term, []).to_a.sort,
    trait_bonus: trait_bonus(term).round(2)
  }
end

#mark(term, trait) ⇒ Object

語に性質を記録する。同じ性質を何度記録しても 1 回ぶんにしかならない。

Parameters:

  • term (String)

    用語

  • trait (Symbol)

    TRAIT_WEIGHTS のキー



58
59
60
61
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 58

def mark(term, trait)
  Common.log_debug("未知の性質を無視します: #{trait}") unless TRAIT_WEIGHTS.key?(trait)
  (@traits[term] ||= Set[]) << trait if TRAIT_WEIGHTS.key?(trait)
end

#observe(term, tf:, df:, doc_count:) ⇒ Object

出現統計から TF-IDF を与える(語につき 1 回呼ぶ)。

Parameters:

  • term (String)

    用語

  • tf (Integer)

    全文書での延べ出現数

  • df (Integer)

    その語が現れた文書数

  • doc_count (Integer)

    総文書数



68
69
70
71
72
73
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 68

def observe(term, tf:, df:, doc_count:)
  return if tf.to_i.zero?

  idf = Math.log((doc_count + 1.0) / (df + 1.0)) + 1.0
  @tfidf[term] = (1 + Math.log(tf)) * idf * TFIDF_SCALE
end

#reset!Object

スコアをリセット



85
86
87
88
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 85

def reset!
  @traits.clear
  @tfidf.clear
end

#score(term) ⇒ Object

1 語のスコア



79
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 79

def score(term) = @tfidf.fetch(term, 0.0) + trait_bonus(term)

#scoresObject

用語 → スコアのハッシュ



82
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 82

def scores = terms.to_h { [it, score(it)] }

#termsObject

記録済みの全用語



76
# File 'lib/vivlio_starter/cli/index/scoring_engine.rb', line 76

def terms = (@traits.keys + @tfidf.keys).uniq