簡體   English   中英

Spark:對RDD中的高效質量查找

[英]Spark: Efficient mass lookup in pair RDD's

在Apache Spark中我有兩個RDD。 第一個data : RDD[(K,V)]包含鍵值形式的數據。 第二pairs : RDD[(K,K)]包含一組有趣的數據密鑰對。

如何有效地構造RDD對與pairsWithData : RDD[((K,K)),(V,V))] ,使得它包含來自pairs所有元素作為鍵元組及其對應的值(來自data )as價值元組?

數據的一些屬性:

  • data中的鍵是唯一的
  • pairs所有條目都是唯一的
  • 對於所有對(k1,k2)pairs可以保證k1 <= k2
  • “對”的大小只是數據|pairs| = O(|data|)的大小的常量 |pairs| = O(|data|)
  • 當前數據大小(預計會增長): |data| ~ 10^8, |pairs| ~ 10^10 |data| ~ 10^8, |pairs| ~ 10^10

目前的嘗試

以下是Scala中的一些示例代碼:

import org.apache.spark.rdd.RDD
import org.apache.spark.SparkContext._

// This kind of show the idea, but fails at runtime.
def massPairLookup1(keyPairs : RDD[(Int, Int)], data : RDD[(Int, String)]) = {
  keyPairs map {case (k1,k2) =>
    val v1 : String = data lookup k1 head;
    val v2 : String = data lookup k2 head;
    ((k1, k2), (v1,v2))
  }
}

// Works but is O(|data|^2)
def massPairLookup2(keyPairs : RDD[(Int, Int)], data : RDD[(Int, String)]) = {
  // Construct all possible pairs of values
  val cartesianData = data cartesian data map {case((k1,v1),(k2,v2)) => ((k1,k2),(v1,v2))}
  // Select only the values who's keys are in keyPairs
  keyPairs map {(_,0)} join cartesianData mapValues {_._2}
}

// Example function that find pairs of keys
// Runs in O(|data|) in real life, but cannot maintain the values
def relevantPairs(data : RDD[(Int, String)]) = {
  val keys = data map (_._1)
  keys cartesian keys filter {case (x,y) => x*y == 12 && x < y}
}

// Example run
val data = sc parallelize(1 to 12) map (x => (x, "Number " + x))
val pairs = relevantPairs(data)
val pairsWithData = massPairLookup2(pairs, data) 


// Print: 
// ((1,12),(Number1,Number12))
// ((2,6),(Number2,Number6))
// ((3,4),(Number3,Number4))
pairsWithData.foreach(println)

嘗試1

首先,我嘗試在data上使用lookup函數,但在執行時會拋出運行時錯誤。 好像self是在空PairRDDFunctions特征。

另外我不確定lookup的性能。 文檔如果RDD通過僅搜索鍵映射到的分區而具有已知分區器,則此操作有效地完成。 這聽起來像n查找最多需要O(n * |分區|)時間,我懷疑可以優化。

嘗試2

這種嘗試有效,但我創建了|data|^2對會破壞性能。 我不希望Spark能夠優化它。

您的查找1不起作用,因為您無法在工作者內部執行RDD轉換(在另一個轉換中)。

在查找2中,我認為沒有必要執行完整的笛卡爾...

你可以這樣做:

val firstjoin = pairs.map({case (k1,k2) => (k1, (k1,k2))})
    .join(data)
    .map({case (_, ((k1, k2), v1)) => ((k1, k2), v1)})
val result = firstjoin.map({case ((k1,k2),v1) => (k2, ((k1,k2),v1))})
    .join(data)
    .map({case(_, (((k1,k2), v1), v2))=>((k1, k2), (v1, v2))})

或者以更密集的形式:

    val firstjoin = pairs.map(x => (x._1, x)).join(data).map(_._2)
    val result = firstjoin.map({case (x,y) => (x._2, (x,y))})
        .join(data).map({case(x, (y, z))=>(y._1, (y._2, z))})

我認為你不能更有效地做到這一點,但我可能錯了......

暫無
暫無

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

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