跳到主要內容

發表文章

目前顯示的是 4月, 2020的文章

Group By Then Limit And Offset in Elastic Search

前言 傳統的 Relational database 可以使用 SQL 語言以 GROUP BY 的方式將資料分群然後做計算 SELECT country, COUNT(*) AS Count FROM `bi_dataset.usr` GROUP BY country DESC ORDER BY 1 若想要在 Elastic Search  上實現相同的結果的話, 可以使用 Terms Aggregation { "size": 0, "aggs" : { "country" : { "terms" : { "field" : "country" } } } } 但實務上基於效能的考量, 通常不會希望回傳全部的結果, 而是以分頁的方式傳回部分資料 SQL的做法是在語法裡加入 LIMIT 以及 OFFSET 來控制結果 SELECT country, COUNT(*) AS count FROM `dataset.usr` GROUP BY country ORDER BY 1 DESC LIMIT 20 /* 限制資料量 */ OFFSET 100 /* 取得某特定區段的資料, 即 skip 前100筆 */ 而在 Elastic Search 裡, 可以藉由 bucket sort aggregation 來實現, 分頁的部分可以透過 size, 以及from 來控制 { "size": 0, "aggs": { "country": { "aggs": { "sort_country": { "bucket_sort": { "sort": [ { "_count": { ...

[解決方法] Cloud Scheduler Permission Denied

前言 Cloud Scheduler 有個進階的功能, 可以設定當排程被觸發的時候, 必須先取得指定的 IAM 身份, 才能去打指定的 Cloud Run 或是 Cloud Function 上的服務 整體的流程大致如下圖 Cloud Scheduler 發出 POST 請求取得 Token Cloud IAM 回傳 Token Cloud Scheduler 帶著 Token 打去打 Cloud Run 上的服務 最後 Cloud Run 根據 Token 是否擁有 Cloud Run Invoker 的權限來決定是否要執行這個請求 %3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%222%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3Baspect%3Dfixed%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22206%22%20y%3D%22197.5%22%20width%3D%2219%22%20height%3D%2219%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E 若部署完後在 Log 頁面出現 PERMISSION_DENIED 的話該如何處理??? {   "jobName": "projects/cloud-833005/locations/us-central1/jobs/sync_usr",   "targetType": "HTTP",   "url": "https://ukrjq-uc.a.run.app/api/job/load",   ...

Golang 的物件導向: Golang Object Oriented Programming

前言 Go 不是一個典型的物件導向程式語言 (Object Oriented Programming, OOP), 所謂的 OOP 三大精神 "封裝", "繼承",  與 "多形" 在Go語言中其實並沒有被完整的實現,  取而代之的是以結構來代替類別, 以組合來代替繼承, 以及介面實作來達到多形 結構與類別的差異 Go 允許將相關的資料組織在同一個結構 (struct) 裡, 甚至還可以為其定義方法, 這個作法跟其他 OOP  語言 (如 C# ) 將資料封裝在類別裡的概念很像 type User struct { Hight int Weight int Name string } func (p * User) GetBMI() int { return p.Weight / p. Hight * p. Hight } 差別是結構沒有建構子可以用, 所以通常是要自己寫一個 New_ _ _( ) 的函式來實現相關的初始化的動作 func NewUser(h, w int, name string) *User{ p:= &Page{Hight: h, Weight: w} if name == "" { p.Name = "Unknown" // set default value } return p } 組合 Composition Go 沒有繼承, 若想要重用程式碼必須以 has-a 的方式將其他結構的資料嵌入 (Type Embedding) type BusinessUser struct { User // <------------------ type embedding CreditCarNumber string } func NewBusinessUser(h, w int, name, cred string) *User{ if cred == "" { return nil } p:= &Bus...

Calculate DAU, WAU, and MAU by BigQuery

前言 近年來, 商業智慧( Business Intelligence, BI )的運用已漸漸地受到企業的重視, 決策者可以藉由 BI 提供的資料來做業務的分析與預測 在做業務分析的時候, 通常會以每日活躍使用者數( Daily Active User, DAU ), 每週活躍使用者數( Weekly Active User, WAU ), 以及每月活躍使用者數( Monthly Active User, MAU )的多寡, 來暸解目前產品的營運狀況 要計算出這些資訊其實並不難, 首先以 Group By "日期"的方式算就可以先算出 DAU WITH DAUtbl AS ( SELECT _PARTITIONDATE AS date, COUNT(*) as dau FROM my_dataset.usr WHERE _PARTITIONDATE BETWEEN DATE_SUB(DATE('2020-03-16T13:15:30Z'), INTERVAL 7 - 1 DAY) AND DATE('2020-03-21T13:15:30Z') GROUP BY _PARTITIONDATE ) 有了每日人數( DAU )之後, 接下來就是來算 WAU 計算 WAU 時, 須將當日以及前六天的 Active User 數量都加總起來 而想要取得七天內的資料, 可以先透過 CROSS JOIN 的方式將每一日的資料都複製成七份 SELECT * FROM DAUtbl, UNNEST(GENERATE_ARRAY(0, 7 - 1 )) i 每個副本都會有個索引值 i (如下) 有了七份的副本之後, 再將資料移動到合適的群組(日期)做加總, 最後就可以獲得每一日 WAU 的數目 SELECT DATE_ADD(date, INTERVAL i DAY) date_grp <--- 移動資料 , SUM(DISTINCT IF( i < 7 ,dau, null)) wau FROM DAUtbl, UNNEST(GENERATE_ARRAY(0, 7 - 1 )) i GROUP BY 1 ORDER BY...

Entity Framework Inner Join and Left Join

Inner Join  就是合併兩張表中有交集的資料 Left Join  也是在合併兩張表,但不同於Inner Join的是, 若在右方表格找不到對應於左方表格的資料時, 預設會給null代替 在Entity Framework中如何實現Inner Join from c in Students join o in Addresses on c.StudentId equals o.StudentId select new { c.StudentName , o.AddressName} 對應的T-SQL SELECT [t1].[StudentName], [t0].[AddressName] FROM [Students] AS [t0] INNER JOIN [Addresses] AS [t1] ON [t1].[StudentId] = [t0].[StudentId] 在Entity Framework中如何實現Left Join from c in Categories join o in Products on c.CategoryID equals o.CategoryID  as ps from p in ps.DefaultIfEmpty() select new { c.CategoryName ,p.ProductID, p.ProductName } ps.DefaultIfEmpty 表示join後的結果會存在ps, 若在Products中找不到對應資料就會回傳null 對應的T-SQL SELECT [t0].[Categories], [t1].[Products] FROM [Categories] AS [t0] LEFT OUTER JOIN [Products] AS [t1] ON [t1]. CategoryID = [t0].[CategoryID]

Create a new instance of a struct from its type in go

前言 為了讓程式更有彈性, 在某些情況下會需要在 runtime 的時候建立 struct 的實例, 透過使用 Go Lang 內建的 reflect 套件, 就可以輕鬆地動態產生實例並且賦值 以實作一個Copy的函式為例 func Copy(i interface{}) interface{}{ objType := reflect.TypeOf(i) objVal := reflect.ValueOf(i) newObjValPtr := reflect.New(objType) newObjValPtr.Elem().Set(objVal) return newObjValPtr.Elem().Interface() } 首先呼叫 reflect.TypeOf 取得某個型態的相關結構資訊 objType := reflect.TypeOf(i) Note 以Go Lang的設計原則來說, 每個變數都會有一組資訊用來記錄值以及型態的資訊 (value, type ) 接著呼叫 reflect.ValueOf 傳回一個 Value 的實例 (Value 是定義在 reflect 套件裡的結構, 提供了一些方法可以取得實際的值) objVal := reflect.ValueOf(i) 接下來傳遞型態資訊給 reflect.New 來產生一個空的 Value 實例 newObjValPtr := reflect.New(objType) 實際上 reflect.New 並不是直接回傳空的 Value 實例, 而是回傳一個實際值為指向空 Value 的指標的 Value 實例 若要對這個空 Value 賦值, 必須使用 .Elem 取得 newObjValPtr 的實際值指向的本體後, 才能以 .Set 賦值 newObjValPtr.Elem().Set(objVal) Note Value的值若是一個指標, 必須 透過 Elem() 方法才能取得目標值 最後再用 .Interface 以 Interface{}的形態輸出 newObjValPtr .Elem().Interface() 實驗1. fu...

Retention Cohorts Using BigQuery

前言 在擬定商業策略的時候 Cohorts Retention 一直是很常被用來參考的指標, 透過這個指標可以了解客戶對於產品的黏著度倒底有多高, 進而去調整產品規劃或是公司的營運方向 Cohorts Retention Rate 又稱回客率,  也就是當過了一段時間之後仍還繼續使用產品的客戶比率, 若以七天為一個週期來看的話, 就是每週的回客率 每週回客率 = 當週的舊客戶數/第0週的所有客戶數 舉例來說, 以下是一個週回客率的表格, 總共分析六週(Week 0 ~ Week 5), 而在Week 0 出現的客戶群即在左方日期區間內出現的客戶群, 而紅色箭頭的 25.7% 指的是出現在Week 0(Feb 3 - Feb 9) 的客戶仍然有出現在Week 1的(即當週的舊客戶)占所有出現在 Week 0 的客戶的比例 SQL 計算 Retention 如下圖所示, Retention 計算出來之後會呈現出一個左上三角形的圖表 而這整張表的計算其實並不複雜, 基本上只要知道第一列怎麼算, 剩下的也都不是問題, 只要如法炮製就好 接下來的演練將使用 Open Data 的資料 Step 1. 首先算出第0週的所有使用者 SELECT DISTINCT user_pseudo_id FROM `firebase-public-project.analytics_153293282.events_*` WHERE _TABLE_SUFFIX BETWEEN '20180731' AND '20180807' Step 2. 計算第一週(Week 1)還留存多少客戶 這個部分就是將第0週的客戶資料跟第1週的直接做JOIN, 就可得知在第一週時有哪些第0週的客戶回流了, 如下 WITH week_0 AS( SELECT DISTINCT user_pseudo_id FROM `firebase-public-project.analytics_153293282.events_*` WHERE _TABLE_SUFFIX BETWEEN '20180731' AND '20180807' ) SELECT ...