查询每个Kafka消息的Cassandra表

时间:2018-03-14 09:00:28

标签: scala apache-spark cassandra apache-kafka spark-cassandra-connector

我正在尝试查询每张kafka消息的cassandra表。

以下是我一直在处理的代码:

 def main(args: Array[String]) {
 val spark = SparkSession
  .builder()
  .master("local[*]")
  .appName("Spark SQL basic example")
  .config("spark.cassandra.connection.host", "localhost")
  .config("spark.cassandra.connection.port", "9042")
  .getOrCreate()

val topicsSet = List("Test").toSet
val kafkaParams = Map[String, Object](
          "bootstrap.servers" -> "localhost:9092",
          "key.deserializer" -> classOf[StringDeserializer],
          "value.deserializer" -> classOf[StringDeserializer],
          "group.id" -> "12345",
          "auto.offset.reset" -> "latest",
          "enable.auto.commit" -> (false: java.lang.Boolean)
          )
val messages = KafkaUtils.createDirectStream[String, String](
  ssc,
  LocationStrategies.PreferConsistent,
  ConsumerStrategies.Subscribe[String, String](topicsSet, kafkaParams))

val lines = messages.map(_.value)

val lines_myobjects = lines.map(line =>
  new Gson().fromJson(line, classOf[myClass]) // The myClass is a simple case class which extends serializable
//This changes every single message into an object
)

现在事情变得复杂了,我无法解决我可以查询cassandra表与kafka消息中的消息相关的问题。每个kafka消息对象都有一个返回方法。

我尝试了多种方法来解决这个问题。例如:

val transformed_data = lines_myobjects.map(myobject => {
   val forest = spark.read
    .format("org.apache.spark.sql.cassandra")
    .options(Map( "table" -> "mytable", "keyspace" -> "mydb"))
    .load()
    .filter("userid='" + myobject.getuserId + "'")
)}

我也试过ssc.cassandraTable但没有给我带来好运。

主要目标是从userid匹配的数据库中获取所有来自kafka消息的用户ID的行。

我想提到的一件事是,即使每次加载或查询cassandra数据库效率都不高,cassandra数据库每次都会更改。

2 个答案:

答案 0 :(得分:2)

您无法在spark.read内执行ssc.cassandraTable.map(。因为这意味着您将尝试为每条消息创建新的RDD。它不应该那样工作。

请提出以下选项:

1 - 如果您可以通过一个/两个CQL查询询问所需数据,请尝试在.mapPartitions(内使用CassandraConnector。像这样:

import com.datastax.spark.connector._
import com.datastax.spark.connector.cql._

val connector = ...instantiate CassandraConnector onece here
val transformed_data = lines_myobjects.mapPartitions(it => {
   connector.withSessionDo { session =>
       it.map(myobject => session.execute("CQL QUERY TO GET YOUR DATA HERE", myobject.getuserId)
})

2 - 否则(如果您按主/分区键选择)考虑.joinWithCassandraTable。像这样:

import com.datastax.spark.connector._

val mytableRDD = sc.cassandraTable("mydb", "mytable")
val transformed_data = lines_myobjects
    .map(myobject => {
       Tuple1(myobject.getuserId) // you need to wrap ids to a tuple to do join with Cassandra
    })
    .joinWithCassandraTable("mydb", "mytable")
    // process results here

答案 1 :(得分:1)

我会以不同的方式接近这一点。 流入Cassandra的数据,通过Kafka(以及从Kafka发送到带有Kafka Connect sink的Cassandra)。 利用Kafka中的数据,您可以在您的数据流之间加入,无论是在Spark中,还是在Kafka的Streams API或KSQL中。 Kafka Streams和KSQL都支持您在此处执行的流表连接。您可以使用KSQL herehere来查看它。