Files
danbooru/app/presenters/post_set_presenters/post.rb
evazion bda69315ff search: optimize related tag calc in multi-tag searches (#4120).
In multi-tag searches, we calculated the tags in the sidebar by sampling
300 random posts from within the search and finding the most frequently
used tags. This meant we were effectively doing two searches on every
page load, one for the actual search and one for the sidebar. This is
not so bad for fast searches, but very bad for slow searches.

Instead, now we calculate the related tags from the current page of
results. This is much faster, at the cost of slightly lower accuracy and
the tag list changing slightly as you browse between pages.

We could use caching here, which would help when browsing between pages,
but we would still have to calculate the tags on the first page load,
which can be very slow in the worst case.
2019-08-12 13:38:45 -05:00

78 lines
2.3 KiB
Ruby

module PostSetPresenters
class Post < Base
attr_accessor :post_set
delegate :posts, :to => :post_set
def initialize(post_set)
@post_set = post_set
end
def tag_set_presenter
@tag_set_presenter ||= TagSetPresenter.new(related_tags)
end
def post_previews_html(template, options = {})
super(template, options.merge(show_cropped: true))
end
def related_tags
if post_set.is_pattern_search?
pattern_tags
elsif post_set.is_saved_search?
["search:all"] + SavedSearch.labels_for(CurrentUser.user.id).map {|x| "search:#{x}"}
elsif post_set.is_empty_tag? || post_set.tag_string == "order:rank"
popular_tags
elsif post_set.is_single_tag?
related_tags_for_single(post_set.tag_string)
elsif post_set.unordered_tag_array.size == 1
related_tags_for_single(post_set.unordered_tag_array.first)
elsif Tag.has_metatag?(post_set.tag_array, *Tag::SUBQUERY_METATAGS)
calculate_related_tags_from_post_set
else
calculate_related_tags_from_post_set
end
end
def popular_tags
if PopularSearchService.enabled?
PopularSearchService.new(Date.today).tags.slice(0, 25)
else
Tag.trending
end
end
def pattern_tags
Tag.name_matches(post_set.tag_string).select("name").limit(Danbooru.config.tag_query_limit).order("post_count DESC").map(&:name)
end
def related_tags_for_group
normalized_tags = Tag.normalize_query(post_set.tag_string, normalize_aliases: false)
Cache.get("PostSetPresenters::Post#related_tags_for_group(#{normalized_tags})", 5.minutes) do
RelatedTagCalculator.calculate_from_sample_to_array(normalized_tags).map(&:first)
end
end
def related_tags_for_single(tag_string)
tag = Tag.find_by_name(tag_string.downcase)
if tag
tag.related_tag_array.map(&:first)
else
calculate_related_tags_from_post_set
end
end
def calculate_related_tags_from_post_set
RelatedTagCalculator.calculate_from_posts_to_array(post_set.posts).map(&:first)
end
def saved_search_labels
SavedSearch.labels_for(CurrentUser.user.id).map {|x| "search:#{x}"}
end
def tag_list_html(**options)
tag_set_presenter.tag_list_html(name_only: post_set.is_saved_search?, **options)
end
end
end