posts: optimize filetype: searches.
When searching posts by width, height, file size, or file extension, use the values from the media_assets table rather than the posts table. This makes filetype: searches faster because the file_ext is indexed on the media assets table, but not on the posts table. This paves the way for getting rid of the width, height, file_size, and file_ext indexes on the posts table in the future. It's wasteful to index these columns on both the posts table and the media assets table.
This commit is contained in:
@@ -90,13 +90,13 @@ class PostQueryBuilder
|
|||||||
when "md5"
|
when "md5"
|
||||||
relation.attribute_matches(value, :md5, :md5)
|
relation.attribute_matches(value, :md5, :md5)
|
||||||
when "width"
|
when "width"
|
||||||
relation.attribute_matches(value, :image_width)
|
relation.attribute_matches(value, "media_assets.image_width").joins(:media_asset)
|
||||||
when "height"
|
when "height"
|
||||||
relation.attribute_matches(value, :image_height)
|
relation.attribute_matches(value, "media_assets.image_height").joins(:media_asset)
|
||||||
when "mpixels"
|
when "mpixels"
|
||||||
relation.attribute_matches(value, "posts.image_width * posts.image_height / 1000000.0", :float)
|
relation.attribute_matches(value, "(media_assets.image_width * media_assets.image_height) / 1000000.0", :float).joins(:media_asset)
|
||||||
when "ratio"
|
when "ratio"
|
||||||
relation.attribute_matches(value, "ROUND(1.0 * posts.image_width / GREATEST(1, posts.image_height), 2)", :ratio)
|
relation.attribute_matches(value, "ROUND(media_assets.image_width::numeric / media_assets.image_height::numeric, 2)", :ratio).joins(:media_asset)
|
||||||
when "score"
|
when "score"
|
||||||
relation.attribute_matches(value, :score)
|
relation.attribute_matches(value, :score)
|
||||||
when "upvotes"
|
when "upvotes"
|
||||||
@@ -106,9 +106,9 @@ class PostQueryBuilder
|
|||||||
when "favcount"
|
when "favcount"
|
||||||
relation.attribute_matches(value, :fav_count)
|
relation.attribute_matches(value, :fav_count)
|
||||||
when "filesize"
|
when "filesize"
|
||||||
relation.attribute_matches(value, :file_size, :filesize)
|
relation.attribute_matches(value, "media_assets.file_size", :filesize).joins(:media_asset)
|
||||||
when "filetype"
|
when "filetype"
|
||||||
relation.attribute_matches(value, :file_ext, :enum)
|
relation.attribute_matches(value, "media_assets.file_ext", :enum).joins(:media_asset)
|
||||||
when "date"
|
when "date"
|
||||||
relation.attribute_matches(value, :created_at, :date)
|
relation.attribute_matches(value, :created_at, :date)
|
||||||
when "age"
|
when "age"
|
||||||
@@ -414,28 +414,23 @@ class PostQueryBuilder
|
|||||||
relation = relation.reorder("artist_commentaries.updated_at ASC")
|
relation = relation.reorder("artist_commentaries.updated_at ASC")
|
||||||
|
|
||||||
when "mpixels", "mpixels_desc"
|
when "mpixels", "mpixels_desc"
|
||||||
relation = relation.where(Arel.sql("posts.image_width is not null and posts.image_height is not null"))
|
# Use "w*h/1000000", even though "w*h" would give the same result, so this can use the posts_mpixels index.
|
||||||
# Use "w*h/1000000", even though "w*h" would give the same result, so this can use
|
relation = relation.joins(:media_asset).reorder(Arel.sql("media_assets.image_width * media_assets.image_height / 1000000.0 DESC"))
|
||||||
# the posts_mpixels index.
|
|
||||||
relation = relation.reorder(Arel.sql("posts.image_width * posts.image_height / 1000000.0 DESC"))
|
|
||||||
|
|
||||||
when "mpixels_asc"
|
when "mpixels_asc"
|
||||||
relation = relation.where("posts.image_width is not null and posts.image_height is not null")
|
relation = relation.joins(:media_asset).reorder(Arel.sql("media_assets.image_width * media_assets.image_height / 1000000.0 ASC"))
|
||||||
relation = relation.reorder(Arel.sql("posts.image_width * posts.image_height / 1000000.0 ASC"))
|
|
||||||
|
|
||||||
when "portrait"
|
when "portrait"
|
||||||
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL")
|
relation = relation.joins(:media_asset).reorder(Arel.sql("media_assets.image_width::numeric / media_assets.image_height::numeric ASC"))
|
||||||
relation = relation.reorder(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) ASC"))
|
|
||||||
|
|
||||||
when "landscape"
|
when "landscape"
|
||||||
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL")
|
relation = relation.joins(:media_asset).reorder(Arel.sql("media_assets.image_width::numeric / media_assets.image_height::numeric DESC"))
|
||||||
relation = relation.reorder(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) DESC"))
|
|
||||||
|
|
||||||
when "filesize", "filesize_desc"
|
when "filesize", "filesize_desc"
|
||||||
relation = relation.reorder("posts.file_size DESC")
|
relation = relation.joins(:media_asset).reorder("media_assets.file_size DESC")
|
||||||
|
|
||||||
when "filesize_asc"
|
when "filesize_asc"
|
||||||
relation = relation.reorder("posts.file_size ASC")
|
relation = relation.joins(:media_asset).reorder("media_assets.file_size ASC")
|
||||||
|
|
||||||
when /\A(?<column>#{COUNT_METATAGS.join("|")})(_(?<direction>asc|desc))?\z/i
|
when /\A(?<column>#{COUNT_METATAGS.join("|")})(_(?<direction>asc|desc))?\z/i
|
||||||
column = $~[:column]
|
column = $~[:column]
|
||||||
|
|||||||
@@ -1075,7 +1075,7 @@ class Post < ApplicationRecord
|
|||||||
when *AutocompleteService::POST_STATUSES
|
when *AutocompleteService::POST_STATUSES
|
||||||
status_matches(value, current_user)
|
status_matches(value, current_user)
|
||||||
when *MediaAsset::FILE_TYPES
|
when *MediaAsset::FILE_TYPES
|
||||||
attribute_matches(value, :file_ext, :enum)
|
attribute_matches(value, "media_assets.file_ext", :enum).joins(:media_asset)
|
||||||
when *Post::RATINGS.values.map(&:downcase)
|
when *Post::RATINGS.values.map(&:downcase)
|
||||||
rating_matches(value)
|
rating_matches(value)
|
||||||
when *Post::RATING_ALIASES.keys
|
when *Post::RATING_ALIASES.keys
|
||||||
|
|||||||
@@ -823,13 +823,13 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the is:<filetype> metatag" do
|
should "return posts for the is:<filetype> metatag" do
|
||||||
jpg = create(:post, file_ext: "jpg")
|
jpg = create(:post, file_ext: "jpg", media_asset: build(:media_asset, file_ext: "jpg"))
|
||||||
png = create(:post, file_ext: "png")
|
png = create(:post, file_ext: "png", media_asset: build(:media_asset, file_ext: "png"))
|
||||||
gif = create(:post, file_ext: "gif")
|
gif = create(:post, file_ext: "gif", media_asset: build(:media_asset, file_ext: "gif"))
|
||||||
mp4 = create(:post, file_ext: "mp4")
|
mp4 = create(:post, file_ext: "mp4", media_asset: build(:media_asset, file_ext: "mp4"))
|
||||||
webm = create(:post, file_ext: "webm")
|
webm = create(:post, file_ext: "webm", media_asset: build(:media_asset, file_ext: "webm"))
|
||||||
swf = create(:post, file_ext: "swf")
|
swf = create(:post, file_ext: "swf", media_asset: build(:media_asset, file_ext: "swf"))
|
||||||
zip = create(:post, file_ext: "zip")
|
zip = create(:post, file_ext: "zip", media_asset: build(:media_asset, file_ext: "zip"))
|
||||||
|
|
||||||
assert_tag_match([jpg], "is:jpg")
|
assert_tag_match([jpg], "is:jpg")
|
||||||
assert_tag_match([png], "is:png")
|
assert_tag_match([png], "is:png")
|
||||||
@@ -937,8 +937,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the filetype:<ext> metatag" do
|
should "return posts for the filetype:<ext> metatag" do
|
||||||
png = create(:post, file_ext: "png")
|
png = create(:post, file_ext: "png", media_asset: build(:media_asset, file_ext: "png"))
|
||||||
jpg = create(:post, file_ext: "jpg")
|
jpg = create(:post, file_ext: "jpg", media_asset: build(:media_asset, file_ext: "jpg"))
|
||||||
|
|
||||||
assert_tag_match([png], "filetype:png")
|
assert_tag_match([png], "filetype:png")
|
||||||
assert_tag_match([jpg], "-filetype:png")
|
assert_tag_match([jpg], "-filetype:png")
|
||||||
@@ -1275,7 +1275,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
# posts[0] is portrait, posts[1] is landscape. posts[1].mpixels > posts[0].mpixels.
|
# posts[0] is portrait, posts[1] is landscape. posts[1].mpixels > posts[0].mpixels.
|
||||||
image_height: 100 * n * n,
|
image_height: 100 * n * n,
|
||||||
image_width: 100 * (3 - n) * n,
|
image_width: 100 * (3 - n) * n,
|
||||||
tag_string: tags[n - 1]
|
tag_string: tags[n - 1],
|
||||||
|
media_asset: build(:media_asset, image_height: 100 * n * n, image_width: 100 * (3 - n) * n, file_size: 1.megabyte * n)
|
||||||
)
|
)
|
||||||
|
|
||||||
u = create(:user, created_at: 2.weeks.ago)
|
u = create(:user, created_at: 2.weeks.ago)
|
||||||
@@ -1378,7 +1379,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for a filesize search" do
|
should "return posts for a filesize search" do
|
||||||
post = create(:post, file_size: 1.megabyte)
|
post = create(:post, file_size: 1.megabyte, media_asset: build(:media_asset, file_size: 1.megabyte))
|
||||||
|
|
||||||
assert_tag_match([post], "filesize:1mb")
|
assert_tag_match([post], "filesize:1mb")
|
||||||
assert_tag_match([post], "filesize:1000kb")
|
assert_tag_match([post], "filesize:1000kb")
|
||||||
|
|||||||
Reference in New Issue
Block a user