当使用多个关联来管理严重的标签时,按照所选标签的数量对集合进行排序/排序的最有效方法是什么。
例如:
在这种情况下是否可以使用cache_counter或类似的东西?我不相信使用sort
是最好的选择。我是否认为在实际数据库上使用order
通常比sort
更快?
很抱歉,如果上述情况令人困惑。基本上我所追求的更接近于通过相关性排序。例如,用户可以选择标签1,2和4.如果产品具有与之关联的所有树标签,我希望首先列出该产品。第二个产品可能只有标签1&等等。我几乎肯定这必须使用sort
与order
,但是想知道是否有人找到了更有效的方法。
答案 0 :(得分:0)
在数据库中按相关性排序既可能也比在Ruby中使用sort方法更有效。假设以下模型结构和适当的基础SQL表结构:
class Product < ActiveRecord::Base
has_many :product_taggings
has_many :product_tags, :through => :product_taggings
end
class ProductTags < ActiveRecord::Base
has_many :product_taggings
has_many :products, :through => :product_taggings
end
class ProductTaggings < ActiveRecord::Base
belongs_to :product
belongs_to :product_tags
end
在MySQL中查询相关性看起来像:
SELECT
`product_id`
,COUNT(*) AS relevance
FROM
`product_taggings` AS ptj
LEFT JOIN
`products` AS p
ON p.`id` = ptj.`product_id`
LEFT JOIN
`product_tags` AS pt
ON pt.`id` = ptj.`product_tag_id`
WHERE
pt.`name` IN ('Tag 1', 'Tag 2')
GROUP BY
`product_id`
如果我有以下产品和相关标签:
Product 1 -> Tag 3
Product 2 -> Tag 1, Tag 2
Product 3 -> Tag 1, Tag 3
然后上面的WHERE
条款应该是我:
product_id | relevance
----------------------
2 | 2
3 | 1
* Product 1 is not included since there were no matches.
Given that the user is performing a filtered search,
this behavior is probably fine. There's a way to get
Product 1 into the results with 0 relevance if
necessary.
你所做的是创建一个很好的小结果集,它可以作为一种内联联接表。为了将相关性分数粘贴到products
表中查询的每一行,请将此查询用作子查询,如下所示:
SELECT *
FROM
`products` AS p
,(SELECT
`product_id`
,COUNT(*) AS relevance
FROM
`product_taggings` AS ptj
LEFT JOIN
`products` AS p
ON p.`id` = ptj.`product_id`
LEFT JOIN
`product_tags` AS pt
ON pt.`id` = ptj.`product_tag_id`
WHERE
pt.`name` IN ('Tag 1', 'Tag 2')
GROUP BY `product_id`
) AS r
WHERE
p.`id` = r.`product_id`
ORDER BY
r.`relevance` DESC
您将拥有的结果集包含products
表格中的字段以及末尾的其他相关性列,然后将在ORDER BY
中使用子句。
您需要编写一个方法,使用您想要的pt.name IN
列表填充此查询。在将其插入查询之前,请务必清理该列表,否则您将打开自己的SQL注入。
获取查询汇编方法的结果并通过Product.find_by_sql(my_relevance_sql)
运行,以便直接从数据库中按相关性对模型进行预先排序。
显而易见的缺点是,您在Rails代码中引入了特定于DBMS的依赖关系(如果您不小心,则会冒SQL注入风险)。如果您不使用MySQL,则可能需要调整语法。但是,与在结果上使用Ruby sort
相比,它应该执行得更快,特别是在结果集上。此外,如果需要,添加LIMIT
子句将为您提供分页支持。
答案 1 :(得分:0)
在Ryan的优秀答案的基础上,我想要一个可以使用acts-as-taggable-on
的方法和类似的插件(名为tags
/ taggings
的表),最后得到这个:< / p>
def Product.find_by_tag_list(tag_list)
tag_list_sql = "'" + tag_list.join("','") + "'"
Product.find_by_sql("SELECT * FROM products, (SELECT taggable_id, COUNT(*) AS relevance FROM taggings LEFT JOIN tags ON tags.id = taggings.tag_id WHERE tags.name IN (" + tag_list_sql + ") GROUP BY taggable_id) AS r WHERE products.id = r.taggable_id ORDER BY r.relevance DESC;")
end
要获得按相关性排序的相关产品列表,我可以这样做:
Product.find_by_tag_list(my_product.tag_list)