【问题标题】:SQL- Selecting the most similar productSQL-选择最相似的产品
【发布时间】:2013-05-09 02:55:43
【问题描述】:

好的,我有一个存储两个键的关系,一个产品 ID 和一个属性 ID。我想找出与给定产品最相似的产品。 (属性实际上是数字,但它使示例更加混乱,因此将它们更改为字母以简化视觉表示。)

Prod_att

Product | Attributes  
   1   |    A     
   1   |    B  
   1   |    C  
   2   |    A  
   2   |    B  
   2   |    D  
   3   |    A  
   3   |    E  
   4   |    A  

最初这看起来相当简单,只需选择产品具有的属性,然后计算每个产品共享的属性数量。然后将其结果与产品具有的属性数量进行比较,我可以看到两种产品的相似程度。这适用于相对于其比较产品具有大量属性的产品,但是当产品的属性非常少时会出现问题。例如,产品 3 几乎与所有其他产品都有一个平局(因为 A 很常见)。

SELECT Product, count(Attributes)  
FROM Prod_att  
WHERE Attributes IN  
(SELECT Attributes  
FROM prod_att  
WHERE Product = 1)  
GROUP BY Product
;  

对如何解决此问题或改进我当前的查询有何建议?
谢谢!

*edit: 产品 4 将为所有产品返回 count() =1。我想展示产品 3 更相似,因为它具有更少的不同属性。

【问题讨论】:

  • 如何定义一个最小的相似属性集?这可以使用HAVING 子句来实现。
  • 您使用的是什么RDBMSRDBMS 代表关系数据库管理系统RDBMS is the basis for SQL,对于所有现代数据库系统,如 MS SQL Server、IBM DB2、Oracle、MySQL 等...您能否也提供具有所需结果的示例记录?
  • 你用的是什么数据库?
  • 在这种情况下应该如何处理产品 3?听起来您需要某种额外的因素来降低属性很少的产品的相似性......但如果不知道您想要什么结果,这很难建议。

标签: mysql sql


【解决方案1】:

试试这个

SELECT 
  a_product_id, 
  COALESCE( b_product_id, 'no_matchs_found' ) AS closest_product_match
FROM (
  SELECT 
    *,  
    @row_num := IF(@prev_value=A_product_id,@row_num+1,1) AS row_num,
    @prev_value := a_product_id
  FROM 
    (SELECT @prev_value := 0) r
    JOIN (
        SELECT 
         a.product_id as a_product_id,
         b.product_id as b_product_id,
         count( distinct b.Attributes ),
         count( distinct b2.Attributes ) as total_products
        FROM
          products a
          LEFT JOIN products b ON ( a.Attributes = b.Attributes AND a.product_id <> b.product_id )
          LEFT JOIN products b2 ON ( b2.product_id = b.product_id )
       /*WHERE */
         /*  a.product_id = 3 */
        GROUP BY
         a.product_id,
         b.product_id
        ORDER BY 
          1, 3 desc, 4
  ) t
) t2 
WHERE 
  row_num = 1

上面的query 获取所有产品的closest matches,您可以在最里面的查询中包含product_id,以获取特定product_id 的结果,我使用了LEFT JOIN,这样即使如果 product 没有匹配项,则显示它

SQLFIDDLE

希望对你有帮助

【讨论】:

  • 效果很好!比仅仅比较匹配的属性要复杂得多。谢谢。
  • 很高兴知道它很有帮助:)
【解决方案2】:

试试"Lower bound of Wilson score confidence interval for a Bernoulli parameter"。当 n 较小时,这会明确处理统计置信度问题。它看起来像很多数学,但实际上这是正确完成此类事情所需的最少数学量。该网站解释得很好。

这假设可以从正面/负面评分迈向匹配/不匹配属性的问题。

以下是正面和负面评分以及 95% CL 的示例:

SELECT widget_id, ((positive + 1.9208) / (positive + negative) - 
1.96 * SQRT((positive * negative) / (positive + negative) + 0.9604) / 
(positive + negative)) / (1 + 3.8416 / (positive + negative)) 
AS ci_lower_bound FROM widgets WHERE positive + negative > 0 
ORDER BY ci_lower_bound DESC;

【讨论】:

    【解决方案3】:

    您可以编写一个小视图,为您提供两个产品之间的全部共享属性。

    create view vw_shared_attributes as
    select a.product, 
          b.product 'product_match', 
          count(*) 'shared_attributes'
    from  your_table a
      inner join test b on b.attribute = a.attribute and b.product <> a.product
    group by a.product, b.product  
    

    然后使用该视图选择最佳匹配项。

       select product,
          (select top 1 s.product_match from vw_shared_attributes s where t.product = s.product order by s.shared_attributes desc)
        from your_table t
        group by product
    

    请参阅http://www.sqlfiddle.com/#!6/53039/1 了解示例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-26
      • 2018-04-26
      • 2018-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多