根据规则在Spark数据框中添加列

时间:2017-06-03 15:43:08

标签: scala apache-spark apache-spark-sql

我有一个数据帧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

有没有更好的方法来实现它,通过遍历整个数据集一次而不是遍历整个数据集两次来添加两列?

2 个答案:

答案 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函数几乎相似,都需要serializationdeserialization。它可以帮助您测试哪种更快更有效。

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()