Leo Yeh's Blog

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 多次,將會發現回應時間比未優化之前快非常多。

相關資源

⬅️ Go back