IndexedRDD 源碼解讀一

1. IndexedRDDPartion構建過程

  • 調用構建函數
    val vp = IndexedRDDPartition(Iterator((0L, 1), (1L, 1)))
  • 這裏會調用IndexedRDDPartition 的apply 方法。
    def apply[V: ClassTag](iter: Iterator[(Id, V)]): IndexedRDDPartition[V] = { 
        // 申請PrimitiveKeyOpenHashMap的hash表  
        val map = new PrimitiveKeyOpenHashMap[Id, V]

        // 將iter數據寫入hash表中
        iter.foreach { pair =>
            map(pair._1) = pair._2
    }

    // new一個新的IndexedRDDPartition對象作爲返回值
    // 3個參數依次對應:index、values、mask
    new IndexedRDDPartition(
        ImmutableLongOpenHashSet.fromLongOpenHashSet(map.keySet), // index
        ImmutableVector.fromArray(map.values),                    // values
        map.keySet.getBitSet.toImmutableBitSet)                   // mask
    }

2. index構建過程

  • index 構建函數調用
    // 這裏實際是調用ImmutableLongOpenHashSet的fromLongOpenHashSet方法
    ImmutableLongOpenHashSet.fromLongOpenHashSet(map.keySet) // index
  • fromLongOpenHashSet 方法
    def fromLongOpenHashSet(set: OpenHashSet[Long]): ImmutableLongOpenHashSet =
        new ImmutableLongOpenHashSet(
            ImmutableVector.fromArray(set.data), //調用fromArray方法將對應節點的值傳進去
            set.getBitSet.toImmutableBitSet, 
            -1, 
            set.loadFactor)        // loadFactor默認值爲0.7         

3. fromArray方法

  • fromArray 方法定義
    def fromArray[A: ClassTag](array: Array[A]): ImmutableVector[A] = {
        // 再掉3個參數的fromArray方法,0表示起點下標
        fromArray(array, 0, array.length)
    }

    def fromArray[A: ClassTag](array: Array[A], start: Int, end: Int): ImmutableVector[A] = {
        // new一個ImmuableVector對象
        // 該對象第一個參數是樹的大小
        // 第二個參數是樹的根節點
        new ImmutableVector(end - start, nodeFromArray(array, start, end))
    }
  • nodeFromArray 方法構建這棵樹
    private def nodeFromArray[A: ClassTag](array: Array[A], start: Int, end: Int): VectorNode[A] = {
        val length = end - start
        if (length == 0) {
            emptyNode
        } else {
            val depth = depthOf(length) // length個節點需要存儲的樹的高度,高度從0開始
            if (depth == 0) {           // 一層就可以存的下,一層大小爲32,說明節點個數小於等於32,調用LeafNode構建這個存儲
                new LeafNode(array.slice(start, end))
            } else {
                val shift = 5 * depth  // 左移的位數,從根節點出發
                val numChildren = ((length - 1) >> shift) + 1        // 獲取根節點下子節點數目
                val children = new Array[VectorNode[A]](numChildren) // new一個類型爲VectorNode[A],長度爲numChildren的數組

                var i = 0
                while (i < numChildren) {                        // 遍歷子節點
                    val childStart = start + (i << shift)        // 子節點起始點位置
                    var childEnd = start + ((i + 1) << shift)    // 子節點終止點位置
                    if (end < childEnd) {                        // 修正最後一個節點的終止點位置
                        childEnd = end
                    }
                    children(i) = nodeFromArray(array, childStart, childEnd) // 遞歸調用 
                    i += 1
                }

                // 程序返回值就是下面這個InternalNode
                // InternalNode是VectorNode的子類
                // 這裏把子類遞歸返回給了父類,若直接返回children,children是一個Array類型的,不滿足返回值的類型
                new InternalNode(children, depth)
            }
        }
    }  
  • leafNode 構建葉節點
    // 下面是一個主類構造器,構造器中有一個參數爲Array[A]
    // 所以節點的最後一層存儲的就是一個數組
    // 節點對外提供3個方法
    private class LeafNode[@specialized(Long, Int) A: ClassTag](
        children: Array[A])
        extends VectorNode[A] {

        require(children.length <= 32,
        s"nodes cannot have more than 32 children (got ${children.length})")

        override def apply(index: Int): A = children(index)

        override def updated(index: Int, elem: A) = {
            val newChildren = new Array[A](children.length)
            System.arraycopy(children, 0, newChildren, 0, children.length)
            newChildren(index) = elem
            new LeafNode(newChildren)
        }

        override def numChildren = children.length
    }

index 樹的構建過程已經結束,下面介紹bitset 的構建。


3. toImmutableBitSet方法

  • toImmutableBitSet方法定義
    // numBits表示需要多少個二進制位來存儲這些節點
    // numBits大小就是節點數目
    // words是二進制位轉成long型的數組時的數值
    // words存儲也是用樹結構來完成的
    private[spark] def toImmutableBitSet: ImmutableBitSet = {
        new ImmutableBitSet(numBits, ImmutableVector.fromArray(words))
    }

ImmutableVector.fromArray(map.values) 構建values 的樹形結構時可參考fromArray的構建index的過程。

至此,indexedRDD中三棵樹的存儲結構已經構建起來。關於IndexedRDDPartition的操作源碼分析,後面會繼續更新。


【待續】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章