簡體   English   中英

在 Scala 中,通過 List[String] 過濾 Spark Cassandra RDD 的正確方法是什么?

[英]In Scala, What is correct way to filter Spark Cassandra RDD by a List[String]?

我有一個字符串格式的 id 列表,這個列表大約有 20,000 個 id 長:

var timelineIds = source.map(a => a.timelineid);
timelineIds = timelineIds.distinct.cache; // disticnt list we need this for later
var timelineIdsString = timelineIds.map(a => a.asInstanceOf[String]).collect.toList;

當我對我的 cassandra 表之一使用此列表時,它工作得很好,無論timelineIdsString 的大小:

var timelineHistorySource = sc.cassandraTable[Timeline]("acd", "timeline_history_bytimelineid")
        .select("ownerid", "userid", "timelineid", "timelinetype", "starttime", "endtime", "attributes", "states")
if (constrain)
    timelineHistorySource = timelineHistorySource.where("timelineid IN ?", timelineIdsString)

當我對我的另一個表執行此操作時,當我在列表中有超過 1000 個 id 時,它永遠不會完成:

var dispositionSource = sc.cassandraTable[DispositionSource]("acd","dispositions_bytimelineid")
            .select("ownerid","dispositionid","month","timelineid","createddate","createduserid")
if(constrain)
    dispositionSource = dispositionSource.where("timelineid IN ?", timelineIdsString);

兩個 cassandra 表都將鍵作為時間線,所以我知道它是正確的。 只要timelineids 是一個小列表,此代碼就可以正常工作。

有沒有更好的方法從 cassandra RDD 過濾? 是否是導致它窒息的 IN 子句的大小?

您可以嘗試將 ID 列表保留為 dataframe、 timelineIds和基於時間timelineid的內部連接表。 然后從生成的 df 中刪除不必要的列 ( timelineIds.timelineid )。

與其在 Spark 級別執行連接,不如使用 Cassandra 本身執行連接 - 在這種情況下,您將從 Cassandra 僅讀取必要的數據(假設連接鍵是分區或主鍵)。 對於 RDD,這可以通過.joinWithCassandraTable function ( doc ) 來完成:

import com.datastax.spark.connector._

val toJoin = sc.parallelize(1 until 5).map(x => Tuple1(x.toInt))
val joined = toJoin.joinWithCassandraTable("test", "jtest1")
  .on(SomeColumns("pk"))

scala> joined.toDebugString
res21: String =
(8) CassandraJoinRDD[150] at RDD at CassandraRDD.scala:18 []
 |  ParallelCollectionRDD[147] at parallelize at <console>:33 []

對於 Dataframes,它被稱為直接連接,自 SCC 2.5 起可用(請參閱公告)-您需要傳遞一些配置以啟用它,請參閱文檔:

import spark.implicits._
import org.apache.spark.sql.cassandra._

val cassdata = spark.read.cassandraFormat("jtest1", "test").load

val toJoin = spark.range(1, 5).select($"id".cast("int").as("id"))
val joined = toJoin.join(cassdata, cassdata("pk") === toJoin("id"))

scala> joined.explain
== Physical Plan ==
Cassandra Direct Join [pk = id#2] test.jtest1 - Reading (pk, c1, c2, v) Pushed {}
+- *(1) Project [cast(id#0L as int) AS id#2]
   +- *(1) Range (1, 5, step=1, splits=8)

我有一篇關於與 Cassandra 連接的相當長而詳細的博客文章- 查看更多詳細信息。

暫無
暫無

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

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