Cascalog 入門(2)—— Outer Join,Combiners,Sorting 和其餘

這篇文章翻譯自 http://nathanmarz.com/blog/new-cascalog-features-outer-joins-combiners-sorting-and-more.html。如下進入正文。html

新特性 —— Outer Join,Combiners,Sorting 和其餘

第一篇教程譯文)中,我講了 Cascalog 的不少強大的功能:鏈接(join),累計(aggregates),子查詢(subqueries),自定義操做(custom operations),等等。從幾周前 Cascalog release 之後,我又加了不少新的特性,這些新特性使 Cascalog 更富有表現力、更強大,但絲絕不影響原有的簡潔和靈活。java

跟第一篇教程同樣,先經過如下命令把 playground 加載進來:bootstrap

lein compile-java && lein compile
lein repl
user=> (use 'cascalog.playground) (bootstrap)

Outer join

咱們在第一篇教程中就已經看到,你能夠用 Cascalog 把來自多個數據源的數據 join 在一塊兒,只要在多個數據源中使用相同的變量名。例如,在 age 和 gender 數據源中,咱們運行這一段代碼來獲得每一個人的年齡和性別:oop

user=> (?<- (stdout) [?person ?age ?gender]
          (age ?person ?age) (gender ?person ?gender))

這實際上是一個 inner join,只有在兩個數據集中都出現的人才會出如今結果中。咱們能夠這樣作 outer join :優化

user=> (?<- (stdout) [?person !!age !!gender]
          (age ?person !!age) (gender ?person !!gender))

這個查詢的結果對於沒有在 age 或 gender 數據集中沒有出現的人,用空值替代不存在的值。翻譯

Cascalog 的 outer join 由以 !! 開頭的變量名觸發,這些變量稱爲 「未決變量」(原文叫 "ungrounding variales"),包含未決變量的謂詞叫作 「未決謂詞」(原文叫 "unground predicate"),不包含未決變量的謂詞稱做 「已決謂詞」(原文叫 "ground predicate")。對兩個未決謂詞作 join 是一個 full outer join,對一個已決謂詞和一個未決謂詞作 join 是一個 left join。code

這裏有個 left join 的例子,獲取 person 數據集中全部人的 follow 關係,若是沒有 follow 關係則用空值代替:htm

user=> (?<- (stdout) [?person1 !!person2]
          (person ?person1) (follows ?person1 !!person2))

要拿到全部沒有 follow 關係的人,能夠這樣blog

user=> (?<- (stdout) [?person]
          (person ?person) (follows ?person !!p2) (nil? !!p2))

(nil? !!p2) 謂語是在 join 以後執行的,這是 Cascalog 的 outer join 語義中很重要的一部分。排序

如今咱們要數一下每一個人 follow 人的數量,正常的 count 累計器不會生效,由於那會計算全部元組的數量,但不會區分 follows 元組是否爲空。在這種狀況下,咱們須要對空的 follow 元組計數爲 0,對非空的計數爲 1,Cascalog 的 !count 累計器能夠作這件事:

user=> (?<- (stdout) [?person ?count]
          (person ?person) (follows ?person !!p2) (c/!count !!p2 :> ?count))

沒有 follow 關係的人會被計數爲 0。

一個未決變量只能在一個查詢中出現一次,其餘時候都跟正常變量同樣。

Combiners 和 「並行累計」

<!--more-->

常規的累計器會把一個分組的全部元組都傳到一臺機器上去作運算,但有不少累計器如 countsumminmax,能夠被並行計算。例如,要計算總和,能夠吧元組分紅幾個子集,計算各個子集的和,而後再把子集的和彙總來獲得最後的結果,不少累計器均可以這樣計算。

Cascalog 如今能夠容許你定義 「並行累計」,這樣能夠儘量的在 map 階段完成這些計算,而不用全拖到 reducer 裏去完成。map 端的累計器叫作 「combiners」。Cascalog 甚至能夠在運行多個並行累計的時候用到 combiners。下面的例子就是用了 combiners:

user=> (?<- (stdout) [?count ?sum]
          (integer ?n) (c/sum ?n :> ?sum) (c/count ?count))

Cascalog 會在可能的狀況下自動插入 combiners,你不須要作任何事就能利用這個優化。

若是你想把經過 defaggregateopdefbufferop 定義的常規累計器用於並行累計,Cascalog 就不能自動用 combiners,全部的累計都會發生在 reducer 任務中。好比,下面這個用自定義累計器的查詢就會把全部的累計放到 reducer 階段:

user=> (defaggregateop product
         ([] 1)
         ([total val] (* total val))
         ([total] [total]))
user=> (?<- (stdout) [?prod ?count]
          (integer ?n) (product ?n :> ?prod) (c/count ?count))

並行累計器能夠經過 defparallelagg 來定義。具體例子能夠去 cascalog.ops 裏去看。

在分組不多,好比計算全局數量的時候,你會看到這個特性在速度上會有很大的提高。

隱式等式約束

「隱式等式約束」 特性是指定等式約束的比較優雅的方法,這個特性仍是經過例子來說比較好。在 playground 裏定義了一個 "integer" 的數據集,裏面包含了個數字的集合,若是要的到全部平方後和自己相等的數字,能夠這樣搞:

user=> (?<- (stdout) [?n] (integer ?n) (* ?n ?n :> ?n))

Cascalog 檢測到咱們嘗試給 ?n 變量從新綁定值,會自動的過濾掉 * 謂詞的輸出和輸入不相等的元組。

還有一些其餘的狀況你能夠用這個特性。好比,要找到 "num-pair" 數據源裏先後相等的兩個數字對,能夠這樣:

user=> (?<- (stdout) [?n] (num-pair ?n ?n))

若是想拿到第二個數字是第一個數字兩倍的數字對:

user=> (?<- (stdout) [?n1 ?n2]
         (num-pair ?n1 ?n2) (* 2 ?n1 :> ?n2))

這沒什麼可多說的,很直觀。

排序

默認狀況下,累計器接收到的元組是任意順序的,Cascalog 如今有 :sort:reverse 謂詞來控制元組到達累計器的順序。舉個例子,咱們能夠這樣找出一我的 follow 的年齡最小的人:

user=> (defbufferop first-tuple [tuples] (take 1 tuples))
user=> (?<- (stdout) [?person ?youngest] (follows ?person ?p2)
          (age ?p2 ?age) (:sort ?age) (first-tuple ?p2 :> ?youngest))

要找到 follow 的年紀最大的人,只要再加上 :reverse 謂詞:

user=> (?<- (stdout) [?person ?youngest] (follows ?person ?p2)
          (age ?p2 ?age) (:sort ?age) (:reverse true)
          (first-tuple ?p2 :> ?youngest))

去重

若是你的查詢中沒有累計器,Cascalog 默認會在 reduce 這步去掉全部重複的元組,你能夠經過 :distinct 謂詞來控制這個行爲。比較下面兩個查詢:

user=> (?<- (stdout) [?a] (age _ ?a))
user=> (?<- (stdout) [?a] (age _ ?a) (:distinct false))

第二個查詢的輸出中會有重複。這個功能的用例是用一個子查詢來對輸入作一些預處理的時候。

相關文章
相關標籤/搜索