次のサンプルコードは、いくつかのケースオブジェクトをデータフレームに配置しようとします。コードには、この特性を使用したケースオブジェクト階層とケースクラスの定義が含まれています。
import org.Apache.spark.{SparkContext, SparkConf}
import org.Apache.spark.sql.SQLContext
sealed trait Some
case object AType extends Some
case object BType extends Some
case class Data( name : String, t: Some)
object Example {
def main(args: Array[String]) : Unit = {
val conf = new SparkConf()
.setAppName( "Example" )
.setMaster( "local[*]")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
import sqlContext.implicits._
val df = sc.parallelize( Seq( Data( "a", AType), Data( "b", BType) ), 4).toDF()
df.show()
}
}
コードを実行すると、残念ながら次の例外が発生します。
Java.lang.UnsupportedOperationException: Schema for type Some is not supported
Some
型)のスキーマを追加または定義する可能性はありますか?Enumeration
を直接使用しようとしましたが、成功しませんでした。 (下記参照)Enumeration
のコード:
object Some extends Enumeration {
type Some = Value
val AType, BType = Value
}
前もって感謝します。最善のアプローチは、代わりに文字列を使用しないことです。
Spark 2.0.0 +:
UserDefinedType
はSpark 2.0.0で非公開になり、今のところDataset
に優しい代替物はありません。
参照: SPARK-14155(Spark 2.0)のUserDefinedTypeを非表示)
ほとんどの場合、静的に型指定されたDataset
は置換として機能します。保留中のJira SPARK-7768 があり、ターゲットバージョン2.4でUDT APIを再び公開します。
データセットにカスタムオブジェクトを保存する方法? も参照してください
スパーク<2.0.0
特定のタイプ(ここではタイプSome)のスキーマを追加または定義する可能性はありますか?
答えは、どれほどひどくこれを必要とするかによると思います。 UserDefinedType
を作成することは可能に見えますが、DeveloperApi
へのアクセスが必要であり、正確であるか、十分に文書化されていません。
import org.Apache.spark.sql.types._
@SQLUserDefinedType(udt = classOf[SomeUDT])
sealed trait Some
case object AType extends Some
case object BType extends Some
class SomeUDT extends UserDefinedType[Some] {
override def sqlType: DataType = IntegerType
override def serialize(obj: Any) = {
obj match {
case AType => 0
case BType => 1
}
}
override def deserialize(datum: Any): Some = {
datum match {
case 0 => AType
case 1 => BType
}
}
override def userClass: Class[Some] = classOf[Some]
}
おそらくhashCode
とequals
もオーバーライドする必要があります。
PySparkのカウンターパートは次のようになります。
from enum import Enum, unique
from pyspark.sql.types import UserDefinedType, IntegerType
class SomeUDT(UserDefinedType):
@classmethod
def sqlType(self):
return IntegerType()
@classmethod
def module(cls):
return cls.__module__
@classmethod
def scalaUDT(cls): # Required in Spark < 1.5
return 'net.zero323.enum.SomeUDT'
def serialize(self, obj):
return obj.value
def deserialize(self, datum):
return {x.value: x for x in Some}[datum]
@unique
class Some(Enum):
__UDT__ = SomeUDT()
AType = 0
BType = 1
In Spark <1.5 Python UDTにはペアのScala UDTが必要ですが、それはもはやそうではないようです1.5。
単純なUDTの場合、単純な型を使用できます(たとえば、IntegerType
全体ではなくStruct
)。