我有一个带有架构的火花数据帧 df :
[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.至少一个标签" v"对于每个id。
我在想我需要创建三列来检查每个上述条件。然后我需要通过" 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]}
我还没能解决这个问题。并且可能有比这更好的方法。希望有人能给我建议。感谢
答案 0 :(得分:3)
要将三个检查转换为矢量,您可以执行以下操作: 具体来说,你可以这样做:
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和标签分组,以便我们获得有关组合的信息。我们收集的信息是有多少值(cnt)和第一个元素(无关紧要)。
现在我们做两个过滤步骤: 1.我们只需要一个h和一个w以及任意数量的v,因此第一个过滤器可以获得这些情况。 2.我们确保每个案例都符合所有规则。
现在我们只有id和label的组合符合规则,所以为了使id合法,我们需要有三个标签实例。这导致第二组,其仅简单地计算与规则匹配的标签的数量。我们需要三个合法的(即匹配所有规则)。