2016-09-11 4 views
3

入れ子フィールドを持つ既存のデータフレームのスキーマを平坦化しようとしています。私のデータフレームの構造は、そのようなものです:apacheで配列を爆発させるデータフレーム

root 
|-- Id: long (nullable = true) 
|-- Type: string (nullable = true) 
|-- Uri: string (nullable = true)  
|-- Type: array (nullable = true) 
| |-- element: string (containsNull = true) 
|-- Gender: array (nullable = true) 
| |-- element: string (containsNull = true) 

タイプと性別は、要素の配列、一つの要素はnull値を含めることができます。

var resDf = df.withColumn("FlatType", explode(df("Type"))) 

しかし、私はタイプ列のNULL値を有していたの行を失う結果のデータフレーム内の結果として: 私は次のコードを使用しようとしました。たとえば、10行あり、7行の型がnullで、3型がnullでない場合、結果のデータフレームでexplodeを使用した後、3行しか持たないということです。

null値を持つ行を保持するが、値の配列を爆発させるにはどうすればよいですか?

私はいくつかの種類の回避策を見つけましたが、依然として1か所に詰まっています。標準タイプのために我々は、以下の操作を行うことができます。

def customExplode(df: DataFrame, field: String, colType: String): org.apache.spark.sql.Column = { 
var exploded = None: Option[org.apache.spark.sql.Column] 
colType.toLowerCase() match { 
    case "string" => 
    val avoidNull = udf((column: Seq[String]) => 
    if (column == null) Seq[String](null) 
    else column) 
    exploded = Some(explode(avoidNull(df(field)))) 
    case "boolean" => 
    val avoidNull = udf((xs: Seq[Boolean]) => 
    if (xs == null) Seq[Boolean]() 
    else xs) 
    exploded = Some(explode(avoidNull(df(field)))) 
    case _ => exploded = Some(explode(df(field))) 
} 
exploded.get 

}

そして、それだけでこのようにそれを使用した後:

val explodedField = customExplode(resultDf, fieldName, fieldTypeMap(field)) 
resultDf = resultDf.withColumn(newName, explodedField) 

しかし、私は次のタイプのための構造体型のために問題を抱えているが構造体:

|-- Address: array (nullable = true) 
| |-- element: struct (containsNull = true) 
| | |-- AddressType: array (nullable = true) 
| | | |-- element: string (containsNull = true) 
| | |-- DEA: array (nullable = true) 
| | | |-- element: struct (containsNull = true) 
| | | | |-- Number: array (nullable = true) 
| | | | | |-- element: string (containsNull = true) 
| | | | |-- ExpirationDate: array (nullable = true) 
| | | | | |-- element: timestamp (containsNull = true) 
| | | | |-- Status: array (nullable = true) 
| | | | | |-- element: string (containsNull = true) 

DEAがnullの場合、どのようにこの種のスキーマを処理できますか?

ありがとうございます。

P.S.ラテラルビューを使用しようとしましたが、結果は同じです。

答えて

1

たぶん、あなたはwhenを使用して試すことができます:

when機能の documentationに示すように
val resDf = df.withColumn("FlatType", when(df("Type").isNotNull, explode(df("Type"))) 

は、値nullは、条件に一致しない値のために挿入されています。

+0

申し訳ありませんが、このソリューションを試すと、次の例外があります:java.lang.UnsupportedOperationException。私がexplode(df( "Type"))をちょうどある値で置き換えると、うまく動作します。私は関数が値として – Artem

+0

@Artemとして分解された列をサポートしていないと思います、あなたは正しいです、残念です。あなたのために「組合」は選択肢ですか? unionAll(df.withColumn( "FlatType"、explode($ "Type"))) ' –

+0

yes 'を指定すると、df.where($" Type ".isNull).withColumn(" FlatType "、lit(null) 、ありがとう、私はこのオプションについて考えましたが、私はスキーマを平坦化するための汎用アルゴリズムを構築していて、私は組合が本当に遅いかもしれないと恐れています。私はよりよい解決策を見いだすことを望むが、組合は私のバックアップオプションである。 – Artem

関連する問題