Node.js 雲端服務 Amazon (5)

基本介紹

教學目標

透過 Node.js 搭配 Amazon Elastic MapReduce 建立簡易的電影推薦 API 之應用。

前置作業

  1. 申請 AWS 雲端服務帳號。
  2. 建立 Amazon Elastic MapReduce 的叢集服務。

使用教學

推薦分析

在 Amazon Elastic MapReduce 中的 Cluster Details 就能找到 SSH 的登入方式。

登入 Amazon Elastic MapReduce 的主要伺服器

1
$ ssh hadoop@ec2-54-169-107-189.ap-southeast-1.compute.amazonaws.com -i ~/leoyehme.pem

下載範例檔案,並且解壓縮該檔案。

1
2
$ wget http://files.grouplens.org/datasets/movielens/ml-1m.zip
$ unzip ml-1m.zip

進行範例檔案內容的處理,以進行接下來的推薦分析。

1
$ cat ml-1m/ratings.dat | sed 's/::/,/g' | cut -f1-3 -d, > ratings.csv

將本機檔案放置 Hadoop 檔案系統之中。

1
$ hadoop fs -put ratings.csv /ratings.csv

開始透過 Apache Mahout 和 Amazon Elastic MapReduce 進行推薦分析

1
$ mahout recommenditembased --input /ratings.csv --output recommendations --numRecommendations 10 --outputPathForSimilarityMatrix similarity-matrix --similarityClassname SIMILARITY_COSINE

當我們透過三台 m1.medium 等級的 EC2 進行 Hadoop + Mahout 資料解析需要花費二十分鐘左右。

檢查推薦分析之後的結果。

1
2
$ hadoop fs -ls recommendations
$ hadoop fs -cat recommendations/part-r-00000 | head

安裝 Node.js

開始進行安裝。

1
2
3
4
5
6
$ sudo yum update
$ sudo yum install gcc-c++ make
$ sudo yum install openssl-devel
$ sudo yum install git
$ git clone git://github.com/joyent/node.git
$ git checkout v0.8.1 ./configure make sudo make install

修改執行檔的路徑。

1
2
3
$ sudo vi /etc/sudoers

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

繼續安裝 NPM。

1
2
3
$ git clone https://github.com/isaacs/npm.git
$ cd npm
$ sudo make install

升級 Node.js 為穩定版本

1
2
3
$ sudo npm install n -g
$ sudo n stable
$ node -v

安裝相關套件

1
$ npm install express --save

實作推薦 API

透過 vi 工具撰寫推薦 API 程式碼

1
$ vi server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var express = require('express');
var app = express();
var router = express.Router();
app.use('/api', router);
router.get('/movie/:id', function(req, res){
var exec = require('child_process').exec;
exec("hadoop fs -cat recommendations/part*", function(error, stdout, stderr){
var result = stdout.split("\n");
result.forEach(function(element, index, arr) {
var data = element.split("\t");
var key = data[0];
var value = data[1];
if (req.params.id == key) {
res.json({data:value});
}
});
});
});
var port = process.env.PORT || 8080;
app.listen(port);

修改 EC2 的 Security Groups 中的 ElasticMapReduce-master 的 Inbound

1
2
3
4
5
Custom TCP Rule
TCP
8080
Anywhere
0.0.0.0/0

啟動推薦 API 伺服器

1
$ node server.js

在瀏覽器網址列輸入 http://ec2-54-169-107-189.ap-southeast-1.compute.amazonaws.com:8080/api/movie/37

1
{"data":"[1231:5.0,237:5.0,2133:5.0,3844:5.0,2478:5.0,1688:5.0,832:5.0,3108:5.0,1946:5.0,224:5.0]"}

推薦 API 優化

將每次存取 Hadoop 檔案系統中的檔案匯出至本機,接著再被推薦 API 進行存取。

1
hadoop fs -cat recommendations/part* > result.csv

將每次存取本機檔案的結果儲存至陣列變數中,接著再下次推薦 API 被存取時就能先取陣列的內容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var express = require('express');
var app = express();
var router = express.Router();
app.use('/api', router);
var cache = new Array();
router.get('/movie/:id', function(req, res){
if (cache[req.params.id]) {
res.json({data:cache[req.params.id]});
} else {
var fs = require('fs');
var path = require('path');
var filePath = path.join(__dirname, 'result.csv');
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
if (!err) {
var result = data.split("\n");
result.forEach(function(element, index, arr) {
var data = element.split("\t");
var key = data[0];
var value = data[1];
cache[key] = value;
if (req.params.id == key) {
res.json({data:value});
}
});
} else {
console.log(err);
}
});
}
});
var port = process.env.PORT || 8080;
app.listen(port);

啟動推薦 API 伺服器

1
$ node server.js

在瀏覽器網址列輸入 http://ec2-54-169-107-189.ap-southeast-1.compute.amazonaws.com:8080/api/movie/37。

1
{"data":"[1231:5.0,237:5.0,2133:5.0,3844:5.0,2478:5.0,1688:5.0,832:5.0,3108:5.0,1946:5.0,224:5.0]"}

重複存取推薦 API 多次,將會發現回應時間比未優化之前快非常多。

相關資源