Scala spark kafka代码 - 功能方法

时间:2018-01-02 10:58:31

标签: scala unit-testing functional-programming apache-kafka

我在scala中有以下代码。我使用spark sql从hadoop中提取数据,在结果上执行一些组,序列化它然后将该消息写入Kafka。

我已经编写了代码 - 但我想以功能方式编写代码。我应该创建一个功能'getCategories'的新类来从Hadoop获取类别吗?我不知道如何处理这个问题。

这是代码

class ExtractProcessor {
  def process(): Unit = {

  implicit val formats = DefaultFormats

  val spark = SparkSession.builder().appName("test app").getOrCreate()

  try {
     val df = spark.sql("SELECT DISTINCT SUBCAT_CODE, SUBCAT_NAME, CAT_CODE, CAT_NAME " +
    "FROM CATEGORY_HIERARCHY " +
    "ORDER BY CAT_CODE, SUBCAT_CODE ")

     val result = df.collect().groupBy(row => (row(2), row(3)))
     val categories = result.map(cat =>
                    category(cat._1._1.toString(), cat._1._2.toString(),
                      cat._2.map(subcat =>
                      subcategory(subcat(0).toString(), subcat(1).toString())).toList))

     val jsonMessage = write(categories)
     val kafkaKey = java.security.MessageDigest.getInstance("SHA-1").digest(jsonMessage.getBytes("UTF-8")).map("%02x".format(_)).mkString.toString()
     val key = write(kafkaKey)

     Logger.log.info(s"Json Message: ${jsonMessage}")
     Logger.log.info(s"Kafka Key: ${key}")

     KafkaUtil.apply.send(key, jsonMessage, "testTopic")      
}

这是卡夫卡代码

class KafkaUtil {
  def send(key: String, message: String, topicName: String): Unit = {
  val properties = new Properties()
  properties.put("bootstrap.servers", "localhost:9092")
  properties.put("client.id", "test publisher")
  properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer")
  properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer")
  val producer = new KafkaProducer[String, String](properties)

  try {

    val record = new ProducerRecord[String, String](topicName, key, message)
    producer.send(record)
  }
  finally {
    producer.close()
    Logger.log.info("Kafka producer closed...")
  }
 }
}

object KafkaUtil {
  def apply: KafkaUtil = {
  new KafkaUtil
 }
}

另外,对于编写单元测试,我应该在功能方法中测试什么。在OOP中,我们对业务逻辑进行单元测试,但在我的scala代码中几乎没有任何业务逻辑。

感谢任何帮助。

提前致谢, Suyog

1 个答案:

答案 0 :(得分:1)

您的代码包含 1)将数据加载到spark df中 2)处理数据 3)创建json消息 4)将json消息发送到kafka

单元测试适用于测试纯函数。 您可以将步骤2)提取到具有签名的方法中 def getCategories(df: DataFrame): Seq[Category]并通过测试覆盖它。 在测试数据帧中,将仅从简单的硬编码内存序列生成。

步骤3)也可以通过单元测试覆盖,如果您觉得它容易出错

步骤1)4)将由端到端测试涵盖

顺便说一下 val result = df.collect().groupBy(row => (row(2), row(3)))效率低下。最好用val result = df.groupBy(row => (row(2), row(3))).collect

替换它

此外,无需为每条消息单独初始化KafkaProducer。