posts: move fast_count to PostQueryBuilder.
This commit is contained in:
@@ -2,11 +2,6 @@ class CountsController < ApplicationController
|
||||
respond_to :xml, :json
|
||||
|
||||
def posts
|
||||
@count = Post.fast_count(
|
||||
params[:tags],
|
||||
timeout: CurrentUser.statement_timeout,
|
||||
raise_on_timeout: true,
|
||||
skip_cache: params[:skip_cache]
|
||||
)
|
||||
@count = PostQueryBuilder.new(params[:tags]).fast_count(timeout: CurrentUser.statement_timeout, raise_on_timeout: true, skip_cache: params[:skip_cache])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -810,6 +810,89 @@ class PostQueryBuilder
|
||||
end
|
||||
end
|
||||
|
||||
concerning :CountMethods do
|
||||
def fast_count(timeout: 1_000, raise_on_timeout: false, skip_cache: false)
|
||||
tags = normalize_query(normalize_aliases: true)
|
||||
tags += " rating:s" if CurrentUser.safe_mode?
|
||||
tags += " -status:deleted" if CurrentUser.hide_deleted_posts? && !has_metatag?("status")
|
||||
tags = tags.strip
|
||||
|
||||
# Optimize some cases. these are just estimates but at these
|
||||
# quantities being off by a few hundred doesn't matter much
|
||||
if Danbooru.config.estimate_post_counts
|
||||
if tags == ""
|
||||
return (Post.maximum(:id).to_i * (2200402.0 / 2232212)).floor
|
||||
|
||||
elsif tags =~ /^rating:s(?:afe)?$/
|
||||
return (Post.maximum(:id).to_i * (1648652.0 / 2200402)).floor
|
||||
|
||||
elsif tags =~ /^rating:q(?:uestionable)?$/
|
||||
return (Post.maximum(:id).to_i * (350101.0 / 2200402)).floor
|
||||
|
||||
elsif tags =~ /^rating:e(?:xplicit)?$/
|
||||
return (Post.maximum(:id).to_i * (201650.0 / 2200402)).floor
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
count = nil
|
||||
|
||||
unless skip_cache
|
||||
count = get_count_from_cache(tags)
|
||||
end
|
||||
|
||||
if count.nil?
|
||||
count = fast_count_search(tags, timeout: timeout, raise_on_timeout: raise_on_timeout)
|
||||
end
|
||||
|
||||
count
|
||||
rescue Post::SearchError
|
||||
0
|
||||
end
|
||||
|
||||
def fast_count_search(tags, timeout:, raise_on_timeout:)
|
||||
count = Post.with_timeout(timeout, nil, tags: tags) do
|
||||
Post.tag_match(tags).count
|
||||
end
|
||||
|
||||
if count.nil?
|
||||
# give up
|
||||
if raise_on_timeout
|
||||
raise TimeoutError.new("timed out")
|
||||
end
|
||||
|
||||
count = Danbooru.config.blank_tag_search_fast_count
|
||||
else
|
||||
set_count_in_cache(tags, count)
|
||||
end
|
||||
|
||||
count ? count.to_i : nil
|
||||
rescue PG::ConnectionBad
|
||||
return nil
|
||||
end
|
||||
|
||||
def get_count_from_cache(tags)
|
||||
if PostQueryBuilder.new(tags).is_simple_tag?
|
||||
count = Tag.find_by(name: tags).try(:post_count)
|
||||
else
|
||||
# this will only have a value for multi-tag searches or single metatag searches
|
||||
count = Cache.get(count_cache_key(tags))
|
||||
end
|
||||
|
||||
count.try(:to_i)
|
||||
end
|
||||
|
||||
def set_count_in_cache(tags, count, expiry = nil)
|
||||
expiry ||= count.seconds.clamp(3.minutes, 20.hours).to_i
|
||||
|
||||
Cache.put(count_cache_key(tags), count, expiry)
|
||||
end
|
||||
|
||||
def count_cache_key(tags)
|
||||
"pfc:#{Cache.hash(tags)}"
|
||||
end
|
||||
end
|
||||
|
||||
concerning :UtilityMethods do
|
||||
def terms
|
||||
scan_query
|
||||
|
||||
@@ -86,7 +86,7 @@ module PostSets
|
||||
# no need to get counts for formats that don't use a paginator
|
||||
return Danbooru.config.blank_tag_search_fast_count
|
||||
else
|
||||
::Post.fast_count(tag_string)
|
||||
query.fast_count
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module RelatedTagCalculator
|
||||
def self.similar_tags_for_search(tag_query, search_sample_size: 1000, tag_sample_size: 250, category: nil)
|
||||
search_count = Post.fast_count(tag_query)
|
||||
search_count = PostQueryBuilder.new(tag_query).fast_count
|
||||
return [] if search_count.nil?
|
||||
|
||||
search_sample_size = [search_count, search_sample_size].min
|
||||
|
||||
@@ -588,6 +588,14 @@ class Post < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def fix_post_counts(post)
|
||||
post.set_tag_counts(false)
|
||||
if post.changes_saved?
|
||||
args = Hash[TagCategory.categories.map {|x| ["tag_count_#{x}", post.send("tag_count_#{x}")]}].update(:tag_count => post.tag_count)
|
||||
post.update_columns(args)
|
||||
end
|
||||
end
|
||||
|
||||
def merge_old_changes
|
||||
reset_tag_array_cache
|
||||
@removed_tags = []
|
||||
@@ -1065,97 +1073,6 @@ class Post < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
module CountMethods
|
||||
def fast_count(tags = "", timeout: 1_000, raise_on_timeout: false, skip_cache: false)
|
||||
tags = tags.to_s
|
||||
tags += " rating:s" if CurrentUser.safe_mode?
|
||||
tags += " -status:deleted" if CurrentUser.hide_deleted_posts? && !PostQueryBuilder.new(tags).has_metatag?("status")
|
||||
tags = PostQueryBuilder.new(tags).normalize_query(normalize_aliases: true)
|
||||
|
||||
# Optimize some cases. these are just estimates but at these
|
||||
# quantities being off by a few hundred doesn't matter much
|
||||
if Danbooru.config.estimate_post_counts
|
||||
if tags == ""
|
||||
return (Post.maximum(:id).to_i * (2200402.0 / 2232212)).floor
|
||||
|
||||
elsif tags =~ /^rating:s(?:afe)?$/
|
||||
return (Post.maximum(:id).to_i * (1648652.0 / 2200402)).floor
|
||||
|
||||
elsif tags =~ /^rating:q(?:uestionable)?$/
|
||||
return (Post.maximum(:id).to_i * (350101.0 / 2200402)).floor
|
||||
|
||||
elsif tags =~ /^rating:e(?:xplicit)?$/
|
||||
return (Post.maximum(:id).to_i * (201650.0 / 2200402)).floor
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
count = nil
|
||||
|
||||
unless skip_cache
|
||||
count = get_count_from_cache(tags)
|
||||
end
|
||||
|
||||
if count.nil?
|
||||
count = fast_count_search(tags, timeout: timeout, raise_on_timeout: raise_on_timeout)
|
||||
end
|
||||
|
||||
count
|
||||
rescue SearchError
|
||||
0
|
||||
end
|
||||
|
||||
def fast_count_search(tags, timeout:, raise_on_timeout:)
|
||||
count = Post.with_timeout(timeout, nil, tags: tags) do
|
||||
Post.tag_match(tags).count
|
||||
end
|
||||
|
||||
if count.nil?
|
||||
# give up
|
||||
if raise_on_timeout
|
||||
raise TimeoutError.new("timed out")
|
||||
end
|
||||
|
||||
count = Danbooru.config.blank_tag_search_fast_count
|
||||
else
|
||||
set_count_in_cache(tags, count)
|
||||
end
|
||||
|
||||
count ? count.to_i : nil
|
||||
rescue PG::ConnectionBad
|
||||
return nil
|
||||
end
|
||||
|
||||
def fix_post_counts(post)
|
||||
post.set_tag_counts(false)
|
||||
if post.changes_saved?
|
||||
args = Hash[TagCategory.categories.map {|x| ["tag_count_#{x}", post.send("tag_count_#{x}")]}].update(:tag_count => post.tag_count)
|
||||
post.update_columns(args)
|
||||
end
|
||||
end
|
||||
|
||||
def get_count_from_cache(tags)
|
||||
if PostQueryBuilder.new(tags).is_simple_tag?
|
||||
count = Tag.find_by(name: tags).try(:post_count)
|
||||
else
|
||||
# this will only have a value for multi-tag searches or single metatag searches
|
||||
count = Cache.get(count_cache_key(tags))
|
||||
end
|
||||
|
||||
count.try(:to_i)
|
||||
end
|
||||
|
||||
def set_count_in_cache(tags, count, expiry = nil)
|
||||
expiry ||= count.seconds.clamp(3.minutes, 20.hours).to_i
|
||||
|
||||
Cache.put(count_cache_key(tags), count, expiry)
|
||||
end
|
||||
|
||||
def count_cache_key(tags)
|
||||
"pfc:#{Cache.hash(tags)}"
|
||||
end
|
||||
end
|
||||
|
||||
module ParentMethods
|
||||
# A parent has many children. A child belongs to a parent.
|
||||
# A parent cannot have a parent.
|
||||
@@ -1715,7 +1632,6 @@ class Post < ApplicationRecord
|
||||
include FavoriteMethods
|
||||
include PoolMethods
|
||||
include VoteMethods
|
||||
extend CountMethods
|
||||
include ParentMethods
|
||||
include DeletionMethods
|
||||
include VersionMethods
|
||||
|
||||
@@ -76,7 +76,7 @@ class UserPresenter
|
||||
end
|
||||
|
||||
def commented_posts_count(template)
|
||||
count = CurrentUser.without_safe_mode { Post.fast_count("commenter:#{user.name}") }
|
||||
count = CurrentUser.without_safe_mode { PostQueryBuilder.new("commenter:#{user.name}").fast_count }
|
||||
count = "?" if count.nil?
|
||||
template.link_to(count, template.posts_path(:tags => "commenter:#{user.name} order:comment_bumped"))
|
||||
end
|
||||
@@ -90,7 +90,7 @@ class UserPresenter
|
||||
end
|
||||
|
||||
def noted_posts_count(template)
|
||||
count = CurrentUser.without_safe_mode { Post.fast_count("noteupdater:#{user.name}") }
|
||||
count = CurrentUser.without_safe_mode { PostQueryBuilder.new("noteupdater:#{user.name}").fast_count }
|
||||
count = "?" if count.nil?
|
||||
template.link_to(count, template.posts_path(:tags => "noteupdater:#{user.name} order:note"))
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user