Thursday, September 21, 2017

Datomic 學習/使用心得

之前在研究 object-relation impedance mismatch 的時候,發現了 Datomic 這個資料庫,據說這個資料庫可以有效地迴避這個 object-relation impedance mismatch ,於是我找到機會後就來用看看。

學習的過程大概是這樣子:
1.  下載 datomic-free 的 docker 來用,並且寫 clojure 程式將資料塞入資料庫。
2.  註冊 datomic  的網站,取得 datomic 的 web console
3.  上一個 learn datalog today 的網站練習 Datomic 的 Query 怎麼寫。

踩過的坑:
(1) group-by
本來一度以為,Datomic 沒有支援 group-by 的語法。後來仔細查才發現,原來是 implicit 。而且要搭配 :with 語句來控制 group-by 的行為。
範例:
    [:find ?i (avg ?r)
     :with ?u
     :where  [?e :movie/rating ?r]
                  [?e :movie/id ?i]
                  [?e :user/id ?u]]
相當於
select movie_id, avg(rating * 1.0) from RATINGS group by movie_id;

實際測試中,我用電影資料庫,放了 100000 筆的電影評分資料 (user id, movie id, rating)。結果用 Datomic query 做 group-by average 花費了 3000 milliseconds。但是 H2 database 卻只用了 500 milliseconds

( 註:做上述的實驗時,我對 Datomic 頗不熟,也因此沒有對 Datomic 設定 index 。然而, H2 database 卻有設定 index ,所以其實這個比較並不公平。由於電影資料的特性,其實可以考慮將 :/user/id:movie/id 這兩個 schema 都設定為 :db/unique )

(2) transact-async
本來我照範例是用 transact ,結果當有大量資料一開始要匯入時,資料庫就發生 timeout exception 了。查了論壇後,才發現因為 transact 函數內建的 timeout 是十秒。所以論壇上建議,遇到大量匯入或是資料庫在高負載時,要用 transact-async 。

If a system is under heavy load (e.g. an import job) then the default transaction timeout can be too short, and you should use transact-async so you can apply your own timeout logic.