我有一个数据帧df,其中包含以下数据:
**customers** **product** **Val_id**
1 A 1
2 B X
3 C
4 D Z
我已经提供了2条规则,如下所示:
**rule_id** **rule_name** **product value** **priority**
123 ABC A,B 1
456 DEF A,B,D 2
要求是按优先级顺序对数据框df应用这些规则,已通过规则1的客户不应考虑用于规则2,而在最终数据框中添加另外两列rule_id和rule_name,我已编写下面的代码来实现它:
val rule_name = when(col("product").isin("A","B"), "ABC").otherwise(when(col("product").isin("A","B","D"), "DEF").otherwise(""))
val rule_id = when(col("product").isin("A","B"), "123").otherwise(when(col("product").isin("A","B","D"), "456").otherwise(""))
val df1 = df_customers.withColumn("rule_name" , rule_name).withColumn("rule_id" , rule_id)
df1.show()
最终输出如下所示:
**customers** **product** **Val_id** **rule_name** **rule_id**
1 A 1 ABC 123
2 B X ABC 123
3 C
4 D Z DEF 456
有没有更好的方法来实现它,通过遍历整个数据集一次而不是遍历整个数据集两次来添加两列?
答案 0 :(得分:2)
问题:有没有更好的方法来实现它,添加两列 只需通过整个数据集一次而不是通过 整个数据集两次?
回答 :您可以在scala中使用Map返回类型...
限制:如果您使用With Column,则为此udf 列名是
ruleIDandRuleName
,那么您可以使用单个功能 使用Map数据类型或spark sql列的任何可接受数据类型。 其他明智的你不能使用下面提到的方法
显示在以下示例代码段
中 def ruleNameAndruleId = udf((product : String) => {
if(Seq("A", "B").contains(product)) Map("ruleName"->"ABC","ruleId"->"123")
else if(Seq("A", "B", "D").contains(product)) (Map("ruleName"->"DEF","ruleId"->"456")
else (Map("ruleName"->"","ruleId"->"") })
来电者将
df.withColumn("ruleIDandRuleName",ruleNameAndruleId(product here) ) // ruleNameAndruleId will return a map containing rulename and rule id
答案 1 :(得分:1)
您的解决方案的替代方案是使用udf
函数。它与when
函数几乎相似,都需要serialization
和deserialization
。它可以帮助您测试哪种更快更有效。
def rule_name = udf((product : String) => {
if(Seq("A", "B").contains(product)) "ABC"
else if(Seq("A", "B", "D").contains(product)) "DEF"
else ""
})
def rule_id = udf((product : String) => {
if(Seq("A", "B").contains(product)) "123"
else if(Seq("A", "B", "D").contains(product)) "456"
else ""
})
val df1 = df_customers.withColumn("rule_name" , rule_name(col("product"))).withColumn("rule_id" , rule_id(col("product")))
df1.show()