算法系列:矩陣相乘算法的MapReduce實現

看到一篇文章,列出了幾個使用MapReduce完成的算法(附有實現案例),但是還是想自己實現下,所以自己寫了一個,後來看了下案例,不是太一樣,但是我實現了,不管效果如何,或者好不好看,總之我實現了。這裏就跟大家分享下,同時也希望能得到一個建議。

首先介紹下我的實現思想:

1.兩個矩陣相乘,我們假設爲a[i][j],b[x][y],若a*b則i==y,即c[n][n]=a[i][j]*b[x][y](n==i==y),圖方便直接使用對稱矩陣。

2.使用Matrix對象來封裝一個矩陣的節點,Matrix對象有三個變量:flag,script1,script2。flag用來標示該矩陣節點屬於左邊的矩陣(a)還是右邊的矩陣(b),又或是結果矩陣(c),因爲左右矩陣需要不同的方式進行處理,所以需要區分開。

3.我們知道c[i][j]=sum(a[i][x]*b[x][j])(x=1-->n),根據此公式,我們可以知道一個c節點的值由a,b的哪些節點決定,我們這些a,b節點同c[i][j]放到一起,作爲map的輸出,reduce的輸入。然後通過使用合適的分組比較器和排序比較器,我們可以讓所有決定c[i][j]值的a和b節點放到一個reduce方法中,這樣我們就可以方便的計算出c[i][j]的值了。

4.分組比較器:map的輸出是[c[i][j],a[i][x]/b[x][j]},a[i][x]/b[x][j]的值],這樣的方式,而我們需要所有包含c[i][j]的key放到一起,所以分組比較器只要針對key的第一個對象進行比較即可,在對key的第一個對象(c)進行比較時,先flag進行比較(這裏不出意外應該都是一樣的),再根據script1進行比較,最後根據script2進行比較,這樣得到的可能排序結果如下:

c[1][1],c[1][2],c[2][1],c[2][2],...正是我們需要的順序,我們可以按此順序將值一次寫入輸出文件中,配置合理的換行機制,就可以得到一個很清晰的矩陣結果。

5.排序比較器:上面的分組比較器可以使得計算一個c[i][j]所需要的所有a和b矩陣節點都在一個reduce方法中進行計算,這樣雖然可以滿足我們的需求,但是計算相對來說還是比較麻煩的。比如我們需要計算c[2][3](假設矩陣大小=10),那麼我們需要計算a[2][1]*b[1][3]+a[2][2]*b[2][3]+...+a[2][10]*b[10][3],而reduce方法提供給我們的只是一個Iterable迭代器,我們需要在這個迭代器中找到a[2][1],b[1][3]然後再相乘,但是迭代器只能迭代一次,固然我們可以將其保存到一個list中,但是還是需要對該list進行N次遍歷,效率低下。這時就需要排序比較器出場了,從前面的計算公式我們可以看出,a的列標和b的行標其實是相同的,同時所有的a的行標是一致的,所有b的列標是一致的,因此我們在對其進行排序時完全可以按照a的列標和b的行標進行排序,這樣得到的排序結果如下:a[2][1],b[1][3],a[2][2],b[2][3],...這樣我們可以直接將相鄰兩個值相乘然後求和即可獲得最終的c[2][3]的值。這裏不要誤會,reduce是先排序,然後再對排序結果進行遍歷時才調用分組比較器判斷組的,這裏先介紹分組後介紹排序只是因爲方便講解。所以在排序時實際上我們實現按照key的第一個矩陣對象,即c矩陣進行排序,然後再根據第二個對象進行排序。

5.在計算出c[i][j]的值之後我們需要將其寫入到輸出文件中,同時我們想要保持良好的顯示風格,保持矩陣的順序,因爲在排序時已經保證了矩陣的順序,所以我們只需順序寫入輸出文件即可,但是我們需要合理的換行。實現方法是自定義RecordWriter對象,然後在每次調用RecordWriter的write方法時將參數key保存到一個變量中(last),然後每次調用該方法時將last的行標同key的行標進行比較,如果相同則不換行,不相同則換行。


以上就是我的整個實現思想,如有不妥之處還望賜教,順便附上自己的代碼,在運行時可以先調用util裏的FileUtil寫兩個矩陣文件,這裏需說明下因爲在計算過程中需要根據文件名區分a和b矩陣,所以a矩陣的文件名需要包含”1“,而b矩陣的文件名不能包含1,則文件中每行的第一個值是行號,且從1開始。也可以直接使用files裏面的文件。

<<請將文件上傳到hdfs中>>

該方法支持文件切分,但是最好使用一個reduce,因爲多個reduce會將結果輸出到多個文件,不易查看。

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