Apache spark Spark:删除少于N次的行

Apache spark Spark:删除少于N次的行,apache-spark,pyspark,Apache Spark,Pyspark,假设我有以下rdd: a=[('a',1),('a',2),('a',3),('b',1),('b',4),('c',3)] anRDD=sc.parallelize(a) 我想得到它们的键出现次数超过N次的行(在本例中,假设大于或等于2)。在另一个rdd中,被排除在外的rdd 我所做的是: threshold=2 anRDD.persist() 分组计数=anRDD .toDF([“字母”,“数字]) .groupBy(“字母”) .count() downFromLimit=grouped

假设我有以下rdd:

a=[('a',1),('a',2),('a',3),('b',1),('b',4),('c',3)]
anRDD=sc.parallelize(a)
我想得到它们的键出现次数超过N次的行(在本例中,假设大于或等于2)。在另一个rdd中,被排除在外的rdd

我所做的是:

threshold=2
anRDD.persist()
分组计数=anRDD
.toDF([“字母”,“数字])
.groupBy(“字母”)
.count()
downFromLimit=grouped_counts.filter(grouped_counts['count']=threshold)。选择(“字母”).map(lambda x:x.letter)。collect()
updatea=anRDD.filter(upTheLimit中的lambda x:x[0])
downData=anRDD.filter(downFromLimit中的λx:x[0])
anRDD.unpersist()
这是我想要的,但它应该比这更清晰、更容易、更有效

如果我使用
reduceByKey
并计算值的长度,这会更有益吗

还有其他想法吗?

如果键的数量不是太多,可以使用。此外,还可以将结果转换为a,并最终过滤结果

rdd=sc.parallelize([('a',1),('a',2),('a',3),('b',1),('b',4),('c',3)])
广播=sc.broadcast(rdd.countByKey())
广播价值
#defaultdict(,{'a':3,'c':1,'b':2})
rdd.filter(lambda x:broadcast.value[x[0]]>=2)。取(10)
#[('a',1),('a',2),('a',3),('b',1),('b',4)]

你的方法和阿尔贝托的方法都在将所有钥匙拉回到司机手中,如果你有很多钥匙,这将是一个问题

我不会这样做,而是创建聚合的DF,然后将其与原始数据连接起来。然后,您可以在写入时使用分区,一次保存两个组

您应该尽可能将所有数据保存在数据帧中,而不是RDD中。在使用数据帧时有大量的优化,这在使用pyspark时尤其适用

from pyspark.sql import functions as F    

df = anRDD.toDF(['letter','number'])

counts = df.groupBy('letter') \
           .count()

# Join to the original data
df = df.join(counts, df.letter == counts.letter)

# Add the column to partition on
updated = df.withColumn('group', F.when(df.count < 2, 'down').otherwise('up')) \
           .select('letter', 'group')

# Partitioning lets us write out both groups at once, instead of recomputing stages
updated.write.partitionBy('group').text('/some/output/path')

在Scala中做同样的事情

// assuming df is a dataframe that already exists

val count_df = df.select($"column_name").groupBy($"column_name").count()
val join_df = df.join(count_df, df.col("column_name") === count_df.col("column_name"))
val new_df = join_df.filter($"count" >= 2)

谢谢你的回答。我不确定这两种方法中哪一种更有效(你的和我给的)。在我的情况下,密钥的数量是巨大的,使用广播可能会产生负面影响。如果我不想编写它们,只创建两个新的数据帧,最好的方法是制作两个过滤器?是的。我不知道还有什么其他方法来划分数据。我在EMR/S3上发现了这一点,尽管有时候只写出分区后的数据并读回会更快。您最终添加了一些IO工作,但没有为每个生成的过滤RDD重新计算阶段。这取决于你在之前和之后做了多少工作。但计数应该意味着更少的键,所以将这些返回给驱动程序会有那么糟糕吗?这取决于有多少不同的键值。如果有10个就可以了,如果有1000万个就有问题了。
// assuming df is a dataframe that already exists

val count_df = df.select($"column_name").groupBy($"column_name").count()
val join_df = df.join(count_df, df.col("column_name") === count_df.col("column_name"))
val new_df = join_df.filter($"count" >= 2)