繁体   English   中英

如何在Spark数据帧中按分组和聚合后进行过滤?

[英]How to filter after group by and aggregate in Spark dataframe?

with schema as such: 我有一个带有架构的spark数据帧

[id:string, label:string, tags:string]

id | label | tag
---|-------|-----
 1 | h     | null
 1 | w     | x
 1 | v     | null
 1 | v     | x
 2 | h     | x
 3 | h     | x
 3 | w     | x
 3 | v     | null
 3 | v     | null
 4 | h     | null
 4 | w     | x
 5 | w     | x

(h,w,v是标签.x可以是任何非空值)

对于每个id,最多只有一个标签“h”或“w”,但可能有多个“v”。 我想选择满足以下条件的所有ID:

每个id具有:1。一个标签“h”,其标签= null,2。一个标签“w”及其标签!= null,3。每个id至少有一个标签“v”。

我想我需要创建三列来检查上述每个条件。 然后我需要通过“id”做一组。

val hCheck = (label: String, tag: String) => {if (label=="h" && tag==null) 1 else 0}
val udfHCheck = udf(hCheck)
val wCheck = (label: String, tag: String) => {if (label=="w" && tag!=null) 1 else 0}
val udfWCheck = udf(wCheck)
val vCheck = (label: String) => {if (label==null) 1 else 0}
val udfVCheck = udf(vCheck)

dfx = df.withColumn("hCheck", udfHCheck(col("label"), col("tag")))
        .withColumn("wCheck", udfWCheck(col("label"), col("tag")))
        .withColumn("vCheck", udfVCheck(col("label")))
        .select("id","hCheck","wCheck","vCheck")
        .groupBy("id")

不知何故,我需要将三列{“hCheck”,“wCheck”,“vCheck”}分组到列表[x,0,0],[0,x,0],[0,0,x]的向量中。 并检查这些向量是否包含所有三个{[1,0,0],[0,1,0],[0,0,1]}

我还没能解决这个问题。 并且可能有比这更好的方法。 希望有人能给我建议。 谢谢

要将三个检查转换为矢量,您可以执行以下操作:具体来说,您可以:

val df1 = df.withColumn("hCheck", udfHCheck(col("label"), col("tag")))
            .withColumn("wCheck", udfWCheck(col("label"), col("tag")))
            .withColumn("vCheck", udfVCheck(col("label")))
            .select($"id",array($"hCheck",$"wCheck",$"vCheck").as("vec"))

接下来,groupby返回您需要执行聚合的分组对象。 特别要获得所有向量,你应该做的事情如下:

    .groupBy("id").agg(collect_list($"vec"))

此外,您不需要udfs进行各种检查。 您可以使用列语义来完成它。 例如,udfHCheck可以写成:

with($"label" == lit("h") && tag.isnull 1).otherwise(0)

顺便说一句,你说你想要每个标签'v',但在vcheck中你只需检查标签是否为空。

更新:替代解决方案

再看一遍这个问题,我会做这样的事情:

val grouped = df.groupBy("id", "label").agg(count("$label").as("cnt"), first($"tag").as("tag"))
val filtered1 = grouped.filter($"label" === "v" || $"cnt" === 1)
val filtered2 = filtered.filter($"label" === "v" || ($"label" === "h" && $"tag".isNull) || ($"label" === "w" && $"tag".isNotNull))
val ids = filtered2.groupBy("id").count.filter($"count" === 3)

我们的想法是首先通过BOTH id和label进行分组,以便我们获得有关组合的信息。 我们收集的信息是多少个值(cnt)和第一个元素(无关紧要)。

现在我们做两个过滤步骤:1。我们只需要一个h和一个w以及任意数量的v,因此第一个过滤器可以获得这些情况。 2.我们确保每个案例都符合所有规则。

现在我们只有id和label的组合符合规则,所以为了使id合法,我们需要有三个标签实例。 这导致第二组,其仅简单地计算与规则匹配的标签的数量。 我们需要三个合法的(即匹配所有规则)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM