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
