namespace :post_similarity do desc '関聯投稿テーブル作成' task calc: :environment do dot = -> a, b { (a.keys & b.keys).sum { |k| a[k] * b[k] } } norm = -> v { Math.sqrt(v.values.sum { |e| e * e }) } cos = -> a, b do na = norm.(a) nb = norm.(b) if na.zero? || nb.zero? 0.0 else dot.(a, b) / na / nb end end posts = Post.includes(:tags).to_a posts.each_with_index do |post, i| existence_of_tags = post.tags.index_with(1) ((i + 1)...posts.size).each do |j| target_post = posts[j] existence_of_target_tags = target_post.tags.index_with(1) PostSimilarity.find_or_initialize_by(post:, target_post:).tap { |ps| ps.cos = cos.(existence_of_tags, existence_of_target_tags) }.save! end end end end