倒排索引

1.實例描述

輸入爲一批文件,文件內容格式如下:

Id1 The Spark

……

Id2 The Hadoop

……

輸出如下:(單詞,文檔ID合併字符串)

The    Id1 Id2

Hadoop    Id2

……

2.設計思路

先讀取所有文件,數據項爲(文檔ID,文檔詞集合)的RDD,然後將數據映射爲(詞,文檔ID)的RDD,去重,最後在reduceByKey階段聚合每個單詞的文檔ID

3.代碼

import org.apache.spark.{SparkContext, SparkConf}

import org.apache.spark.SparkContext._

import scala.collection.mutable

object InvertedIndex {

  def main(args: Array[String]) {

    val conf = new SparkConf().setAppName("InvertedIndex").setMaster("local[1]")

    val sc = new SparkContext(conf)

    val textRdd=sc.textFile("hdfs://master:9000/wordIndex")

    val md=textRdd.map(file=>file.split("\t"))

    val md2=md.map(item=>{(item(0),item(1))})

    val fd=md2.flatMap(file =>{

      val words=file._2.split(" ").iterator

      val list=mutable.LinkedList[(String,String)]((words.next(),file._1))

      var temp=list

      while(words.hasNext){

        temp.next=mutable.LinkedList[(String,String)]((words.next,file._1))

        temp=temp.next

      }

      list

    })

    val result=fd.distinct()

    val resRdd=result.reduceByKey(_+" "+_)

    resRdd.saveAsTextFile("hdfs://master:9000/InvertIndex")

  }

}

4.說明

其中有如下幾點要注意

rdd flatMap方法定義如下

/**

   *  Return a new RDD by first applying a function to all elements of this

   *  RDD, and then flattening the results.

   */

  def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U] =

    new FlatMappedRDD(this, sc.clean(f))

方法的參數爲函數,函數輸出類型爲集合(的父類)。它的作用是將這些集合合併爲一個新的集合,但不刪除相同的元素,也不合並rdd中的分區。

reduce 方法定義如下

/**

   * Reduces the elements of this RDD using the specified commutative and

   * associative binary operator.

   */

  def reduce(f: (T, T) => T): T = {

    val cleanF = sc.clean(f)

    val reducePartition: Iterator[T] => Option[T] = iter => {

      if (iter.hasNext) {

        Some(iter.reduceLeft(cleanF))

      } else {

        None

      }

    }

    var jobResult: Option[T] = None

    val mergeResult = (index: Int, taskResult: Option[T]) => {

      if (taskResult.isDefined) {

        jobResult = jobResult match {

          case Some(value) => Some(f(value, taskResult.get))

          case None => taskResult

        }

      }

    }

    sc.runJob(this, reducePartition, mergeResult)

    // Get the final result out of our Option, or throw an exception if the RDD was empty

    jobResult.getOrElse(throw new UnsupportedOperationException("empty collection"))

  }

reduce 函數相當於對RDD中的元素進行reduceLeft函數的操作。reduceLeft先對兩個元素<K,V>進行reduce函數操作,然後將結果和迭代器取出的下一個元素<K,V>進行reduce函數操作,直到迭代器遍歷完所有元素,得到最後結果。

在RDD中,先對每個分區中的所有元素<K,V>的集合分別進行reduceLeft。每個分區形成的結果相當於一個元素<K,V>,再對這個結果集合進行reduceLeft操作。

例如:用戶自定義函數如下。

f:(A,B)=>(A._1+"@"+B._1 , A._2+B._2)

如圖:

spacer.gif


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