1. 程式人生 > >MarReduce小練習 - 多表關聯(使用靜態變數)

MarReduce小練習 - 多表關聯(使用靜態變數)

題意:

輸入檔案1:地址編號-地址
輸入檔案2:公司-地址編號
根據兩個輸入檔案,輸出公司所在的地址。
格式如下:

1.輸入檔案1:
address.txt:
1  Beijing
2  Guangzhou
3  Shenzhen
4  Xian


2.輸入檔案2:
factory.txt:
Beijing Red Star         1
Shenzhen Thunder     3
Guangzhou Honda     2
Beijing Rising          1
Guangzhou Development Bank    2
Tencent    3
Back of Beijing   1


3.輸出結果:

        factory                    city
Beijing Red Star                  Beijing
 Shenzhen Thunder                 Shenzhen
 Guangzhou Honda                  Guangzhou
 Beijing Rising                   Beijing
 Guangzhou DevelopmentBank        Guangzhou
 Tencent                          Shenzhen
 Back of Beijing                   Beijing

實現思路

該題重點是兩個檔案之間存在連線關係,即地址編號,只要輸出時按照地址編號尋找其地址即可,主要步驟入下:

  1. Job驅動類定義靜態變數,儲存地址編號-地址,這裡使用Map集合
  2. Mapper端按照輸入資料的型別分開儲存:
  • 型別1:格式為地址編號-地址,將該類資料儲存到靜態變數
  • 型別2:格式為公司-地址編號,將該類資料輸出到Reducer端
  1. Reducer端遍歷靜態變數,按照一定關係輸出資料。
重點:

大致步驟如上述1-3點,但其中還有很重要的細節,主要在Mapper端,如:

  1. 如何判斷輸入資料的型別,這裡採用正則判斷。
  2. maper的格式化是將一行資料讀入,在按照空格等分割時,分割如下:
    在這裡插入圖片描述
    需要做的就是拼接公司名稱。

程式碼

  1. Job驅動類
public static Map<String, String> numberAddress = new HashMap<>();
  1. Mapper
		StringTokenizer stringTokenizer = new StringTokenizer(value.toString()); // 好像用String.split(" ")分割更簡單點
		String column1 = stringTokenizer.nextToken();
		/*
		 *  讀取檔案內容可分為兩種:編號-地址、公司-地址編號, 處理方法如下:
		 *  使用正則表示式判斷資料的型別
		 *  將屬於編號-地址類資料存入靜態便利
		 *  將屬於公司-地址編號類輸出到reducer端
		 */
		// 正則
		Matcher matcher = Pattern.compile("^[0-9]*$").matcher(column1);
		if (matcher.find()) { // 匹配到地址編號,屬於編號-地址型別資料
			MTLinkJob.numberAddress.put(column1, stringTokenizer.nextToken());
		} else { // 屬於公司-地址編號型別
			// 由於公司名稱會被分割,所以先儲存分割的片段,最後一個片段則為地址編號
			String companyName = "" + column1; // 公司名稱
			String numberOfaddress = null;
			while (stringTokenizer.hasMoreTokens()) {
				if (stringTokenizer.countTokens() > 1) { // countTokens=剩餘數量。不是最後一個片段則拼接為公司名稱
					companyName = companyName + " " + stringTokenizer.nextToken().toString();
				} else { // 最後一個片段為地址編號
					numberOfaddress = stringTokenizer.nextToken().toString();
				}
			}
			context.write(new Text(companyName), new Text(numberOfaddress));
		}
  1. Reducer
	private int tol = 0; // 寫入行首提示
	@Override
	protected void reduce(Text key, Iterable<Text> values, Reducer<Text, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		if (tol++ == 0) {
			context.write(new Text("\tfactory"), new Text("\t\t\t\t\tcity"));
		}
		// 根據key,查詢靜態變數來確定地址
		String numberOfaddress = values.iterator().next().toString();
		if (MTLinkJob.numberAddress.containsKey(numberOfaddress)) {
			// 控制輸出對其
			String spaceCounts = "";
			for (int i=0; i<30-key.toString().length(); i++) {
				spaceCounts = spaceCounts + " ";
			}
			context.write(new Text(key), new Text(spaceCounts + MTLinkJob.numberAddress.get(numberOfaddress)));
		}
	}

完整專案程式碼見GitHub:https://github.com/GYT0313/MapReducePractice