software engineering

Intro to MongoDB

Ricky Wu 的照片

NoSQL」是不同於關聯式資料庫的一類資料庫,他不具備SQL語法的介面來進行資料的查詢或是處理。NoSQL資料庫可分為:「Column-orientedKey-value pairs」與「Document-oriented」等三大範疇,以下介紹的MongoDB則是屬於Document-oriented的資料庫系統。

Document-oriented資料庫中,一筆資料不再是以固定大小的方式處存於表格裡,取而代之的是無論多少欄位或是不同大小的欄位都能夠被放置入資料庫中。每個欄位更可細分為更小的資料片段,形成巢狀的資料結構。以下為一段PHP描述person物件定義的程式碼:

$person = array(

    "name" => "Cesar Rodas",
    "country" => "Paraguay",
    "languages" => array("Spanish", "English", "Guarani"),
);

MongoDB是一套由C++所編寫出擁有高效能且具高延展性的開放原始碼文件導向資料庫系統。其最主要的目標是將「Key-Value stores」及傳統RDBMS系統的優點結合起來,因此他具有「Key-Value stores」快速且具高度擴充性的儲存功能,也具備RDBMS所提供豐富的查詢方式及功能強大的查詢功能。在實作上,MongoDB具備以下幾點有趣的特性:

  • It uses JSON, instead of XML
  • It is fast, as it is written in C++
  • Supports index definitions
  • Provides an easy to use query interface, very similar to some database abstraction layers
  • Supports operations with sub-documents
  • Provides a native PHP extension
  • Supports auto-sharding
  • Supports map-reduce for data transformation

安裝及配置上,MongoDB可支援如PHPRubyPythonJAVAC++多種主流程式語言,因此在使用上相對的方便而簡單。在MongoDB官方網站的下載頁面裡,有提供適用於各種作業系統平台已編譯完成的可執行檔包裝,也一併提供使用者對應版本的MongoDB原始碼。

Linux上安裝MongoDB相當的簡單,首先在http://www.mongodb.org/display/DOCS/Downloads下載頁面裡下載對應平台的壓縮檔,解壓縮後執行Mongod,以預設模式啟動MongoDB

mkdir -p /data/db tar -xvzf PACKAGE   ./mongodb-xxxxxxx/bin/mongod

./mongodb-xxxxxxx/bin/mongo  

執行後Database Daemon便開始監聽主機的27017埠,資料預設儲存路徑為 /data/dbWindows底下為c:\data\db),再來便可以執行Mongo來進入MongoDB的命令列下,操作資料庫。

Ref.

Developing scalable PHP applications using MongoDB - PHP Classes blog

Libgtop

David Lee 的照片

如何寫一隻程式來判斷這隻程式在執行階段所佔用的 linux 系統資源,例如 CPU 和記憶體使用率呢? 可以去查看系統中的 /proc/<process id>/stat,或是藉由系統 shell 的 top 指令,但是這兩者都必須花費額外的功夫去分析檔案或介面中的資料。在這邊介紹一個 c 語言的開源函式庫: libgtop,可以幫助我們獲取系統或特定線程所佔用的資源量。

libgtop 是 GNOME 計畫中的一個函式庫,用來實現 GNOME 桌面環境中的”top”功能。它依賴於另一個GNOME 的函式庫 glib。目前最新的版本是 2.28,在安裝前必須先安裝 glib 2.6.0 以上版本 以及 intltool 0.35.0 以上版本。

一般來說,CPU 的使用率,是根據 CPU 花費在各種不同模式的時間所計算的。這些時間通常可分為user mode, nice mode, system(kernel) mode 和 idle mode,而使用 libgtop 的 API 可以獲取系統 boot 到目前為止,各種 mode 所佔用的時間(clock click 次數)。舉例而言,可以利用下面的程式碼來計算出系統 CPU 的使用率:

#include <glibtop>
#include <glibtop/cpu.h>

double cpu_rate;
int dt, du, dn, ds;
glibtop_cpu cpu_begin,cpu_end;
glibtop_get_cpu(&cpu_begin);
sleep(1);
glibtop_get_cpu(&cpu_end);
dt = cpu_end.total - cpu.begin.total;
du = cpu_end.user - cpu.begin.user;
dn = cpu_end.nice - cpu.begin.nice;
ds = cpu_end.sys - cpu.begin.sys;
cpu_rate = 100.0 * (du+dn+ds) / dt

注意 CPU 使用率的計算必須根據兩個時間點的 click 次數的差,所以必須截取兩次這個資訊後再相減。而memory 的觀測就比較單純,可以一次獲得。例如:

#include <glibtop>
#include <glibtop/mem.h>

double mem_rate;
glibtop_mem memory;
glibtop_get_mem(&memory);
mem_rate = 100.0 * memory.used / memory.total;

libgtop 可以觀測的資源種類相當多,除了上例中介紹的系統 CPU 和記憶體以外,還包括特定線程的 CPU 和記憶體、swap、檔案系統、網路介面等等。詳細的 API 及資料結構可以參考 GNOME 的官方網站: http://developer.gnome.org/libgtop/

Google File System 介紹

David Lee 的照片

Google 之所以能獨霸搜尋引擎市場,一方面是依靠 PageRank 技術所提供的優良搜尋排序,另一方面則仰賴其文件儲存系統的優良效率。Google 設計了一套獨特的分散式檔案系統以滿足其龐大的儲存需求,也就是所謂的 Google File System (簡稱 GFS)。Google 並沒有將 GFS 當做開源軟體釋出,不過還是公布了一些技術細節,包含一篇官方論文。

與傳統的分散式檔案系統相比,GFS 有兩個主要的不同點。首先,設備的失效被視為正常的現象而非意外。所謂的失效包括了應用程式的錯誤、作業系統的錯誤、人為操作的錯誤、乃至於硬體或網路的問題。既然連昂貴的硬碟設備也不可能百分之百排除發生錯誤的可能性,Google乾脆使用多個廉價的磁碟機來組成他們的儲存設備。而為了對抗設備的失效,GFS 包含了監視、錯誤偵測、容錯以及自動修復的機制。

其次,資料大多只會被追加到文件的末端,鮮少會修改或刪除原本存在的檔案。已寫入的資料通常只需要可讀 (readable) 不需要可寫 (writable),而且通常是按照順序且大規模的讀取,一次操作便可能讀取數百 KB甚至 MB 以上的資料。要特別注意到的是,GFS 預期所保存的檔案通常都是數百 MB 甚至 GB 以上的文件,小型的文件會被支持但不會被優化。

GFS 處理客戶端所下要求的方式是採類似 supernode (Master) 與分散式結點 (Chunkserver) 的架構。真正的數據資料儲存在 Chunkserver上,並且定期將其狀態報告給 Master。當客戶端需要讀取某個檔案時,要先向 Master 發出要求,Master 會考慮 Chunkserver 是否為閒置狀態,若為閒置則將 Chunkserver 的位置回報給 client,於是 client 就可以對 Chunkserver 中的檔案進行操作。

GFS 支持了必需提供超大文件量與超大流量的 Google 搜尋引擎服務,同時建構於 GFS 之上的 BigTable 資料庫技術也是 Gmail、Google Maps、Youtube 乃至於其他許多 Google 應用軟體或雲端服務的基礎,可以說是雲端時代的殺手級技術。

礙於篇幅,更多的 GFS 細節可以參考: http://labs.google.com/papers/gfs.html

PHP 函數實作 Semaphore

Ruby Lin 的照片

Semaphore 是一個可變或抽象的資料型態,在並行計算環境中,若有多個行程對一個共用資源,將可提供簡單有用的控制存取。

可以把 semaphore 想成是一個記錄,有多少單位的特殊資源是可使用的,加上操作安全地(即沒有競爭危害)調整那個紀錄,且那是有需要等待的直到一個單位的資源變得可使用。

Semaphore是有用的工具來預防競爭危害和死鎖; 然而,他們的用途絕不是保證程式可以從這些問題中解脱。資源允許任意數量的 semaphore 叫 counting semaphores;值只有 1 或 0 的 semaphore (或 locked/unlocked、unavailable/available)稱 binary semaphores。

下面為 PHP 的 semaphore 函數
int ftok (string $pathname, string $proj) – 將可存取的路徑和方案編號轉換成 System V 可存取的 IPC key。

bool sem_acquire (resource $sem_identifier) - 向信號機要求,信號機會減少一個資源數,並進入臨界區。

resource sem_get (int $key [, int $max_acquire = 1 [, int $perm = 0666 [, int $auto_release = 1 ]]]) - 取得一個新的信號機。

bool sem_release (resource $sem_identifier) - 向信號機通知釋放一個資源數,並離開臨界區。

bool sem_remove (resource $sem_identifier) - 移除一個信號機。

resource shm_attach (int $key [, int $memsize [, int $perm ]]) - 回傳一個可以存取 system V 共享記憶體的編號。

bool shm_detach (resource $shm_identifier) - 中止對共享記憶體的連結。

mixed shm_get_var (resource $shm_identifier, int $variable_key) - 取得共享記憶體中指定的變數值。

bool shm_has_var (resource $shm_identifier, int $variable_key) - 檢查共享記憶體裡是否存在該鍵值。

bool shm_put_var (resource $shm_identifier, int $variable_key, mixed $variable) - 增加或修改共享記憶體中的變數值。

bool shm_remove_var (resource $shm_identifier, int $variable_key) - 移除指定的變數名稱。

bool shm_remove (resource $shm_identifier) – 移除共享記憶體。

GNU libextractor

Shawn Lin 的照片

Introduction

GNU libextractor 是一個種用來從 file 中提取 meta data 的 library。他的設計為以輔助程式庫的方式來執行提取文件實際內容,Meta data 格式的資料有下列 (mime type, image dimensions, color depth, recording frequency),GNU libextractor 主要是被我們用來提取 meta data 之用。目前,GNU libextractor 支持以下格式:HTML, PDF, PS, OLE2 (DOC, XLS, PPT), OpenOffice (sxw), StarOffice (sdw), DVI, MAN, FLAC, MP3 (ID3v1 and ID3v2), NSF(E) (NES music), SID (C64 music), OGG, WAV, EXIV2, JPEG, GIF, PNG, TIFF, DEB, RPM, TAR(.GZ), ZIP, ELF, S3M (Scream Tracker 3), XM (eXtended Module), IT (Impulse Tracker), FLV, REAL, RIFF (AVI), MPEG, QT and ASF. 此外,還有各種額外的 MIME 類型檢測。

GNU libextractor 是免費軟件,可以下載下來修改以及發布。
GNU libextractor 使用 plugin 來處理各種文件格式。從技術上講一個 plugin 可以支持多種文件格式,但大多數 plugin 只支持一個特定的格式。默認情況下,GNU libextractor 將使用所有在安裝目錄下發現的可用 plugin。應用程序可以要求使用特定 plugin 或只有排除某些 plugin。

Example for using dynamic library

// hello.c
#include <extractor.h>
int main()
{
struct EXTRACTOR_PluginList *el;
el = EXTRACTOR_plugin_load_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY);
// ...
EXTRACTOR_plugin_remove_all (el);
return 0;
}

執行以下指令 compile
$ gcc \ -I/Library/Frameworks/Extractor.framework/Versions/Current/include \
-o hello hello.c \
-L/Library/Frameworks/Extractor.framework/Versions/Current/lib \
-lextractor

Plugin management

C Struct: EXTRACTOR_PluginList
建立一組 plugin

Function: void EXTRACTOR_plugin_remove_all (struct EXTRACTOR_PluginList *plugins)
刪除所有給定 plugin 列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_remove (struct EXTRACTOR_PluginList *plugins, const char*name)
刪除給定 plugin 列表例如 mime 中的 mpeg

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList *plugins, const char* name,const char* options, enum EXTRACTOR_Options flags)
增加給定 plugin 列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_config (struct EXTRACTOR_PluginList *plugins, const char* config, enum EXTRACTOR_Options flags)
根據 config string load 或是 unload 或是修改已存在的列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_defaults (enum EXTRACTOR_Options flags)
載入所有在 plugin 資料夾下的預設 plugin 列表

Example for a minimal extract method

以下範例告訴我們如何利用 plugin 解讀出 MIME type

int
EXTRACTOR_mymime_extract
(const char *data,
size_t data_size,
EXTRACTOR_MetaDataProcessor proc,
void *proc_cls,
const char * options)
{
if (data_size < 4)
return 0;
if (0 != memcmp (data, "\177ELF", 4))
return 0;
if (0 != proc (proc_cls,
"mymime",
EXTRACTOR_METATYPE_MIMETYPE,
EXTRACTOR_METAFORMAT_UTF8,
"text/plain",
"application/x-executable",
1 + strlen("application/x-executable")))
return 1;
/* more calls to 'proc' here as needed */
return 0;
}

Internal utility functions

有些實用的內部開發 API
“convert_numeric.h” 定義了各種數字的轉換功能(特別是轉換為浮點數)。
“unzip.h” 定義了一個訪問壓縮文件的 API。
“pack.h” 可以把有 integer 的 struts 分解順便也可以把 big/little endian 轉成 host byte order。
“convert.h” 提供了一個函數進行所需之字符集轉換。
Function: char * EXTRACTOR_common_convert_to_utf8 (const char *input, size_t len, const char * charset) 可以用來方便地從任何字符集轉換為 UTF - 8 文本。

Conclusion

總之,對於訊息解析平凡的我們來說,GNU libextractor 不只幫助了我們找到檔案的正確格式,還可以撰寫各種 plugin 工具,分析各種文字格式,找到相對應的 MIME type。這對 email 這塊領域而言,可說是不可或缺的一項工具。

What is memcache?

HH Tu 的照片

今天我要介紹一個對於存取資料庫相當有用的技術 - Memcache.

Memcache 是一種分散式記憶體快取系統,對於現在熱門的雲端系統也是相當有用的。 它最基本的概念式用 key-based 的資料結構來存取資料到記憶體內部。 原先這個概念來自於 Brad Fitzpatrick,他最早用在一家叫做 LiveJournal.com(2003) 的公司,因為效果不錯,而又加以發揚光大。 現在有更多的大公司有在用這項服務:LiveJournal、Wikipedia、Flickr、Twitter、Youtube、Digg、WordPress.com…etc. 它的好處在,可以縮減大部分存取資料庫的時間轉而到存取記憶體上面,就算資料沒有在記憶體上面對於要到後方存取資料庫也是相當的容易設計。 雖然它有 key-based 快取還有分散式記憶體功能,但是對於存取限制這點必須由建構者自己決定。 這項技術效果最好的地方當然就是把常用的資料寫到記憶體內部,那麼下次存取的時候就近乎不用等待時間。 這概念有點像是當你上網的時候,網站會將網站大部分的圖片資料先暫存到你電腦內,等你下次又再存取這個網站的時候,速度會大幅提升是一樣道理。Memcache 也是用一樣的概念,它拿你電腦的記憶體來加速存取,它可以拿整個網路的空閒記憶體來存取,讓你可以在同一個網路架構下共同存取使用到, 另外一個特點就是你想要增加多少記憶體使用就可以增加多少(當然你需要充足的記憶體),甚至它會將所有記憶體區塊視為同一個記憶體,這就結合著前面所敘述著,網路上的記憶體只要你可以用你就可以將全體合併執行。而理論上它的設計這些行為應該都在 O(1) 可以完成。

現在我來給一個簡單的範例來敘說有 Memcache 使用上的差異 我們每天從一台電腦存取資料,如果我們想加入就會想要再加一台機器,但是要怎樣才會有效率?

圖片1,我們有兩台機器兩個分開的記憶體,為了確保兩台資料相同不會有不一致情形發生,所以我們會讓兩台記憶體都存取一樣的資料, 結果導致只是電腦 CPU 運作很快,但是記憶體沒有有效率的使用,這種設置效率很差。

圖片2,我們有兩台機器,但是透過 Memcache 來結合兩邊的記憶體,所以我們記憶體是共存使用的,不用擔心不一致的情形, 而且空間還加倍使用,整個生活變得更美好了!!

那我們到底該怎樣使用 Memcache 比較好? 以目前較有意義的使用方式是,如果你的存取資料庫充滿著”SELECT * from XXX”, 表示你常常要所有的資料而且量不少,而且如果又是常常重複的資料,那你就可以使用Memcache使用的相當快樂。 這邊給一個簡單的分析,你如果要用 Memcache 必須要考慮幾個要點:1. 搜尋的時間 2. 擊中率 3. 檔案存在時間,當然你需要花費額外的人力時間去寫程式來增加這段效率,不過比較起結果,這算是常態時間 (Constant time) 的考量吧?

我再給予一個簡單的流程來說明要如何建構你的系統跟 Memcache 還有資料庫運作 假設你現在有很多台伺服器,現在想要連結這幾台伺服器有更有效率的應用記憶體。 以下是一個簡單的流程: 你的客戶們來詢問伺服器資料,你的伺服器一開始會先去詢問 Memcache,如果資料不存在於 Memcache,這時候在去詢問 Database,等到找到資料的時候,記得要將資料再寫回去 Memcache,這就是一個簡單的標準流程。系統剛開始跑 或許會有陣痛期,等只要時間久了,整體速度應該是向上提升才對。

再上面的例子其實你可以看的出來 Memcache在實做上是一個網路的 daemon 大多數人會配合著 PHP或是 C/C++來跟 Memcache 溝通 我使用的 Linux 系統,如果你想要用 C/C++ 來建構,基本上你必須先安裝幾個程式:1. libevent 2.Memcache 3. libmemcache

想要了解更詳細的操作跟內容請參造 Memcache官網: http://memcached.org/

甚麼是 Node.js?

Paul Chien 的照片

傳統上,JavaScript 只在網頁瀏覽器執行,但由於 CommonJS 專案,最近已經有相當多的興趣也把它拿到伺服器端。其他伺服器端 JavaScript 環境,包括 Jaxer 和 Narwhal。然而,Node.js 有點不同於這些解決方式,因為它是事件基礎 (event-based) 而不是執行序基礎 (thread based),像 Apache 這種被用來服務 PHP 和其他 CGI 語言的網頁伺服器是執行序基礎,因為它們為每個近來的需求產生一個系統執行序。雖然這對很多應用程式是沒問題,但執行序基礎在很多諸如為了服務及時應用程式需要長久的 (long-lived) 連線,像 Friendfeed 或 Google Wave,並沒有很好地擴展。

Node.js 使用事件迴圈取代執行序,且能夠擴充到同時有上百萬的連線,它利用伺服器花最多的時間在等待讀取與寫入操作的事實,像從硬碟讀取檔案、存取額外的網頁服務或等待檔案上傳完成,因為這些作業比記憶體作業慢很多。每個讀取與寫入操作在 Node.js 是非同期,意指當讀取與寫入操作發生時,伺服器能夠繼續處理進來的需求。JavaScript 是非常適合事件基礎的程式設計,因為它有匿名函數 (anonymous functions) 和封絕 (closure),且 JavaScript 開發者已經知道如何以這種方式編程,這種事件基礎模式讓 Node.js 很快,且讓擴充及時應用程式很容易。

http://docs.pylonsproject.org/projects/pyramid/1.0/narr/introduction.html

LDAP

David Lee 的照片

試想兩個不同的問題:其一,一個上千人的龐大組織,擁有許多不同的部門與 IT 資源,要如何維護一個便於更新且組織成員們易於查詢的線上通訊錄? 其二,一個必須同時維護多個不同系統 (可能包含 linux 登入、apache、samba、mail service 等等) 的 MIS 人員,要如何維護多組不同的帳號密碼,甚至必須定期更新它們? 這兩個問題看來毫不相干,可是都可以使用同一個方案來解決:LDAP (Lightweight Directory Access Protocol)。

LDAP 是一個參考線上目錄服務 (Directory Service) 的協定,其經由 X.500 改造而來,省略了 X.500 許多繁瑣的細節,成為了一個能夠建構於 IP 網路上、彈性而方便的網路協定。對前文的問題一而言,LDAP 充滿彈性的設計讓我們能夠將組織資源整理成目錄型式的資料庫;而對於問題二而言,LDAP 提供了一個標準化的介面供不同的應用程式參考,因而很容易整合多種不同應用服務的組態配置 (configuration)。

以宏觀的角度來看,LDAP 將多筆資料以樹狀結構做儲存,稱為 DIT (Directory Information Tree)。整個 DIT 可以切割成許多子樹,每個子樹都可以儲存在不同的 LDAP 伺服器上,以達到分散式架構的目的。其中,每一筆資料都會有一個獨一無二的 Distinguished Name (DN),就像是一般檔案系統中的「絕對路徑」,用來標記這筆資料在 DIT 中的位址。

以微觀的角度來看,LDAP 中每一筆資料都符合一種特殊的schema,並且可以轉換成 LDIF (LDAP Data Interchange Format) 格式以便閱讀 (注意實際上資料的儲存方式可能是binary 的)。在 LDIF 格式中,每一筆資料都會擁有多個不同的「屬性」,每種屬性則會擁有一到多個不同的「值」。一筆資料可能擁有哪些屬性,必須根據它所屬的物件類別 (objectClass)。例如,類別為「員工」的資料可能會有「姓名」、「所屬部門」、「郵件位址」等屬性,而類別為「部門」的資料則可能有「主管」、「所屬員工」等屬性。其中,每一筆資料都一定會有 DN 和 objectClass 這兩個屬性,至於其他「應有」和「可有」的屬性,則由其 objectClass 而定。

要在 LDAP server 上查詢資料時,可以把查詢 (query) 包裝成LDAP URL 的格式:

ldap://" [ <host> ]"/" <dn> [ "?" <attributes>[ "?" <scope> "?" <filter> ] ]
<host> ::= <hostname>[ ":" <port> ]
<attributes> ::= NULL | <attributelist>
<attributelist> ::= <attributetype>| <attributetype>[ "," <attributelist> ]
<scope> ::= "base" | "one" | "sub"

● host: server 的 IP 位址
● dn: 搜尋起點的 dn
● attributes: 希望回傳的屬性有哪些
● scope: 搜尋的範圍(單一節點、第一代的子節點、或是整個子樹)
● filter: 搜尋條件

例如: ldap://cellopoint.com/ou=rd,ou=unit,ou=company,dc=cellopoint,dc=com?mail?sub?uid=david
會回傳 cellopoint 公司中、rd 部門下、id 為 ”david” 的員工的email。

目前最常被使用的兩個 LDAP 軟體為 openldap 和 Microsoft Active Directory。前者是 open source 的軟體,對 LDAP 有興趣者不妨測試看看,也許就會發現一些原本很繁瑣的 MIS 工作頓時變得輕鬆不少喔!

CodeIgniter 2.0.2 版本釋出

Ruby Lin 的照片

 目前有許多 PHP 框架可以使用,而現今開發者最常使用的包括了:Zend、CakePHP、Symfony、CodeIgniter、Seagull、Yii。這些 PHP 框架在程式開發時帶來了許多好處,例如:

1. MVC (模型-視圖-控制器) 架構

2. 將 PHP 和 HTML 分開

3. 容易使用的 URL 命名空間

4. 開發速度加快

這些框架都有他們各自的優缺點。當每位程式設計師在建構應用程式時所選擇的工具,會依他們各自的風格和優先的考量不同而不同。CodeIgniter 是用來快速開發 PHP 程式的一套開放原始碼應用程式框架,而它因為以下幾個特色而聞名:

1. 小巧的框架

2. 出色的性能

3. 好上手

4. 清晰、完整的文件

5. 幾乎零配置的框架

6. 不需使用命令行

7. 非大規模集成類

CodeIgniter 會吸引我的注意是因為它好上手、好擴充。而且它有許多可使用的輔助程式、函式庫、外掛程式。所有你需要的工具都在一個小程式包裡,若你覺得不夠,你也可以建立你自己的函式庫。CodeIgniter 也有一些安全的工具,對於使用者和開發者來說,安全是很重要的。跨網站指令碼 (XSS) 是常見的應用層網路攻擊之一。CodeIgniter 可以自動過濾所有遇見的 POST 和 COOKIE 值,也可以只針對一些項目來過濾,用來防止跨網站指令碼攻擊。

CodeIgniter 2.0.2 版本已經釋出。這次升級主要是針對安全性的漏洞,跨網站指令碼 (XSS) 過濾器也做了一些修正。

http://codeigniter.com/

甚麼是機器學習?

HH Tu 的照片

在現實生活中,如果程式設計師想要解決一個文字剖析問題,可能會透過寫演算法來解決。而常見的做法通常是要有適當的檔案輸入,寫出一系列連續的指令而且有效率的做出加減乘除等動作,達到剖析的目的地之後,再加以輸出。但是這並不能達到這世界上解決所有問題的辦法。有些東西並沒有一定的規律來讓我們寫固定的演算法解決,例如說: 直接寫個演算法判斷一封信是不是垃圾郵件。我們可以看到信,如果今天是透過人眼人腦,可以說出它是不是垃圾信,可是單純靠個簡單的演算法,可能就不是件輕易的事情,甚至也不一定存在。

更進一步來說,垃圾信的可能信有很多種,而且會有部分的資訊並不一定會在人腦中,如果今天我們可以透過電腦幫我們收集資料,並且自動的截取出適合的資訊,透過現有的基礎演算法來幫我們排序分類…等,更甚至可以加以學習那就太棒了,這重點在於–我們沒有直接的演算法,但是我們有資料。

從郵件分析這點出發,假設今天我們擁有了成千上萬的客戶,但是遍布全球,而每天的信件上千萬封郵件,如果今天只是單純的想要知道一封信是否是垃圾郵件,照傳統的統計分析,可會花費相當龐大的時間與金錢;更甚者,垃圾發信的花樣事會隨著時間日益更新,郵件類型也會隨著區域的不同而改變,若只是遵照傳統的規則走,必定會有失敗的一天。從這個角度來看,假設我們知道了這個信其實是從這個垃圾商發送的,或者是這是上面總經理發布命令下來的信件,我們就可以很簡單的處理,可以快速的寫下程式去過濾它。但事實上這並不是一件簡單明瞭的事情。

仔細來看,其實垃圾信並不是隨機的出現,而且也並不是無法跟正常信無法區別!如果今天我們能夠收集並且整理夠多的資料,從中加以假設跟分析,或許不會全然一樣,但是我們期待的是可以找到夠好而且夠接近期待的預測。因為完全的預測是不可能的(除非你是上帝),但是我們希望的是從資料中自動找到有用的資訊,並且分析出一定的結果出來。這樣的流程跟思考就是機器學習的價值所在。

在目前的社會上,機器學習的應用相當廣泛,網路流量的辨識來達到最佳化、銀行的借貸信用評比、股票的預測、醫學上的臨床參考數據、生物上的神經系統、甚至是太空計畫諸如此類,近代有名的則是電腦下西洋棋跟人腦競賽。可以顯示出,機器學習的應用是重要的,但是它到底是怎麼學的呢? 從人的思考下手!!

我們是如何辨識電子信件是不是垃圾信? 你能說出個所以然嗎? 因為它跟我每天收的正常信不一樣,所以它是垃圾信、因為它帶有奇怪的內容、因為寄來的人沒看過、這些通通沒有一個準則。再舉一個例子:人臉辨識,你能說出為甚麼你認得你的爸爸你的媽媽的臉嗎? 因為他們從出生你就看到了、因為他們不是不熟的人所以認的出、他們每天都看到所以不覺得奇怪所以好認、但是一樣沒有準則。從上面兩個例子看到相近的地方,其實我們腦中還是有所謂的特徵的,人的輪廓,信的第一眼印象,人臉對稱的,信會有文字,人有眼睛、鼻子、嘴巴,信會有收信寄信附加檔案等屬性…等等,其實這些就是平常我們判斷的依據,但是因為可能性太多,人無法直接寫一條規則去解決這個問題,所以機器學習就此誕生,透過電腦自動的收集資料,加以分析找出有用的特徵(也就是上述的屬性),並且配合著我們想要的目的,例如分析人臉或者是找出垃圾信。

現代的機器學習,充斥著大量的統計微積分等的理論在背後支持,因為我們要找到相關性跟最佳化來達到目的,所以會利用到這兩個因子。機器學習過程則分成兩大部分,第一點就是學習,透過大量的資料數據,來產生出有用的模型並且可以當為代表;第二點則是預測,將之前學習好的模型來輸入未來想要預估的資料,並且產出有用的資訊,對於現實上來說,甚至會持續的學習新的資料。 不過說起來簡單,實際上卻是考慮了相當多的事情在裡面。