如何在SQL中获得至少有X个评论的所有产品?

如何在SQL中获得至少有X个评论的所有产品?,sql,apache-spark,apache-spark-sql,Sql,Apache Spark,Apache Spark Sql,我想查找product\u id至少有3条评论的所有行(review\u id) 因此,对于以下示例: product_id, review_id 1, 1 1, 2 1, 3 2, 4 3, 5 4, 6 4, 7 4, 8 它应返回: product_id, review_id 1, 1 1, 2 1, 3 4, 6 4, 7 4, 8 以下是我尝试过的查询: query1 = ''' SELECT first_va

我想查找
product\u id
至少有3条评论的所有行(
review\u id

因此,对于以下示例:

product_id, review_id
1,   1
1,   2
1,   3
2,   4
3,   5
4,   6
4,   7
4,   8
它应返回:

product_id, review_id
1,   1
1,   2
1,   3
4,   6
4,   7
4,   8
以下是我尝试过的查询:

query1 = '''
        SELECT first_value(customer_id), first_value(review_id), first_value(product_id)
        FROM df
        WHERE product_category='Toys' OR product_category='Beauty'
        GROUP BY product_id
        HAVING COUNT(*) >= 5
'''
上面只返回第一个结果,但当我不使用
first\u value
函数时,我得到一个错误
“表达式'df.review\u id'既不在group by中,也不是聚合函数。

query1 = '''
        SELECT customer_id, review_id, product_id
        FROM df
        WHERE product_category='Toys' OR product_category='Beauty'
        GROUP BY product_id
        HAVING COUNT(*) >= 5
'''

作为一个单独的查询查找所有最热门的审阅项目,并将其连接回以获取其余数据

SELECT df.* FROM
  df
  INNER JOIN
  (
    SELECT product_id
    FROM df
    WHERE product_category='Toys' OR product_category='Beauty'
    GROUP BY product_id
    HAVING COUNT(*) >= 5
  ) interesting
  on df.product_id = interesting.product_id
这是您需要采用的一般模式,用于分组/计数,然后获取有关组中产品的更多数据。您不能向进行分组的查询中添加更多列,因为这会将组拆分为更小的计数,降低到阈值以下。相反,您只计算ID的出现次数,将其限制为打开将那些具有超过某个值的计数的ID合并,然后使用该感兴趣的ID列表检索这些ID的其余信息,方法是将其连接回包含所有数据的表

支持分析查询的数据库可以一蹴而就,但上面的查询模式适用于不支持分析的数据库,因此我倾向于使用它

可以查询支持分析的数据库,因此:

  SELECT * FROM
  (
    SELECT *, COUNT(*) OVER(partition by product_id) numrev
    FROM df
    WHERE product_category='Toys' OR product_category='Beauty'
  ) interesting
  WHERE numrev >= 5
COUNT(*)OVER()通常做同样的事情;数据库将对每个产品出现次数进行计数,并在每行显示产品的计数,然后where子句仅限制大于4计数的行。假设第一个示例中的group by子查询隐藏在后台(分区是一种分组操作)在这个例子中,连接是隐含的(因为计数的产品id放在每一行上,与它相关的真实产品id一起)

这将起作用:

CREATE TABLE d061_Table1(product_id int, review_id int);    
//do inserts


select * from d061_Table1 where product_id IN( select distinct product_id  from 
(select product_id,count(product_id) from d061_Table1
group by product_id
having count(product_id)>=3));
输出:

1   1
1   2
1   3
4   6
4   7
4   8

使用pysparksql,您可以

from pyspark.sql import functions as func
#Get num reviews per product
counts = df.groupBy(df.product_id).agg(func.countDistinct(df.review_id).alias('num_reviews'))
#Filter for num reviews >= 3
gt_3_reviews = counts.filter(counts.num_reviews >= 3).select(counts.product_id)
#Join it with the original dataframe and select the required columns
res = df.join(counts, counts.product_id == df.product_id).select(df.product_id,df.review_id)
res.show()
或者使用窗口函数

from pyspark.sql import functions as func
from pyspark.sql import Window 
#Select distinct rows from columns needed
dist_df = df.select(df.product_id,df.review_id).distinct()
#Define the window
w = Window.partitionBy(dist_df.product_id)
#Count number of reviews per product with the previously defined window
dist_df = dist_df.withColumn('num_reviews',func.count('*').over(w))
#Filter criteria
res = dist_df.filter(dist_df.num_reviews >= 3).select(dist_df.product_id,dist_df.review_id)
res.show()
使用sparkscalasql

val df = Seq((1,1),(1,2),(1,3),(2,4),(3,5),(4,6),(4,7),(4,8)).toDF("product_id", "review_id")
df.createOrReplaceTempView("review")
spark.sql(
  """ with t1( select product_id, review_id , count(*) over(partition by product_id) c1 from review)
    select product_id, review_id  from t1 where c1 >=3
  """).show(false)
结果:

+----------+---------+
|product_id|review_id|
+----------+---------+
|1         |1        |
|1         |2        |
|1         |3        |
|4         |6        |
|4         |7        |
|4         |8        |
+----------+---------+
使用df函数获得相同的结果

import org.apache.spark.sql.expressions.Window
val df = Seq((1,1),(1,2),(1,3),(2,4),(3,5),(4,6),(4,7),(4,8)).toDF("product_id", "review_id")
df.withColumn("cn",count('product_id).over(Window.partitionBy('product_id))).filter(" cn>=3 ").drop("cn").show(false)
我想返回产品至少有3次评论的所有结果

哦,天哪,这是一个非常好的窗口聚合用例(它通常是
groupBy
后面跟着
join
的更好的替代方案)

scala>input.show
+----------+---------+
|产品标识|审查标识||
+----------+---------+
|         1|        1|
|         1|        2|
|         1|        3|
|         2|        4|
|         3|        5|
|         4|        6|
|         4|        7|
|         4|        8|
+----------+---------+
导入org.apache.spark.sql.expressions.Window
val productId=Window.partitionBy(“产品id”)
val解决方案=输入
.withColumn(“count”,count('*)超过ProductID)

.filter('count>=3)//谢谢,这正是我所需要的。我如何将其恢复为“正常”格式?现在df.head()给我
行(product\u id='ABC',customer\u id=1,review\u id='2',product\u id='ABC')
并查询它会给出错误
“Reference'product\u id'不明确,可能是:df.product\u id,interest.product\u id。;“
指定您想要的一个?它们是相同的,所以您选择哪一个都不重要。我编辑了查询,只需
select df.*from
,这样很有趣。product_id不会放在结果设置中,但如何将其放在没有行的正常数据帧格式中()?我无法对其执行任何操作,因为我获取的“DataFrame”对象没有属性X
。我无法使用
df.product\u id.value\u counts()
df.rename(列={'product\u id':'blah'))
。我不明白它是什么格式的inOops,这是一个愚蠢的问题!这是一个pyspark数据帧,我想要的操作需要一个pandas数据帧。你想要纯SQL的解决方案还是Spark SQL的任何解决方案?
scala> input.show
+----------+---------+
|product_id|review_id|
+----------+---------+
|         1|        1|
|         1|        2|
|         1|        3|
|         2|        4|
|         3|        5|
|         4|        6|
|         4|        7|
|         4|        8|
+----------+---------+

import org.apache.spark.sql.expressions.Window
val productIds = Window.partitionBy("product_id")
val solution = input
  .withColumn("count", count('*) over productIds)
  .filter('count >= 3) // <-- that's the gist of the solution
  .select('product_id, 'review_id)
scala> solution.show
+----------+---------+
|product_id|review_id|
+----------+---------+
|         1|        1|
|         1|        2|
|         1|        3|
|         4|        6|
|         4|        7|
|         4|        8|
+----------+---------+