[英]Spark Scala : Add new column without looping throw same table many times
我想添加一个名为activeIOsAtSite的新列,其值为“ Y ”或“ N ”。
该值将根据以下条件添加:
对于下表行中的每一列SITE_SITE_ID ; 如果SITE_SITE_ID具有:
(APPLICATION_SOURCE == 'CIBASE' AND STANDARD_STATUS =='ACTIVE')
在这种情况下,该值应为“Y”,否则为“N”
是否有一种方法可以做到这一点,而无需一遍又一遍地迭代同一个表(对于每一行),因为我拥有的表是如此之大,我需要以最快的方式做到这一点?
期望结果的示例:
我试图做类似的事情,但我不确定它是否正确:
finvInventoryAllDf
.withColumn(
"activeIOsAtSite",
activeIOsAtSiteGenerator(finvInventoryAllDf, col("Site_siteId"))
)
使用activeIOsAtSiteGenerator()
是 function 我验证上述条件:
def activeIOsAtSiteGenerator(dataFrame: DataFrame, site_siteId: Column): Column = {
val count = dataFrame
.where(col("Site_siteId") === site_siteId)
.where("InstalledOffer_installedOfferId IS NOT NULL AND InstalledOffer_installedOfferId NOT IN ('','null','NULL') AND UPPER(InstalledOffer_standardStatus) IN ('ACTIVE') AND UPPER(InstalledOffer_applicationSource) IN('CIBASE')")
.count()
if (count > 0)
lit("Y")
else
lit("N")
}
您可以先groupBy
唯一 ID,然后collect_set
检查该列是否包含您提到的任何组合。
var grouped = df
.groupBy("SITE_SITE_ID").agg(collect_set(array("APPLICATION_SOURCE", "STANDARD_STATUS")).as("array"))
.withColumn("indicator",
expr("transform(array, x -> array_contains(x, 'CIBASE') and array_contains(x, 'ACTIVE'))")
)
如果订单很重要:
.withColumn("indicator",
expr("transform(array, x -> lower(element_at(x, 1)) = 'cibase' and lower(element_at(x, 2)) = 'active')")
)
我们现有的形式:
+------------+------------------------------------+-------------+
|SITE_SITE_ID|array |indicator |
+------------+------------------------------------+-------------+
|si_2 |[[SLOW, STASH]] |[false] | <- make this N
|si_3 |[[MEDIUM, TREE]] |[false] | <- make this N
|si_1 |[[FAST, DISABLED], [CIBASE, ACTIVE]]|[false, true]| <- make this Y (pair found)
+------------+------------------------------------+-------------+
然后我们继续:
grouped = grouped.withColumn("indicator",
when(array_contains(col("indicator"), true), "Y").otherwise("N")
)
.drop("array")
+------------+---------+
|SITE_SITE_ID|indicator|
+------------+---------+
|si_2 |N |
|si_3 |N |
|si_1 |Y |
+------------+---------+
collected_set
返回一个arrays数组,这就是我们检查combo的原因,我们再次检查,如果数组中有一个为true(找到了combo),则返回Y
,否则返回N
; 最后,我们删除array
列。
分组样本:
+------------+---------+
|SITE_SITE_ID|indicator|
+------------+---------+
|si_2 |N |
|si_3 |N |
|si_1 |Y |
+------------+---------+
最后,我们用grouped
加入我们的主表:
df.join(grouped, Seq("SITE_SITE_ID"))
最后结果:
+------------+-----+------------------+---------------+---------+
|SITE_SITE_ID|IR_ID|APPLICATION_SOURCE|STANDARD_STATUS|indicator|
+------------+-----+------------------+---------------+---------+
|si_2 |ir2 |SLOW |STASH |N |
|si_3 |ir3 |MEDIUM |TREE |N |
|si_1 |ir1 |FAST |DISABLED |Y |
|si_1 |ir4 |CIBASE |ACTIVE |Y |
+------------+-----+------------------+---------------+---------+
祝你好运!
@vilalabinot 答案百分百正确:但我必须使用与 udf function 相同的逻辑来改进它:
所以我们仍然需要按 SITE_SITE_ID 分组:
val grouped0 = finvInventoryAllDf
.groupBy("SITE_SITE_ID")
.agg(
collect_set(
array(
"InstalledOffer_applicationSource",
"InstalledOffer_standardStatus", "InstalledOffer_installedOfferId"
)
).as("array")
)
但是要创建新字段,我使用 udf 会根据所需条件直接给我 Y 或 N 值,所以:
grouped0
.withColumn("activeIOsAtSite", buildFieldActiveIOsAtSite_UDF(col("array")))
.drop("array")
我正在使用的 UDF 声明:
val buildFieldActiveIOsAtSite_UDF = udf(buildFieldActiveIOsAtSite _)
最后是这个udf的function:
def buildFieldActiveIOsAtSite(rows: mutable.WrappedArray[mutable.WrappedArray[String]]): String = {
var yesOrNoCondition = "N";
breakable {
rows.array.foreach(r => {
val installedOffer_applicationSource = Option(r(0)).getOrElse("")
val installedOffer_standardStatus = Option(r(1)).getOrElse("")
val InstalledOffer_installedOfferId = Option(r(2)).getOrElse("")
val yesCondition = InstalledOffer_installedOfferId.nonEmpty &&
!InstalledOffer_installedOfferId.equalsIgnoreCase("null") &&
installedOffer_standardStatus.equalsIgnoreCase("active") &&
installedOffer_applicationSource.equalsIgnoreCase("CIBASE")
if (yesCondition) {
yesOrNoCondition = "Y"
break
}
})
}
yesOrNoCondition
}
现在剩下要做的就是与主 dataframe 进行小连接:
val finvResultOutput1 = finvInventoryAllDf.join(grouped0, Seq("SITE_SITE_ID"))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.