簡體   English   中英

自定義TypeConverters使用spark cassandra連接器

[英]Custom TypeConverters using spark cassandra connector

我使用spark cassandra連接器編寫了一個應用程序。 現在,當spark-submit工作時我得到錯誤java.lang.IllegalArgumentException:要求失敗:在類:MailBox中找不到可映射的屬性 ,即使我定義了https://github.com/datastax/中指定的類型轉換器spark-cassandra-connector / blob / master / doc / 6_advanced_mapper.md ,我的想法是我需要一個MailBox的伴隨對象,我在其中定義一個mapper,但我在doc中找不到它的例子。 有誰知道如何解決這個問題? 謝謝

代碼

object Test {
  case class Size(size: Long) {
    if (size < 0) throw new IllegalArgumentException
    def +(s: Size): Size = Size(size + s.size)
  }

  object LongToSizeConverter extends TypeConverter[Size] {
    def targetTypeTag = typeTag[Size]
    def convertPF = { case long: Long => Size(long)  }
  }
  object SizeToLongConverter extends TypeConverter[Long] {
    def targetTypeTag = typeTag[Long]
    def convertPF = { case Size(long) => long.toLong }
  }
  case class MailBox(id: String,totalsize: Size)
  case class Id(mailboxid:String) 
  object StringToIdConverter extends TypeConverter[Id] {
    def targetTypeTag = typeTag[Id]
    def convertPF = { case str: String => Id(str) 
                      case str: UUID => Id(str.toString)  }
  }
  object IdToStringConverter extends TypeConverter[String] {
    def targetTypeTag = typeTag[String]
    def convertPF = { case Id(str) => str.toString }
  }

  def main(args: Array[String]) {
    val sc = new SparkContext();
    TypeConverter.registerConverter(StringToIdConverter)
    TypeConverter.registerConverter(IdToStringConverter)
    TypeConverter.registerConverter(LongToSizeConverter)
    TypeConverter.registerConverter(SizeToLongConverter)
    val test= sc.parallelize(Array(MailBox(Id("1"),Size(10))))
    test.saveAsCassandraTable("test","Mailbox")
  }
}

首先讓我發布一個快速工作的例子,然后我將解決出錯的問題

package com.datastax.spark.example

import com.datastax.spark.connector._
import org.apache.spark.{SparkConf, SparkContext}
import com.datastax.spark.connector.types._
import scala.reflect.runtime.universe._
import java.util.UUID

import org.apache.spark.sql.catalyst.ReflectionLock.SparkReflectionLock

case class Size(size: Long) {
    if (size < 0) throw new IllegalArgumentException
    def +(s: Size): Size = Size(size + s.size)
}
case class MailBox(id: Id,totalsize: Size)
case class Id(mailboxid:String)



object Test {

    val LongTypeTag = SparkReflectionLock.synchronized {
            implicitly[TypeTag[java.lang.Long]]
    }
    val SizeTypeTag = SparkReflectionLock.synchronized {
            typeTag[Size]
    }
    val IdTypeTag = SparkReflectionLock.synchronized {
            typeTag[Id]
    }
    val StringTypeTag = SparkReflectionLock.synchronized {
            implicitly[TypeTag[String]]
    }

    object LongToSizeConverter extends TypeConverter[Size] {
        def targetTypeTag = SizeTypeTag
        def convertPF = { case long: Long => Size(long)  }
    }
    object LongToSizeConverter extends TypeConverter[Size] {
        def targetTypeTag = SizeTypeTag
        def convertPF = { case long: Long => Size(long)  }
    }

    object SizeToLongConverter extends TypeConverter[java.lang.Long] {
        def targetTypeTag = LongTypeTag
        def convertPF = { case Size(long) => long.toLong }
    }

    object StringToIdConverter extends TypeConverter[Id] {
        def targetTypeTag = IdTypeTag
        def convertPF = { 
            case str: String => Id(str)
            case str: UUID => Id(str.toString)
        }
    }

    object IdToStringConverter extends TypeConverter[String] {
        def targetTypeTag = StringTypeTag
        def convertPF = { case Id(str) => str.toString }
    }

    TypeConverter.registerConverter(StringToIdConverter)
    TypeConverter.registerConverter(IdToStringConverter)
    TypeConverter.registerConverter(LongToSizeConverter)
    TypeConverter.registerConverter(SizeToLongConverter)


    def main(args: Array[String]) {
        val sc = new SparkContext();
        val test = sc.parallelize(Array(MailBox(Id("1"),Size(10))))
        test.saveToCassandra("ks","mailbox")
    }
}

saveAsCassandraTable不適用於自定義類型

saveAsCassandraTable使用fromType方法,該方法需要已知類型(不是自定義類型)。 這是因為saveAsCassandraTable基於已知的字段類型創建Cassandra列。 使用自定義類型轉換器時,您不會明確說明類型與Cassandra列之間的(1到1)映射,因此無法查找它。 由於saveAsCassandraTable在插入之前創建了Cassandra表,因此它不知道如何制作表。

為了解決這個問題,我們更改了一行

test.saveAsCassandraTable("test","Mailbox")

test.saveToCassandraTable("test","Mailbox")

我們在CQLSH中預先制作了表格,但您也可以使用應用程序中的Java驅動程序來完成此操作。

我們需要轉換為Java類型

TypeConverter鏈接不適用於自定義類型轉換器。 這意味着我們需要提供從Custom類型到Java類型的轉換器。 為此,我改變了SizeToLong轉換器

object SizeToLongConverter extends TypeConverter[java.lang.Long] {

我們應該反對Scala反思缺乏線程安全

我添加了synchronized塊(使用SparkReflectionLock)以確保我們不會遇到任何問題。

看到

SparkReflectionLock.synchronized

我們需要在對象級別進行注冊

為了確保我們的注冊發生在執行程序JVM上,我將它們移出“主”范圍。 我不確定這有多重要,但最好反映這應該發生在代碼發送到的地方,而不僅僅是在main方法中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM