recommendations: filter out own uploads and favorites.
Filter out the user's own uploads and favorites from their recommendations. Note that in most cases a user's top-N recommendations will be things they've already favorited. If a user has 10,000 favorites, most of their top 10,000 recommendations will be their own favorites, so we have to generate a little more than 10,000 recommendations to be sure they won't all be filtered out. In other words, the more favorites a user has, the more recommendations we have to generate. The upper bound is clamped to 50,000 for performance reasons. If a user has more favorites than this we may not be able to find any recommendations for them.
This commit is contained in:
@@ -2,17 +2,10 @@ class RecommendedPostsController < ApplicationController
|
|||||||
respond_to :html, :json, :xml, :js
|
respond_to :html, :json, :xml, :js
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000)
|
limit = params.fetch(:limit, 100).to_i.clamp(0, 200)
|
||||||
|
@recs = RecommenderService.search(params).take(limit)
|
||||||
if params[:user_id].present?
|
|
||||||
@recs = RecommenderService.recommend_for_user(params[:user_id], @max_recommendations)
|
|
||||||
elsif params[:post_id].present?
|
|
||||||
@recs = RecommenderService.recommend_for_post(params[:post_id], @max_recommendations)
|
|
||||||
else
|
|
||||||
@recs = []
|
|
||||||
end
|
|
||||||
|
|
||||||
@posts = @recs.map { |rec| rec[:post] }
|
@posts = @recs.map { |rec| rec[:post] }
|
||||||
|
|
||||||
respond_with(@recs)
|
respond_with(@recs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,20 +21,42 @@ module RecommenderService
|
|||||||
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/recommend/#{user_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/recommend/#{user_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
||||||
return [] if status != 200
|
return [] if status != 200
|
||||||
|
|
||||||
process_recs(body)
|
process_recs(body, uploader_id: user_id, favoriter_id: user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def recommend_for_post(post_id, limit = 50)
|
def recommend_for_post(post_id, limit = 50)
|
||||||
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/similar/#{post_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/similar/#{post_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
||||||
return [] if status != 200
|
return [] if status != 200
|
||||||
|
|
||||||
process_recs(body).reject { |rec| rec[:post].id == post_id }
|
process_recs(body, post_id: post_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_recs(recs)
|
def process_recs(recs, post_id: nil, uploader_id: nil, favoriter_id: nil)
|
||||||
recs = JSON.parse(recs).to_h
|
recs = JSON.parse(recs)
|
||||||
recs = Post.where(id: recs.keys).map { |post| { score: recs[post.id], post: post } }
|
|
||||||
|
posts = Post.where(id: recs.map(&:first))
|
||||||
|
posts = posts.where.not(id: post_id) if post_id
|
||||||
|
posts = posts.where.not(uploader_id: uploader_id) if uploader_id
|
||||||
|
posts = posts.where.not(id: Favorite.where(user_id: favoriter_id).select(:post_id)) if favoriter_id
|
||||||
|
|
||||||
|
id_to_score = recs.to_h
|
||||||
|
recs = posts.map { |post| { score: id_to_score[post.id], post: post } }
|
||||||
recs = recs.sort_by { |rec| -rec[:score] }
|
recs = recs.sort_by { |rec| -rec[:score] }
|
||||||
recs
|
recs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search(params)
|
||||||
|
if params[:user_id].present?
|
||||||
|
user = User.find(params[:user_id])
|
||||||
|
max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50000)
|
||||||
|
recs = RecommenderService.recommend_for_user(params[:user_id], max_recommendations)
|
||||||
|
elsif params[:post_id].present?
|
||||||
|
max_recommendations = params.fetch(:max_recommendations, 50).to_i.clamp(0, 200)
|
||||||
|
recs = RecommenderService.recommend_for_post(params[:post_id], max_recommendations)
|
||||||
|
else
|
||||||
|
recs = []
|
||||||
|
end
|
||||||
|
|
||||||
|
recs
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user