Archive for the 'Engineering' category

進階版的排程管理工具 Airflow

十二月 19 2016 Published by under Engineering

Airflow Introduction  markdown版本

前言

最近 EZTABLE 因應紅包活動,希望提高抽紅包的人與發紅包的人參與感,因此不論是抽到紅包、發出紅包,或是更進階朋友拿紅包錢去消費你所能獲得100元的回饋諸如此類的情境,都會發信通知。由於希望寄件人呈現的方式是 某某某 via EZTABLE,支援客製化寄件人名稱的服務相對較少,平常比較常聽到的 Mailgun、Mailchimp 只能被排除。一開始我們採用的是 Amazon Simple Email Service (SES),雖然很非常方便,只要給他 sender 資料、receiver 資料與 html 就好,但是每分鐘只能寄出 14 封信,而且很難追蹤哪些信已經寄出了,最慘的是由於 email 是個非常容易打錯的欄位,我們寄了一萬封之後就因為太多無效的 email 而收到 Amazon 的警告信,為此我還寫了一封非常卑微的道歉信,但是完全沒有任何作用哈哈。

最後還是回到老路 Salseforce Marketing Cloud(以下簡稱 MC),MC 有個 Trigger Send 的服務和 SES 有點像,打資料打到相對應的端點,資料沒問題就會幫你把信放到 Queue 裡面準備寄送,但是最麻煩的一點就是,想要寄信前必須要先幫每一個要寄信的對象建立 Subscriber,每個 Subscriber 需要包含一組唯一的 Key 與正確的 Email,如果 Email 沒有通過 MC 的檢驗就無法正確建立 Subscriber,MC 在寄信前會檢查提供的 Key 與 Email 是不是和當初在 Subscriber 上設定的一樣,不一樣就會出錯。

假設今天會員 Luffy receiver 抽到 Luffy sender 發的紅包 207 元

Luffy Receiver 會收到下面這封信與外加一封簡訊

Luffy Sender 會收到

一開始我們的策略是直接在程式碼裡面新增 Subscriber,如果 Subscriber 已經存在,就必須更新他的 Email,確保 Subscriber 的 Email 和我們要寄的 Email 是一致的不然會出錯,但是這一段是 Soap Api,非常的慢,而且不只要建立 EZ 的會員資料,還要更新 TABLE 的 Email,步驟非常繁複,但是能確保寄信前資料已經更新完畢。但是速度真的是慢到讓人受不了,實測結果一小時最多寄送給發紅包與收紅包的人各 800 封信,處理平常的流量還可以接受,但是一遇到大流量就會卡住,造成抽紅包與收信之間過大的延遲。所以最後我們決定把新增 Subscriber 與寄送 Email 與 SMS 的工作拆分開來。

更新 Subscriber 改用 FTP 上傳,並且設定好更新 Subscriber 的規則,一上傳成功就會觸發更新。等待一段時間,等待更新完成再來發信。但就是等待這個邏輯我一直不想要加在程式裡面,而最基本的 cron 不容易建立 job 之間的依賴性關係,最後決定採用 Airbnb 開源的 Airflow,因為它可以幫我們解決相依性的問題。

Airflow 有很多很棒的優點:
– 視覺化呈現工作狀態、相依性、執行時間
– 和各種服務整合(mysql、postgresql、s3、hive、slack…)
– 集中日誌功能
– 失敗/成功寄信
– 設置失敗重試次數

工作管理主頁面


詳細開始時間結束時間與 Log

相依性:同步資料 -> 等待 -> 寄送 Email/SMS

最近的工作

甘特圖

執行時間

往後我也會把原本在運行的 Cron 搬到 Airflow 上面,統一集中控管,再也不用每一個工作都加入失敗要用 slack 通知的程式碼了,而且這精美的 Dashboard 真的很潮啊!

 

簡易安裝操作教學:

“`
# install from pypi using pip
pip install airflow

#選擇你想要用的插件
pip install airflow[mysql, postgres, slack]

# 修改 config 檔
load_examples = False
# 預設DB是用 SQLite,建議正式使用時改用 Mysql、Mssql 或是 Postgresql 等較為正式的 DB,有比較好用的管理套件可以使用
executor = LocalExecutor # For SQLite
executor = SequentialExecutor # For Other DB,如果選這個記得改 sql_alchemy_conn 的 link
executor = CeleryExecutor # 尚未研究

# 到 airflow 資料夾底下新增兩個資料夾,dags 裡面放想要新增的工作
mkdir dags logs

# initialize the database
airflow initdb

# start the web server, default port is 8080
airflow webserver -p 8080

“`

以下就是這次寄信的 DAG
“`python
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedelta

default_args = {
‘owner’: ‘luffy’,
‘start_date’: datetime.now(),
’email’: [“],
’email_on_failure’: True,
’email_on_retry’: False,
‘retries’: 1,
‘retry_delay’: timedelta(minutes=5),
}

dag = DAG(‘MCWork’, default_args=default_args, schedule_interval=’*/10 * * * *’)

# Sync name, email of receivers and senders, and then upload to maketing cloud to trigger subscribers update
t1 = BashOperator(
task_id=’syncMarketingCloud’,
bash_command=’/Users/eztable/workspace/script/RED_ENV/bin/python /Users/eztable/workspace/script/syncMarketingCloud.py’,
dag=dag)

# Wait 2 minutes
t2 = BashOperator(
task_id=’sleep’,
bash_command=’/Users/eztable/workspace/script/RED_ENV/bin/python /Users/eztable/airflow/dags/sleep.py 120′,
dag=dag)

t3 = BashOperator(
task_id=’EDM’,
bash_command=’/Users/eztable/workspace/script/RED_ENV/bin/python /Users/eztable/workspace/script/EDM.py’,
dag=dag)

t4 = BashOperator(
task_id=’SMS’,
bash_command=’/Users/eztable/workspace/script/RED_ENV/bin/python /Users/eztable/workspace/script/SMS.py’,
dag=dag)

t2.set_upstream(t1)
t3.set_upstream(t2)
t4.set_upstream(t2)

“`

相關教學連結
– http://www.csdn.net/article/1970-01-01/2825690
– http://tech.marksblogg.com/airflow-postgres-redis-forex.html
– https://www.youtube.com/watch?v=60FUHEkcPyY

No responses yet

一場三年後的回顧

十月 09 2016 Published by under Engineering, EZ心情

本文為向前學長 玉子燒 的 一場三年的賭注 致敬。

三年前某日的研究所聚會(右二)

三年前從研究所畢業,萌懂地進入職場。憶起那時的我,說多矬有多矬,多青澀有多青澀,多白目有多白目,著實讓人會心一笑。我的個性內向怕生,甚至遇到不認識的人,通常漲得滿臉通紅。但私底下的我,其實是喜歡玩爛梗,無厘頭搞笑的人。


還記得在第一次在公司的全體會議上自我介紹,我當時臉紅通通,牽強地說出:『你們… 好,我叫 mi…ke ,之後要做 Androi..d 的,請多指.. 教。』

那時明顯地感受到自己採低姿態的述說就已經沒有氣勢,加上又表現得很害羞的模樣,更讓自己成為大家的笑柄。當時的內心充滿恐懼,懊悔自己為何這麼怯場。這份氛圍跟著我相處足足一年之久,我不斷地故步自封,採低姿態的與人交談。因為知道自己的表達能力不足,懼怕與人互動,長久只處在自己隸屬的工程團隊底下。

曾經有一次與主管交談,他說:『你的生活經驗不夠,你要多培養這塊。不然無法跟人有所交流。』

我長久以來一直賴在電腦相關的領域底下,生活的活動也圍繞著它,比如:打電動、看技術文章、寫程式。再加上生活圈也從來沒有太大的變化。如果在這樣的環境底下,期待周遭能有所變化,根本是無稽之談

所幸我待的公司本身是一個大熔爐,大概每一年會有一批新人進來,另一批人離職。我並不是在幸在樂禍公司怎麼留不住人。人才本來就有去有留,這是很正常的事情。在這種情況下,我認識了各式各樣的人,無論是國籍不同、想法不同、生活不同、技術背景不同,在與他們共事下,我學到新的技術、想法,甚至參與未曾體驗過的生活。

2016某日的 Dress code (單寧)

原本我遇到溝通就會心生畏懼或緊張,雖然到現在也有,不過我已經能夠控制自己,面對這份心情,調適自己,讓它轉化成一股助力:因為我感到[畏懼|緊張|亢奮],相信這個體驗是前所未有的,值得試一試。

對比三年前的自己,我不再那麼怕生,反而覺得該適時的主動關心對方,讓對方對你不再那麼生疏。也不再那麼畏懼做一件值得做的事情,因為心理渴望所以更不想錯過嘗試的機會。


題外話:最近被我的產品經理問到:『如果你遇到三年前的自己,你會怎麼幫助他!?』- 我也許會開始嘗試分享我的想法,沖淡他內心的不安感,彰顯他內在潛在的渴望,將想表達的話語,自信地傳達出來。

 

想創造更有價值的 EZTABLE? 請從此 登入

No responses yet

2016 HackNTU 心得

九月 18 2016 Published by under Engineering

%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-22-49-39
第一次參加黑客松,抱著非常期待的心情參加,覺得身為工程師沒有參加過黑客松應該會讓心中留下一個疙瘩。當初很猶豫,到底要去 Coscup(吃東西) 還是 HackNTU(虐自己),經過衡量的結果,因為 Coscup 會有錄影,所以還是趁現在畢業沒多久還有肝可以燒的時候衝一發駭客松吧!沒想到參加了之後才知道自己已經過了能夠熬夜的年紀 XD

我們團隊總共有六個人,就不詳細介紹是怎麼認識的了~嚴格來說這算是第一次各司其職的團隊合作。

我們的作品結合台北市政府動物園的開放資料與經營遊戲的元素,是一個具有教育意義,希望小孩子除了寶可夢之外也能了解真正的動物長什麼樣子的小遊戲,使用者扮演了造物者的角色,可以在遊戲中能量水晶來製造動物,再透過能量寶石為他們進行冰火雷三種屬性的升級,動物越多,代表這些生物在星球的互動越多,生成能量水晶的速度也越快。身為造物主你還可以對星球施放雷電,這能促使有機物質的生成,增加能量水晶。除了可以幫每一隻動物取名字之外,也能與動物對話喲!(這部分現在好像有點故障 XD)

Github: https://github.com/jcjohnson/neural-style
Demo: https://leetcodetaiwan.github.io/animix/#/

%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-23-01-05%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-21-34-08

%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-23-01-19%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-22-51-51

 

使用技術:

  • AngularJS
  • Waston API:負責扮演動物與使用者對話
  • Neuro Style:藉由 ML 技術學習一張圖片的風格與另一張圖片融和,如下圖所示

%e8%9e%a2%e5%b9%95%e6%88%aa%e5%9c%96-2016-09-17-22-55-44

我的貢獻:

  • 找到一顆美麗的星球
  • 跟著滑鼠點擊的閃電
  • 讓動物繞著星球轉轉
  • 創造生物的花費水晶的邏輯

 

分享幾個印象深刻的部分:

形成共識不容易
星期五從零開始決定了題目之後,開始討論遊戲該如何呈現,有些人想像的畫面很精緻,互動很豐富,有些人的想像比較單純簡單,但是用言語不容易辦法表達出之間的差異,才會發展出要不要改用非正規網頁呈現方式來製作遊戲,例如用 Google Extension 修改 Facebook 的介面,或是用 Facebook Bot Api 製作互動遊戲等等的想法,最後是透過紙筆以及相似的遊戲來達成共識。

設計遊戲元素很有趣
剛開始我們發想了很多元素,但是這些元素與遊戲的關聯性是什麼,都讓我們絞盡腦汁。
為什麼要進化?雷電有什麼功用?要挑選動物園的哪些動物?
這是一個從發散到收斂的過程,這種目標漸漸一致的感覺很棒!

做知識類的遊戲很有挑戰性
想要將知識與遊戲結合真的非常有挑戰性,想要遊戲好玩,知識的量就要減少。但是想要教育意義多一點,又怕太過嚴肅沒辦法吸引小孩子。我們的遊戲在這方面遇到了很大的困難。

沒有測試者很痛苦
沒有目標使用者 – 小孩子,可以幫我們測試這個點子,那我們就只能單純靠想像為他們設計遊戲,我覺得如果能早一點決定題目就能早一點驗證這個想法,才不會到了最後才發現方向走錯了。

請做好禦寒措施
因為冷氣很強,會場也沒有準備熱飲,所以一定要帶保暖衣物。

已經不再是少年
星期六到星期日凌晨的這段時間好難熬,好像寫到三四點吧,之後躺在沙發上睡著,好像還睡到流口水哈哈~另外熬夜好傷身,那個週末生理與心理完全沒有休息到的感覺,週一上班覺得特別累,星期一回家睡了很久才稍稍恢復。

對 HackNTU 的抱怨

  • 太多需要用紙筆寫的東西了,到了會場需要簽名還蠻傻眼的,應該可以電子化吧?
  • T-shirt 太瞎,後面印了一堆贊助廠商的 LOGO 穿出門根本是羞恥 PLAY,浪費了正面的好設計
  • 到了星期日最後一天,卻沒有補充飲料和食物,讓熬夜的人很想死
  • 硬性規定組隊人數真的很無聊,還用大會報告發現人數超過就取消資格到底意義何在?現場都有隊伍是拿著完成度很高的東西來比賽的,想維持公平性限制人數有什麼用?駭客松的目的是什麼?我還以為是在解決問題呢?
  • 部分組別因為評審的 DELAY 而被壓縮 Demo 時間實在是爛透了

No responses yet

工程師的空拍機

八月 30 2016 Published by under Engineering, EZ教學

最近我買了一台空拍機,所以今天想要來跟大家介紹一下。

相信大家最近都有注意到空拍機的廣告,新聞還有影片。台灣許多外拍的綜藝節目也開始利用空拍機來呈現更好的節目內容。新聞台更是利用空拍機來捕捉比較大規模的畫面,像是因為美濃地震而震垮的維冠金龍大樓。

 1

網路上也瘋傳許多空拍機墜毀畫面跟一些空拍機有多危險的負面新聞,像是一位滑雪選手在比賽中差點被空拍機砸到而影響到賽程。

看到這些驚悚畫面,大多數的人應該會覺得空拍機是一個很危險的玩具,甚至覺得他不應該出現在市區。但是我個人認為這些事件其實算是少數的,但因為他的畫面驚悚,所以上了新聞,讓大眾對他有個不好的印象。也有許多人對他不夠瞭解,認為他只是一個會造成大家困擾的飛行照相機。像許多交通事故,大多數的空拍機的意外通常都是在玩家不遵守法規,還有在不安全狀況下控制才造成的。

空拍機除了製造了許多爭議還有一些驚悚畫面,他其實也帶給我們平常看不到的美景。像是這個在台灣拍攝的空拍影片:

就是因為這種畫面,讓我砸了大錢買了一台空拍機來重新認識這個世界。

而我會開始拍攝這些美麗的畫面,和大家分享世界和空拍機的美好,請大家繼續關注 EZTABLE IDEAS!

2016/8/30 eric

No responses yet

Promise in JavaScript (ES6)

八月 01 2016 Published by under Engineering

* 什麼是Promise? 為什麼需要Promise?

 

JavaScript和許多語言相比有些讓人難以捉模的特性
其中一個特別的特性是「非同步/異步(asynchronous)」
和其他同步的語言不一樣,JS的程式碼不一定會一行一行按照寫的順序執行

 

setTimeout(function() {
    console.log(0)
}, 1000)
console.log(1)

 

在其他語言我們可能會看到先顯示0,過一秒後再顯示1
但在JavaScript之中這一段會先顯示1,過一秒後再顯示0

這種特性讓我們需要多做些處理來確保執行順序的正確
像是傳統的callback方式

 

function foo(callback) {
    setTimeout(function() {
        console.log(0)
        if (callback) {
            callback()
        }
    }, 1000)
}

function bar() {
    console.log(1)
}

foo(bar);

 

像這樣顯示順序就會是01

我們可以把function傳遞到非同步function的參數中
讓他們在執行非同步的動作後進行想要的動作

但這種做法常常會產生所謂的callback hell,造成程式碼難以維護。

 

* Promise in ES6

 

雖然在ES6之前就有一些類似的Pattern(例如deffered)
但在這邊我們以ES6為主介紹

Promise是一個物件
在建立時你需要給他一個function,告訴他要做哪些事

例如,過一秒後顯示0

 

function toDo() {
    setTimeout(function() {
        console.log(0)
    }, 1000)
}

 

同時我們也要決定這個function什麼時候會’被完成’
Promise在呼叫我們的toDo時會順便多傳兩個變數
分別是resolve和reject
決定’完成’以及’出現問題’的時機、以及到時該回傳的變數

 

function toDo(resolve, reject) {
    setTimeout(function() {
        console.log(0)
        resolve(true)
    }, 1000)
}

 

決定好這個Promise要做的事情後,我們就可以用它建立一個Promise,並且呼叫他

 

let promise = new Promise(toDo)

promise()

 

而Promise以及類似的物件(例如deffered)在執行後都會是一個thenable的物件
其中都會有一個.then()的function讓你告訴他接下來該做的事情

 

promise()
    .then(function(success) {
        console.log(100)
    })

 

還記得上面我們resolve時傳了一個true嗎?
Promise內resolve所帶的值會傳到下一個then,變成下一個動作的參數

而Promise特別的地方在於
.then之後可以拿來做method chaining
或是再次return一個Promise

 

promise()
    .then(function(result) {
        return new Promise(function(resolve) {
            resolve({
                result: result
            })
        })
    })
    .then(JSON.stringify)
    .then(function(jsonString) {
        console.log(jsonString) // '{"result": true}'
    })

 

假若是要同時處理數個Promise
亦可以用Promise.all()來處理

 

Promise.all([promise1, promise2, promise3])
    .then(function(result) {
        console.log(result[0]) // promise1的結果
        console.log(result[1]) // promise2的結果
        console.log(result[2]) // promise3的結果
    })

 

Promise.all會在三個Promise都處理完(不分順序)之後,進行then的動作
可以拿來確保之前所有前置準備都已經做完

有時我們可能只是要建立一個Promise,但其實結果馬上就會拿到(並非非同步動作)
ES6也提供了Promise.resolve以及Promise.reject的方法

 

let promise = Promise.resolve('hi')

promise()
    .then(console.log) // 'hi'

 

雖然處理Async還有ES6的Generater以及ES7的Async Function能使用
但Promise已經是很泛用,能解決許多問題,好理解,也不至於雜亂的寫法了。
要寫出好懂簡單的JavaScript,一定要搞懂Promise~!

更多Promise的用法,例如Error Handle,可以參考MDN的文件

No responses yet

清邁遠距作業後記

七月 14 2016 Published by under Engineering

本文為 我在清邁,你在哪 的短篇後記。

Continue Reading »

No responses yet

寶貝,晚餐想吃什麼?讓我們去有帥哥氣氛又好的餐廳吧~

七月 05 2016 Published by under Engineering

1511a2f4-651c-45d4-8abe-000947e56bf4.1511a2f4-6514-4f57-b9ee-a78ca10c5da5.png.cf

建議點這裡 Markdown 好讀版

有一對情侶正為晚餐不知道要吃什麼而煩惱…

  • 男:寶貝,晚餐想吃什麼?
  • 女:都可以呀!
  • 男:我們去吃久久神鍋好不好?
  • 女:很熱欸~
  • 男:那去轉角吃涼麵怎麼樣?
  • 女:那又沒有冷氣吹~
  • 男:找一家有帥哥店員的好不好?
  • 女:好!讓我們去有帥哥氣氛又好的餐廳吧~
  • 男:😂😂😂

男友不禁想問,為什麼找一家餐廳會這麼困難呢?氣氛要好又要有帥哥店員的餐廳到底在哪裡?換個角度想,炎炎夏日,為什麼找不到一家主打充滿陽光、沙灘、比基尼這種夏日風情的餐廳?我們常常在餐廳享受的不只是食物,而是享受餐廳營造的氣氛,餐廳營造的可以是一個人與食物的寧靜對話,可以是三五好友歡聚的燒烤派對,當然也可以是家人一同聚餐的溫馨。

這是一篇關於如何透過情境搜尋餐廳的文章可以直接往下看結果

專案緣起

不知道大家最近有沒有看到一篇 PTT 上的文章?作者對約 X 信進行語義分析,內容專業到讓人無法直視,看的當下就覺得:哇!原來語意分析還有這種應用的方式!程式語言是用來幫忙解決問題的好工具,能把它應用到生活大小事上真的很棒!這篇文章燃起了我心中對文字探勘的熱情,剛好最近有個比賽會需要這方面的技術(才不是因為 PIXNET HACKTHON 的比賽能不能順利參加而抱著不服輸的心態呢!)

由於本身對資料分析很有興趣,尤其是圖像分析和語意分析,因為他們能夠應用的範疇很廣,而且已經不知不覺地影響著這個世界的運行,例如無人車駕駛、Alphago、SkyRec、IBM Waston 等等。這個領域的知識又深又廣,既然要朝這個方向持續邁進,平常就要有所累積。公司正在朝著將情境與餐廳建立連結轉型,正好和我有興趣的領域有所重疊,所以對於這個專案我也有比平常玩玩還認真的使命感,於是便花了星期六和星期日的上午把做了一些有趣的東西。

 

工具介紹

大多數的公司使用 Solr, Elasticsearch 建置搜尋引擎,有些還會直接嵌入 Google 搜尋列,前者運用的方法是 TF-IDF,後者就是借助 Google 強大的搜尋演算法。但是沒有一種方法是完美的,如果今天下的關鍵字比較多,想要透過「酒館」和「義式」搜尋餐廳,就會發現沒有我要的結果,但是這兩個關鍵字如果分開來就都能得到結果,事實上,這兩個關鍵應該是有著相關性的,但是透過 TF-IDF 卻無法知道。如果可以將這兩個關鍵字的特性相加之後得到一個新的特性,再用新的特性去尋找最相近的餐廳就太棒了!

這就是本篇文章會運用到的概念,這個概念的基礎是 Word2Vec,它很適合用來對文字、圖像、聲音進行模糊搜尋,由於運作原理一言難盡(死線要到啦),我就直接說重點:透過訓練將詞會投影到高維度的向量空間,相近的詞彙有相近的詞向量。

而詞向量有個特性是可以透過相加減獲得有趣的結果,例如:國王 - 男人 + 女人 ~= 皇后

 

操作流程

1. 收集連結:收集公司合作餐廳的食記連結,並且把餐廳資訊與餐廳食記連結輸出成文字檔,檔案內沒有提供連結。

執行 python getUrl.py

2. 爬網站 & 擷取資訊:過濾非 Pixnet 連結透過 requests 結合 multiprocessing 爬網站的 Html。使用 PyQuery 擷取網站標題與內容,並且存到 Sqlite。

執行 python getBlog.py

3. 斷詞:使用 Jieba 對文字進行預處理,轉換成 Word2Vec 能夠訓練的格式。

執行python cut.py

4. 訓練:透過在 gensim 中實作的 Word2Vec,設定參數對資料進行訓練,產生詞向量與模型。(直接使用 52nlp 提供的檔案)

執行 python train_word2vec_model.py training_sentence.txt model_name.model vector_name.vector

 

注意事項

在專案中主要遇到兩個困難:

    • 處理中文字遇到的編碼問題:Unicode、UTF-8 與 ASCII 之間錯綜複雜的關係,不同套件的輸入的接口要求的編碼可能不一樣。
    • 使用 multiprocess 要小心:原因還沒有弄清楚,只要在 the_function 裡面加入了 pyquery 或是 sqlite 的 function 就會 crash,但是放 requests 就沒事。


from multiprocessing import Pool
p = Pool(5)
results = p.map(the_fucntion, inputs)

 

專案成果

1. 先載入 gensim 套件與剛剛訓練好的 model

import gensim
# print result
def ps(result):
if result:
for e in result:
print e[0], e[1]
# load fresh model
model = gensim.models.Word2Vec.load("articles_rname.model")


>>> result = model.most_similar(u"夏天 海灘 餐廳".split(" "), topn=5)
>>> ps(result)
'皮椅' 0.694285988808
'LOUNGE' 0.688326239586
'HALEAKALA' 0.68235886097
'仿舊' 0.674678146839
'小徑' 0.662850260735

我們想要的結果是根據情境找到符合的餐廳,但是得出的結果只有2家餐廳,2個名詞,1個形容詞。因此我們必須建立涵蓋訓練集餐廳的 list,把這個 list 的詞向量拿出來與我們想要搜尋的情境詞向量進行相似度的計算。特別感謝 jimgoo 提供的 most_similar_in_list function,讓我可以直接使用。


>>> print(rname_list[:5])
[u'Follow', u'Bellini', u'TABLE', u'Taverna', u'90']
>>> print(mapping(rname_list[:5]))
[u'Follow Lady 法蕾蒂', u'Bellini Pasta Pasta', u'TABLE JOE 喬桌子廚房', u'Taverna De Medici 梅帝騎小酒館', u'90 a la sante 酒食歐風朝']

>>> result = model.most_similar_in_list(u"夏天 海灘".split(" “), topn=5, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘VG Cafe & Bistro’ 0.650945961475
‘HALEAKALA 夏威夷酒吧餐廳’ 0.615895032883
‘Eslite Tea Room’ 0.599678635597
‘URBAN331-台北慕軒飯店’ 0.579266548157
‘Destino 妳是我的命運’ 0.57857131958

>>> result = model.most_similar_in_list(u"消暑 下午 茶".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Caldo Cafe咖朵咖啡’ 0.47723197937
‘Eslite Tea Room’ 0.468698769808
‘H-Bar’ 0.460396289825

>>> result = model.most_similar_in_list(u"正妹 店員".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘etage15-高雄Hotel dua’ 0.468320250511
‘Sunny Cafe’ 0.447554886341
‘Kevin Coffee’ 0.418976008892

>>> result = model.most_similar_in_list(u"音樂 悠閒".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Mammoth lounge’ 0.670462846756
‘HALEAKALA 夏威夷酒吧餐廳’ 0.626639544964
‘RUBY CAFE’ 0.6229159832

>>> result = model.most_similar_in_list(u"工程師".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘American Steakhouse’ 0.802481234074
‘i sweet’ 0.785791814327
‘Silk Road Feast 絲路宴餐廳’ 0.776082456112

>>> result = model.most_similar_in_list(u"求婚 紀念".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Ton Up Cafe’ 0.62010884285
‘TABLE JOE 喬桌子廚房’ 0.608335494995
‘URBAN331-台北慕軒飯店’ 0.606325864792

>>> result = model.most_similar_in_list(u"酒 餐廳 美式 跨年".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘bar & restaurant a³ 新義式餐廳’ 0.665651142597
‘MW 時尚義法料理&酒品’ 0.665459275246
‘Le Bar 吧 戶外餐廳’ 0.644170224667

這些結果很有趣,有空再來分析~

 

心得 & 未來展望

  • 餐廳的食記數量不夠多,或是數量不平均,會影響到訓練結果
  • 改成收集評論可能會更精準
  • 將多為向量壓到二維,可以拿來做 clustering
  • 文字處理不容易但是很重要
  • 多國語言搜尋也能配合 Word2Vec

 

 

特別感謝 & 參考資源

Python 有很多好用的套件,像是中文斷詞有 jieba,word2vec 有 gensim,用起來上手很快,而且還有熱心的大大們不吝分享與教學。

No responses yet

工程師都是好人

六月 03 2016 Published by under Engineering

 07

 

身為一名工程師,又和這麼多工程師共事過,我得說工程師們都是好人。

——

 

台灣的街道上充斥著各式各樣的工程師,有男有女,有矮有胖,有討人厭更有惹人憐愛的。

那怕只是去隔壁巷口買個鹹酥雞,可能都有好幾個工程師排在你前面。

如果在街上大喊 “那邊那位工程師請留步!" ,我想整個世界應該都會為你而靜止。

但是雖然台灣有著這麼多的工程師,但普羅大眾卻都不瞭解工程師,

除了不瞭解以外,還對工程師有些既定的刻板印象,

不瞭解事小,但誤會事大。

身為工程師的一份子,我認為我有這個責任站出來為工程師發聲。

 

1. 工程師 =\= 肥宅

不知道為什麼只要一提到工程師,許多人腦裡就會浮現肥宅的樣子,

覺得工程師都衣衫襤褸,穿著好幾年前的領口早已鬆脫的系服,不然就是老媽買的迪索奈爾量販成衣,

耳機裡放的音樂一定是日本不知道哪個軟體唱的動畫主體曲。

在這裡,我得跟大家說,

穿系服,是代表著我們對學校的熱愛,穿媽媽的成衣,是代表我們的媽媽的感恩,

鬆脫的領口,恰恰代表著我們勤檢持家的精神

耳裡聽的音樂,不是膚淺的流行,而是科技的結晶。

而工程師因為工作內容的關係,必需長時間坐在電腦前,難免會有些職業傷害。

他們那微胖的身軀,是努力工作的證明。

而我們應該多包容這些為了台灣競爭力而努力殘害自己身體的英雄。

 

2. 工程師 =\= 怪人

很多人都認為,工程師似乎都是很奇怪的人,

他們覺得工程師都會看著螢幕怪笑,不然就是講一些奇怪的笑話,

雖然我必須承認,真的有這樣的工程師,而且我們公司就有這樣的工程師,

但是,這樣的工程師真的只是少數,大家不可以因為這樣少數的幾個異類,

就對全部的工程師存有這樣的偏見。

我就認識許多正常到不行又充滿幽默感的工程師,像我就是一個很好的例子。

 

3. 工程師什麼都要講究邏輯煩死人了

雖然說我們每天的工作都跟邏輯脫不了什麼關係,但這其實不代表說我們就連日常生活中也很講究邏輯。

像我明明就只有一雙手,但卻擁有五個鍵盤,六隻滑鼠,

這種毫無邏輯的事情,在工程師的日常生活中也是相當常見的事,

有的時候我們只是實事求是,希望探索事情的真理而已,

所以當覺得面前的工程師蠻口邏輯煩死人了的時候,不彷先冷靜的想想對方講的話是不是真的有點道理。

在這邊我幫大家整理了一個應對懶人包,大家不坊參考看看。

 

    if (面前的工程師有理) {
        // 膚衍他幾句說我知道了;
    } else if (面前的工程師是肥宅) {
        // break;
    } else if (面前的工程師是帥哥) {
        // Logic Error;
    }

 

4. 關於女性工程師

很多人窮及一輩子都遇不到一個女性工程師,(有一部份的人是遇到了但死不承認對方是女性)

但我很幸運的在短短的職涯中就遇到了許多非常優秀的女工程師,

在這邊我得替她們發聲一下,因為大家實在是對她們有太多的成見了,

女生工程師的工作能力絕對是不輸給男性的,EZTABLE 裡就有著許多才貌兼具的女工程師,

有的事業有成,卻仍然心地善良年輕貌美,有的帶著笑容輕鬆扛住大量擁入的流量,

有的充滿愛心家裡養了許多小動物,不過偶而也會有吃飯不帶錢包這種女工程師出現就是了。

 

5. 工程師都是好人

我前面喇低賽喇了一長串,其實我想說的重點只有一個,就是工程師都是好人。

對大多數的工程師來說,他們沒有心機,沒有欺騙,

也許一開始你會覺得他們無趣,他們一成不變,

但到了最後,這才是最難能可貴的不是嗎?

你要到哪去找一個這樣永遠用真心對你的朋友呢?

不論你是要找尋另一半,或者是想找尋知心好友,

工程師絕對是你的一時之選。

所以下次遇到你公司對面的工程師們,別露出害怕嫌惡的表情,

多跟他們說幾句話吧,也許你會跟我一樣發現,

他們真的都是好人。

就跟我一樣。

 

2016.6.3    nose

No responses yet

我在清邁,你在哪?

四月 26 2016 Published by under Engineering

 

photo by Seth Werkheiser

 

台北 => 清邁 ,倒數 一週 出發!!

打這篇文章的同時,看著身旁的行李箱,

想到再過一週後,我已經在清邁。

對於即將到來的旅程,我精心策劃許久,

早已迫不急待想與你們分享我接下的旅程。

這趟旅程為期一個月,包含工作與旅遊。

 

我是不是提到工作

沒錯,就是工作。

也許你會想:『何不就放假旅遊,輕輕鬆鬆不就好哩,為何要跟工作綁在一起?』

的確,單純的旅遊是最讓人放鬆又沒壓力的行程。

但如果我可以在工作之餘,嘗試當地的生活品味,

這個意義就不僅是『旅遊』,而是融入當地的生活之中,成為短期的泰國人。

 

地點X時間X工作

泰國偏熱均溫約莫 30 幾度,

如果地點有樹蔭和各種調節溫度設備是最佳的的選項。

當地有不少 Coworkspaces 或 Coffee shops,除了提供咖啡、水、小點心外,

還有穩定的 Wifi 。我從中找到 PUNSPACE

這間看起來有種度假村的感覺,加上四處都是大片的落地窗,在裡頭工作也能享受外頭的景緻。

由於時差約比台灣早 一小時,所以要提前到那邊就緒。

稍微享受陽光後,開啟 Google Hangout ,與台灣團隊開 stand up meeting。

之後,開啟一天的工作。

在工作期間,基本上我們都以 Slack 文字訊息溝通 ,

在不影響工作的節奏,又能快速同步任何問題。

若是需要面對面溝通的技術討論或是大型會議皆可 Google Hangout 解決。

我的團隊夥伴也能透過 Trello 來掌控我目前的工作進度。

除了讓產品經理確保整體產品的進度外,

也是我用來證明(我就算在泰國遠端工作,我的工作產能也不會有絲毫的下滑)的數據。

 

photo by Christian Junker | Photography

photo by Christian Junker | Photography

 

生活 & 旅遊行程規劃

身為短暫的當地人,手邊有一台方便的載具是必要的。當地有許多地方提供機車或腳踏車的出租服務。平日可以騎到離我住處不遠處的夜市,嘗遍各種道地的泰國美食,抑或體驗著名的『泰式按摩』。騎到泰國同事推薦的餐廳飽餐一頓。甚至來個不期而遇的人文探索。尤其在泰國有許多著名的廟宇,還有各種豐富的戶外活動,光是排行程就讓人費盡心思。

分享一下,我預計的旅行清單:(若你有推薦其他好玩的點,歡迎在底下留言!!

  • 大象自然公園
  • 夜間動物園
  • 清邁廟 
  • 叢林飛梭
  • 廚藝教室
  • 曼谷之旅 — 如果把旅程對比喻成音樂,在清邁緩慢的慢節奏,怎能少了曼谷緊湊高亢的都市生活。
  • 訂 EZTABLE 泰國餐廳 — 台灣 V.S. 泰國的使用自家的服務所帶來的用餐體驗,差異在哪,到底有多大?恰恰是我們做產品的人最直接的回饋。

 

結語:

我很慶幸 EZTABLE 的 CEO 和 主管們的思維前衛。

前天不久才在 廁所 遇到 CEO,

我提到我這趟旅程的計畫,他只笑笑回應:

 

『只要你把成績做到,

 

    才不管你人在哪裡工作,

 

    這也是 EZTABLE 公司的文化。』

 

" 只要你的產能有到,你便能享有自己的自由。"

如果你也想在自由的氣氛下工作,歡迎加入 EZTABLE

 

Mike Wu, EZTABLE Android Developer

No responses yet

Interactive data

四月 22 2016 Published by under Engineering

At EZTABLE, we encourage a self-serving model when asking questions regarding our massive database. For example, an account manager might ask a question such as “What’s the average age of all customers who made reservations in February of 2015?". Any backend engineer could quickly translate the question into the corresponding SQL query and run it against out MySQL database, however that defies our purpose of being transparent and self-serving. So the key element that we need is “an interface that let everyone in our company to interactively ask questions and learn from data". Enter metabase.

Metabase is an open source project that provides:

  1. Easy to setup
  2. Let anyone on your team ask questions without knowing SQL syntax
  3. Rich & beautiful dashboards

Before jumping into the juicy details, let’s first quickly go through a relational data model 101.

  • Tables
  • Columns
  • Rows
  • Relationships

Fundamentally data are stored in a database, which is a huge collection of tables, conceptually similar to a large Excel document that contains lots of sheets. Tables contain one or more columns and rows.

Tables

Fig 1. A member table.

All the cells in a column contain the same type of information. For example, in the sample table below, the name column contains name in each cell and member_id column contains the member ID.

A bookings table.

Fig 2. A bookings table.

A tables can contain references to other tables, which establishes a relationship between them. For example, a database can lookup the age of members based on the member_id column from the booking table.

Fig 3. Relationships between tables.

Fig 3. Relationships between tables.

With metabase, everyone in the company can quickly produce statistics by looking up demographics or anything they want based on relationships. Don’t worry, sensitive informations are hidden away.

Fig 4. Commonly used tables.

Fig 4. Commonly used tables.

Let’s get back to the main topic. How can metabase help us answering questions such as “What’s the average age of all customers who made reservations in February of 2015″? Let’s see a little animation.

 

Fig 5. Metabase in action.

Fig 5. Metabase in action. Click to enlarge.

 

Each part of our question can be translated to a corresponding element on the user interface, which is simple enough that anyone within our organization to play with and answer their own questions.

Fig 6. Questions translated to metabase UI.

Fig 6. Questions translated to metabase UI.

There more tricks that metabse can do e.g.

  1. Drawing charts.
  2. Create a dashboard for big screens.
  3. Export daily report to email or slack.

Subscribe to EZTABLE IDEAS for more articles!

hden

P.S. For those who use Facebook’s PrestoDB, Airbnb has release a similar tool called Airpal.

No responses yet

Older posts »