2014年12月29日 星期一

MongoDB 開發筆記 - 使用 MapReduce 進行 Matrix Multiplication (矩陣乘法) 運算

最近下了班有空時都會繼續專研 MongoDB 分析資料的部分,一開始完全都用 Aggregation ,實在是有一些實測的效能比 MapReduce 好很多,但對於一些較複雜的計算方式,一直用 Aggregation 反而會卡住或是增加資料結構的複雜度 Orz 總之,開始正式去寫一些簡單的 MongoDB MapReduce 程式。

把玩的過程中,發現先前設計的 Sparse Matrix 結構,在計算矩陣相乘時,花了不少步驟並且效果變成永遠只能有一隻 Mapper 在進行 Orz 完全不能平行處理,因此開始研究一下如何用 MapReduce 進行矩陣運算。

網路上資源果然豐富,找到一篇:Programming Puzzle: Multiply Matrixes with MongoDB,概念解釋得很清楚。簡言之,當矩陣相乘時,以 A x B = C 為例,在組成 C 矩陣內的元素過程中,會採用 A 跟 B 矩陣內的部分元素相乘,那麼試著找個關係式子,讓這些元素最後在 Reducer 裡撞在一起,撞在一起時再相乘即可。

原來如此簡單的想法就可以讓 MapReduce 架構處理矩陣相乘了!有興趣可以再參考一下:changyy/node-mongodb-matrix-multiplication

2014年12月28日 星期日

MongoDB 開發筆記 - 在 MapReduce 進行 debug 的一些心得

有點久沒寫 blog 了!最近有空時就是把玩 MongoDB 或是嘗試送一些 patch ,所以反而就少寫一些筆記,因為都改成用 Code 啦 :P

最近玩 Mongodb MapReduce 時,碰到幾個問題跟需求:
  • 碰到 mongod Out of memory
  • 想要在 Mapper 跟 Reducer 輸出一些 console 訊息
其中 out of memory 的部分,經過 trace 後發現是內部 Mapper 實作的架構採用 C++ Map Structure 紀錄結果,累計處理完一百筆資料會輸出,但如果單一個筆 input 會產生極大數量的結果時,就會出現 out of memory,已經送了個鳥鳥的 patch 出去,就看 MongoDB Reviewer 決定如何 :P 畢竟這種現象也可以歸屬在使用者資料設計問題,為何讓一筆 input 產生巨量資料 XD

至於現況怎樣解套?若碰到 mongod crash 問題,先試試把 jsMode 打開吧!因為 jsMode = true 時,將採用 v8 engine 處理 mapper function,並且資料是直接輸出到 temp collection 的,可避開 out of memory 問題。

對於前期開發時,想在 Mapper 跟 Reducer 印出一些訊息時,此時不能直接用 console.log(obj),要改用 print(JSON.stringify(obj)) ,並且去翻一下 

/var/log/mongodb/mongod.log 吧!

2014年11月25日 星期二

iOS 開發筆記 - UIWebview loadData 以及 local resource 配置

很久以前把玩過 PhoneGap 後,就很久沒使用 UIWebview 來當作主要 UI。這次嘗試使用 Web UI 當作操作介面,於是乎就碰到使用 jQuery 的問題 XD 偷懶的解法就是用 remote resource,更佳的解法是用 local file。

使用方式:

// 記得要 Added folders 要採用 Create folder references
// web-resource/index.html
// web-resource/jquery.min.js
//
NSString *localWebPagePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"web-resource"];

[self.webview loadData:[NSData dataWithContentsOfFile:localWebPagePath] MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:localWebPagePath]];


其中的 baseURL 只要填寫正確,在 index.html 裡頭就可以用相對路徑存取 local file 了。

例如:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="jquery.min.js"></script>
</head>
<body>
...
</body>
</html>

[PHP] CodeIgniter 與 Facebook PHP SDK v4 整合筆記 @ Ubuntu 14.04

整個流程並主要是把 Facebook PHP sdk v4 source code 下載到 ci_proj/application/libraries 中,接著撰寫一隻 ci library: facebook.php 來橋接一下,就差不多可以收工了。在此謹驗證收到的 facebook token 是否有效,其他部分並不實作:

$ cd /path/ci_proj/application/libraries
$ git clone https://github.com/facebook/facebook-php-sdk-v4.git
$ ln -s facebook-php-sdk-v4 facebook


建立 Facebook 相關 config:

$ vim /path/ci_proj/application/config/facebook.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
$config['facebook']['api_id'] = 'FACEBOOK APP ID';
$config['facebook']['app_secret'] = 'FACEBOOK APP SECRET KEY';


編輯橋接的 library 用法:

$ vim /path/ci_proj/application/libraries/facebook.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require_once APPPATH . 'libraries/facebook/autoload.php';

use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\GraphUser;
use Facebook\FacebookRequestException;

class Facebook {
var $ci;
var $helper;
var $session;
var $permissions;

public function __construct() {
$this->ci =& get_instance();
$this->ci->load->config('facebook');
$this->permissions = $this->ci->config->item('permissions', 'facebook');
FacebookSession::setDefaultApplication( $this->ci->config->item('api_id', 'facebook'), $this->ci->config->item('app_secret', 'facebook') );
        }
public function token_validation($token) {
try {
$this->session = new FacebookSession( $token );
if ( $this->session->validate() )
return true;
} catch ( Exception $e ) {
}
$this->session = null;
return false;
}
public function get_user($token = NULL) {
if ( $this->session || (!empty($token) && $this->token_validation($token)) ) {
$request = ( new FacebookRequest( $this->session, 'GET', '/me' ) )->execute();
$user = $request->getGraphObject()->asArray();
return $user;
}
return false;
}
}


使用方式:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Test extends CI_Controller {
public function index()
{
$this->load->config('facebook');
$this->load->library('facebook');
$output = array(
'reqeusts' => $_REQUEST,
'app_id' => $this->config->item('api_id', 'facebook'),
'user_id' => $this->facebook->get_user($_REQUEST['token'])
);
$this->output->set_content_type('application/json')->set_output(json_encode($output));
        }
}

[PHP] 使用 CodeIgniter 和 codeigniter-restserver 建立 RESTful API 以及測試方式 @ Ubuntu 14.04

環境資訊:

  • Ubuntu 14.04 64 Bit (lsb_release -a)
  • PHP 5.5.9 (php -v)
  • CodeIgniter 2.2.0 (echo CI_VERSION)

接著,透過 github.com/chriskacerguis/codeigniter-restserver 擴充 CodeIgniter:

$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/config/rest.php -O /path/ci_proj/application/config/rest.php

$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/libraries/Format.php -O /path/ci_proj/application/libraries/Format.php

$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/libraries/REST_Controller.php -O /path/ci_proj/application/libraries/REST_Controller.php


接著,請確認 application/config/rest.php 設定:

$config[rest_default_format] = 'json'; // 預設為 xml

之後,就可以撰寫簡單的 RESTful API 啦:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require(APPPATH.'/libraries/REST_Controller.php');

class Item extends REST_Controller {
        public function index_get() {
                $this->list_get();
        }
        public function index_post() {
                $this->add_post();
        }
        public function index_put() {
                $this->update_put();
        }
        public function index_delete() {
                $this->delete_delte();
        }

        public function list_get() {
                echo "list";
        }
        public function add_post() {
                echo "create";
        }
        public function update_put() {
                echo "put";
        }
        public function remove_delete() {
                echo "remove";
        }
}


測試方式:

取得清單(GET)

$ curl -X GET http://localhost/ci_proj/item/list
$ curl -X GET http://localhost/ci_proj/item/

新增資料(POST)

$ curl -X POST http://localhost/ci_proj/item/add
$ curl -X POST http://localhost/ci_proj/item/


更新資料(PUT)

$ curl -X PUT http://localhost/ci_proj/item/update
$ curl -X PUT http://localhost/ci_proj/item/


刪除資料(DELETE)

$ curl -X DELETE http://localhost/ci_proj/item/delete
$ curl -X DELETE http://localhost/ci_proj/item/


也可以用 wget --method GET/POST/PUT/DELETE 等進行測試。

至於 RESTful 常見的 HTTP STATUS CODE,可以參考 Using HTTP Methods for RESTful Services

例如:

取得清單成功回應 200 OK,失敗則為 404 NOT FOUND;新增資料成功 200 OK 或是 201 LOCATION 到新增項目的 URI,失敗為 404 NOT FOUND;更新資料成功為 200 OK,失敗為 404 NOT FOUND;刪除資料成功為 200 OK,失敗為 404 NOT FOUND。

接著,是設計每個 GET, POST, PUT, DELETE API 細節,可以分別使用 $this->get('param')、$this->post('param')、$this->put('param') 和 $this->delete('param') 取得對應資料,而回應時,需要的 HTTP Status Code 可以使用:

$this->response( array('status' => true), 200);
$this->response( array('status' => false, 'error' => 'error message'), 400);
$this->response( array('status' => false, 'error' => 'error message'), 404);


若要 debug 的話,大概可以用:

$this->response( array('status' => true, 'get' => $this->get(), 'post' => $this->post(), 'put' => $this->put(), 'delete' => $this->delete() ), 200);

搭配 curl -i -X GET|POST|PUT|DELETE -d 'key=value' 方式進行,除了可以看到 HTTP Response code 外,也能看到 get, post, put, delete 各種參數資訊:

$ curl -i -X DELETE -d "haha=hehe" CGI
HTTP/1.1 200 OK
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.5
Content-Length: 68
Content-Type: application/json; charset=utf-8

{"status":true,"get":[],"post":[],"put":[],"delete":{"haha":"hehe"}}