2016-09-17 58 views
1

我與結構的蜂巢表:如何從字符串中創建數據框鍵=由「;」分隔的值

enter image description here

我需要閱讀的字符串場,打破了鍵,變成一個蜂箱表列,最終的表應該是這樣的:

enter image description here

非常重要的,關鍵的字符串中的數字是動態的,按鍵的名稱也是動態的

嘗試使用spark SQL讀取字符串,根據所有字符串創建一個schema架構並使用saveAsTable()函數轉換數據幀配置表,但不知道如何執行此操作

有什麼建議嗎?

+1

有多遠你就分裂了分號鍵和值得到? –

+0

目前使用蜂巢式查詢,但速度很慢。 –

回答

1

一個天真的(假設獨特(code, date)組合和沒有嵌入string=;)可以是這樣的:

import org.apache.spark.sql.functions.{explode, split} 

val df = Seq(
    (1, 1, "key1=value11;key2=value12;key3=value13;key4=value14"), 
    (1, 2, "key1=value21;key2=value22;key3=value23;key4=value24"), 
    (2, 4, "key3=value33;key4=value34;key5=value35") 
).toDF("code", "date", "string") 

val bits = split($"string", ";") 
val kv = split($"pair", "=") 

df 
    .withColumn("bits", bits) // Split column by `;` 
    .withColumn("pair", explode($"bits")) // Explode into multiple rows 
    .withColumn("key", kv(0)) // Extract key 
    .withColumn("val", kv(1)) // Extract value 
    // Pivot to wide format 
    .groupBy("code", "date") 
    .pivot("key") 
    .agg(first("val")) 

// +----+----+-------+-------+-------+-------+-------+ 
// |code|date| key1| key2| key3| key4| key5| 
// +----+----+-------+-------+-------+-------+-------+ 
// | 1| 2|value21|value22|value23|value24| null| 
// | 1| 1|value11|value12|value13|value14| null| 
// | 2| 4| null| null|value33|value34|value35| 
// +----+----+-------+-------+-------+-------+-------+ 

這可以很容易地調整處理的情況下(code, date)不是唯一的,你可以使用UDF處理更復雜的string模式。

根據您使用的語言和列數,您可能更適合使用RDDDataset。還有一個值得考慮的是放棄全部的explode/pivot以支持UDF。

val parse = udf((text: String) => text.split(";").map(_.split("=")).collect { 
    case Array(k, v) => (k, v) 
}.toMap) 

val keys = udf((pairs: Map[String, String]) => pairs.keys.toList) 

// Parse strings to Map[String, String] 
val withKVs = df.withColumn("kvs", parse($"string")) 

val keys = withKVs 
    .select(explode(keys($"kvs"))).distinct // Get unique keys 
    .as[String] 
    .collect.sorted.toList // Collect and sort 

// Build a list of expressions for subsequent select 
val exprs = keys.map(key => $"kvs".getItem(key).alias(key)) 

withKVs.select($"code" :: $"date" :: exprs: _*) 

在星火1.5,你可以嘗試:

val keys = withKVs.select($"kvs").rdd 
    .flatMap(_.getAs[Map[String, String]]("kvs").keys) 
    .distinct 
    .collect.sorted.toList 
+0

不幸的是我使用的是spark 1.5,並且pivot函數不可用,否則不會使用它? –

+0

用RDD替換'Dataset'後的第二種方法應該很好。 – zero323

+0

.select不適用於RDD,我必須更改? –

相關問題