2016-09-11 3 views
3

중첩 필드가있는 기존 데이터 프레임의 스키마를 병합하려고합니다. 내 데이터 프레임의 구조는 다음과 같습니다.apache에서 배열 분해 Explark 데이터 프레임

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 개의 행에 type이 null이고 3 개의 type이 null이 아닌 경우, 결과 데이터 프레임에서 explode를 사용한 후에 단 3 개의 행을 가짐을 의미합니다.

행을 null 값으로 유지하면서 값 배열을 폭발시킬 수 있습니까?

몇 가지 해결 방법이 있지만 한 곳에서 계속 붙어 있습니다.

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. 측면보기를 사용하려고했지만 결과는 같습니다.

답변

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