2016-04-26 17 views
0

Ich habe eine Spalte in einer Tabelle Hive:Wie wird Array [Struct [String, String]] in Hive to Array [Map [String, String]] umgewandelt?

Spaltenname: Filter

Daten-Typ:

|-- filters: array (nullable = true) 
| |-- element: struct (containsNull = true) 
| | |-- name: string (nullable = true) 
| | |-- value: string (nullable = true) 

Ich möchte den Wert aus dieser Spalte erhalten, indem sie Namen entsprechend ist.

Was ich bisher tat:

val sdf: DataFrame = sqlContext.sql("select * from <tablename> where id='12345'") 

val sdfFilters = sdf.select("filters").rdd.map(r => r(0).asInstanceOf[Seq[(String,String)]]).collect() 

Output: sdfFilters: Array[Seq[(String, String)]] = Array(WrappedArray([filter_RISKFACTOR,OIS.SPD.*], [filter_AGGCODE,IR]), WrappedArray([filter_AGGCODE,IR_])) 

Hinweis: Casting Seq weil WrappedArray Umstellung auf Karte ist nicht möglich.

Was nun zu tun?

Antwort

1
I want to get the value from this column by it's corresponding name. 

Wenn Sie eine einfache und zuverlässige Art und Weise möchten alle Werte von Namen zu erhalten, können Sie Ihre Tabelle abflachen und Filter explodieren mit:

case class Data(name: String, value: String) 
case class Filters(filters: Array[Data]) 

val df = sqlContext.createDataFrame(Seq(Filters(Array(Data("a", "b"), Data("a", "c"))), Filters(Array(Data("b", "c"))))) 
df.show() 
+--------------+ 
|  filters| 
+--------------+ 
|[[a,b], [a,c]]| 
|  [[b,c]]| 
+--------------+ 

df.withColumn("filter", explode($"filters")) 
    .select($"filter.name" as "name", $"filter.value" as "value") 
    .where($"name" === "a") 
    .show() 
+----+-----+ 
|name|value| 
+----+-----+ 
| a| b| 
| a| c| 
+----+-----+ 

Sie Ihre Daten auch jede mögliche Weise sammeln können Sie wollen :

val flatDf = df.withColumn("filter", explode($"filters")).select($"filter.name" as "name", $"filter.value" as "value") 
flatDf.rdd.map(r => Array(r(0), r(1))).collect() 
res0: Array[Array[Any]] = Array(Array(a, b), Array(a, c), Array(b, c)) 
flatDf.rdd.map(r => r(0) -> r(1)).groupByKey().collect() //not the best idea, if you have many values per key 
res1: Array[(Any, Iterable[Any])] = Array((b,CompactBuffer(c)), (a,CompactBuffer(b, c))) 

Wenn Sie array[struct]-map[string, string] für zukünftige Einsparung bis zu einem gewissen Lagerung werfen wollen - ist es anders s tory, und dieser Fall wird besser von UDF gelöst. Wie auch immer, Sie müssen collect() so lange wie möglich vermeiden, um Ihren Code skalierbar zu halten.

+0

Ich möchte die Werte b und c als Sequenz oder Array von String nicht als Zeilenobjekt erhalten. –

+0

Funktioniert das? –

+0

Ich habe die Antwort aktualisiert –