使用Spark和Cassandra進行資料處理(一)

liuya1985liuya發表於2013-10-20

最近在研究將Spark架設到Cassandra之上。發現這方面的資訊比較少,在學習的過程中也遇到了不少問題,因此在此記錄下,也和大家分享。此例為最經典的WordCount示例。

首先我先說下我所使用的各種環境和版本。由於Spark和Cassandra更新較快,如果之後版本有異可能執行不能成功需要一些微調。

暫時使用的是Windows 7, 之後會轉到Linux平臺,但是這個影響不大。使用的是Scala2.9.3,Spark 0.8, Cassandra 1.2.10,sbt 0.13.0,Java 7。

 <wbr>

首先需要我們自己生成下Spark的jar包。這個需要我們執行sbt命令來得到。轉到Spark所在的目錄然後執行

sbtsbt assembly(如果是Linux的話,應該是sbt/sbt assembly)。執行結束後,可以在sparkassembly argetscala-2.9.3下面發現一個名字類似於spark-assembly-0.8.0-*.jar的包。我們需要將這個包加入到編譯路徑中。

 <wbr>

其次我們需要在Cassandra中插入一些資料。首先需要在命令列中執行cassandra/bin下面的cassandra命令來開啟服務。然後執行cassandra-cli,這樣我們就能夠輸入我們需要的資料。本文結尾可以找到此例使用的資料示例。

 <wbr>

然後我們就可以開始了。

Scala程式碼 <wbr>
  1. val sc new SparkContext("local[3]""casDemo" <wbr><wbr><wbr><wbr><wbr><wbr><wbr>

 新建一個Spark上下文物件,第一個引數是將要連線到的Cluster地址,這裡我們僅僅使用localhost來執行,所以可以簡單設定為local[*],*為1,2,3之類的數字。第二個只是一個顯示引數,可以隨意。<wbr>

Scala程式碼 <wbr>
  1. val job new Job()  <wbr><wbr><wbr><wbr><wbr><wbr>

 新建一個Hadoop job。因為Spark是沒有提供直接的API訪問Cassandra,但是Spark是建於Hadoop之上,Cassandra提供了訪問Hadoop的介面所以我們需要先建立一個Hadoop的job來連線它兩。<wbr>

Scala程式碼 <wbr>
  1. job.setInputFormatClass(classOf[ColumnFamilyInputFormat])  <wbr><wbr>

 設定input的類,這個沒有什麼其他可選項,這是Cassandra預設的jar包中提供的介面。<wbr>

 <wbr>

Scala程式碼 <wbr>
  1. ConfigHelper.setInputInitialAddress(job.getConfiguration(), "localhost" <wbr><wbr><wbr>
  2. ConfigHelper.setInputRpcPort(job.getConfiguration(), "9160" <wbr><wbr><wbr>
  3. ConfigHelper.setInputColumnFamily(job.getConfiguration(), "casDemo""Words" <wbr><wbr><wbr><wbr>
  4. ConfigHelper.setInputPartitioner(job.getConfiguration(), "Murmur3Partitioner" <wbr><wbr><wbr>

通過Cassandra提供的靜態類ConfigHelper來設定相對應的一些引數。“casDemo"是這個例子使用的keyspace,words是column family。9160是Cassandra預設使用的埠。最後一個是設定多臺機器執行時使用的Partitioner hash演算法。有三個值可以選擇,分別是org.apache.cassandra.dht.Murmur3Partitioner,org.apache.cassandra.dht.RandomPartitioner和ByteOrderedPartitioner。第三個已經不推薦使用了。在這裡我們使用第一個。

 <wbr>

此外需要說明的是,還有其他引數可以設定比如slice predicate之類的,這裡略過了,僅僅介紹了最簡單的設定。

 <wbr>

然後我們就能夠去建立Spark獨有的RDD物件了,並使用它來完成我們要的工作。

Scala程式碼 <wbr>
  1. val casRdd sc.newAPIHadoopRDD(job.getConfiguration(),  <wbr><wbr><wbr><wbr><wbr>
  2.             classOf[ColumnFamilyInputFormat],  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  3.             classOf[ByteBuffer],//key  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  4.             classOf[SortedMap[ByteBuffer, IColumn]]) //value  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>

 可以看到這裡建立了一個RDD物件,第一個引數就是將之間我們配置好的引數,第二個就是之前提到的Cassandra提供的介面,第三和第四個引數其他沒有其他的可選項,這兩個引數是被ColumnFamilyInputFormat所限制的。這個其實大家看SparkAPI就能瞭解到,這裡不多說。<wbr>

 <wbr>

Scala程式碼 <wbr>
  1. val paraRdd casRdd flatMap  <wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  2.     case (key, value) =>  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  3.         value.filter(v =>  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  4.             ByteBufferUtil.string(v._1).compareTo("paragraph"== 0  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  5.         }).map(v => ByteBufferUtil.string(v._2.value()))  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  6.      <wbr><wbr><wbr><wbr><wbr><wbr>
  7.  <wbr><wbr>

這裡就是執行mapper方法了,就和hadoop中的mapper一個概念。需要說明的是,這裡的key就是一個ByteBuffer物件,value就是一個SortedMap[ByteBuffer, IColumn],有沒有覺得很熟悉,是的,這兩個就是之前建立RDD設定的最後兩個引數。這裡我做的就是過濾掉colomn name不等於paragraph的,然後將colomn是paragraph的值由Icolumn變成ByteBuffer型別。

 <wbr>

Scala程式碼 <wbr>
  1. val counts paraRdd.flatMap(p => p.split("<wbr>)).map(word => (word, 1)).reduceByKey(_ _)  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>

最後就是reduce方法了。 先用空格將段落打散成單詞,然後將單個單詞word轉化成元組(word, 1)。最後統計每個word出現次數。

 <wbr>

這樣我們就完成了簡單的WordCount方法。

我們可以通過以下程式碼列印出結果來觀看。

Scala程式碼 <wbr>
  1. counts.collect() foreach  <wbr><wbr><wbr><wbr>
  2.     case (word, count) => println(word ":" count)  <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>
  3.  <wbr><wbr>

 <wbr>

這裡介紹了通過Spark讀取Cassandra資料並進行處理。下一節,會介紹寫入資料。


此文與http://cjcrobin.iteye.com/blog/1955984同步.可以在上面下載到此例原始碼。

<!-- 正文結束 --&gt

相關文章