2016-01-27 93 views
1

我試圖通過DataFrames從嵌套JSON獲取列名稱。下面的架構給出:Spark獲取嵌套json的列名稱

root 
|-- body: struct (nullable = true) 
| |-- Sw1: string (nullable = true) 
| |-- Sw2: string (nullable = true) 
| |-- Sw3: string (nullable = true) 
| |-- Sw420: string (nullable = true) 
|-- headers: struct (nullable = true) 
| |-- endDate: string (nullable = true) 
| |-- file: string (nullable = true) 
| |-- startDate: string (nullable = true) 

我可以得到列名「體」和「頭」與df.columns(),但是當我試圖讓從身體(列名前:SW1,SW2 ,...)與df.select(「body」)。列總是給我身體專欄。

有什麼建議嗎? :)

回答

5

如果問題是如何找到嵌套的列名,您可以通過檢查數據框的schema做到這一點。模式表示爲StructType,其中可以包含其他DataType對象(包含其他嵌套結構)的字段。如果你想發現所有的領域,你必須遞歸地走這棵樹。例如:

import org.apache.spark.sql.types._ 
def findFields(path: String, dt: DataType): Unit = dt match { 
    case s: StructType => 
    s.fields.foreach(f => findFields(path + "." + f.name, f.dataType)) 
    case other => 
    println(s"$path: $other") 
} 

該走的樹,並打印出所有的葉子字段及其類型:

val df = sqlContext.read.json(sc.parallelize("""{"a": {"b": 1}}""" :: Nil)) 
findFields("", df.schema) 

prints: .a.b: LongType 
+0

謝謝邁克爾。它會幫助我很多,但我使用的是java。你有任何想法在java中做到這一點?我對scala感到不舒服... –

+0

所以我嘗試在java中做到這一點。如果我理解你的代碼,你可以在StructTypes上使用方法fields(),然後在fields()返回的每個StructTypes上使用findFields()。使用Java API,如果我在StructType上使用fields(),它將返回一個FieldType,所以我無法在其上使用findFields ... –

+0

好吧,我成功地從body獲取列值。我只需要將我的StructField轉換爲DataType,然後調用它的fields()。非常感謝邁克爾:) –

0

很簡單:df.select("body.Sw1", "body.Sw2")

+0

我不想指定「Sw1」和「Sw2」手動。這個想法是以編程方式獲取列值(Sw1,Sw2,...)並將這些列名稱迭代以進行選擇。 –

0

要得到嵌套的列名,請使用如下代碼如下:

從主方法調用象下面這樣:

findFields(df,df.schema) 

方法:

def findFields(df:DataFrame,dt: DataType) = 
{ 
    val fieldName = dt.asInstanceOf[StructType].fields 
    for (value <- fieldName) 
    { 
     val colNames = value.productElement(1).asInstanceOf[StructType].fields 
     for (f <- colNames) 
     { 
     println("Inner Columns of "+value.name+" -->>"+f.name) 
     } 
    } 

}

注意:這隻會工作,當兩個第一組列的結構類型。