
儀表板先搭好了,底層的數據怎麼管理?
樸素的想法是把各個來源的數據接進來,直接秀在儀表板上。但這回答不了很多問題。
例如,人人都說脆的文章一週就死,是真的嗎?我到現在還常收到前幾個月〈眾神之島〉那則的互動更新,那又是怎麼回事?
又例如,哪些平台會有自然擴散,哪些平台是要人推才動?
又或者想知道更精確的:脆發文的流量到底集中在前三天、前七天,還是其他?
這些都需要把數字快照接到自己家裡,而不是只依靠平台事後給你的累計資訊。
更何況,每次都用平台的累計資訊做全局更新,一個不小心就會蓋掉所有資料。我早期把資料放在會跟 iCloud 同步的電腦上,就遇過同步過程出錯、前面資料全部斷掉的慘劇。
一開始我想到的是資料快照,把每週儀表板看的資料留下來,未來可比對就好。
既不用每週更新一次全歷史資料庫,也可以有每週的週資訊比對。
後來陸續踩到幾次坑,都是因為不同資料來源的格式定義或更新邏輯不同造成的,搞得我的儀表板 Agent 一天到晚跟我道歉:我踩到這個坑、那個坑。
前面提到的儀表板搭好後的一週建立,七張表,從來源到目標。
七張是:source(來源)、metric(指標)、entity(實體,一則貼文、一篇文章、一個 App 都算)、observation(觀測)、annotation(人工標註)、run(抓取紀錄)、target(目標)。
資料庫檔案刻意不放在專案資料夾,因為我把專案資料夾在電腦桌面、電腦桌面又設計成跟 iCloud 自動同步。SQLite 的暫存檔被雲端同步會壞。前面那個慘劇發生一次就夠了。
一、一個數字可以有很多版本,舊的不刪。 observation 不是「一個指標一天一列」,是每次我去看就記一列。我設定成每週手動更新一次,但有時候會過度緊張,一天看個五次,那同一天的同一個數字就有五列,值都不一樣。
五列不是毛病,是這張表的工作。因為平台給你的永遠是「現在」:你今天去查八月九日,拿到的是八月九日現在長成什麼樣,不是八月九日當天長什麼樣。
二、不是 0,是沒抓到。 run 是抓取紀錄,這張表很重要,因為需要分清楚,我在儀表板畫面上看到的 0,到底是真的沒人下載,還是那天腳本掛了。
三、增量跟累計要分開看。 目標的達成狀況看累計,但每週效果看增量。目標的差距很重要,但只看差距太心酸,所以我主要看的是每週的增量趨勢,有沒有逐漸增加,或是維持在一樣的水準。
四、把上游的脾氣寫進資料。 所謂的脾氣,包含了更新時間、時區、資料快照、保留時間等。
| 欄位 | 它在記什麼 | 現況 |
|---|---|---|
day_tz |
這個來源的一天從幾點開始 | 三種時區並存:洛杉磯 6 個、台北 3 個、UTC 3 個 |
revises |
它會不會事後改已公布的數字 | 十二個裡有 8 個會 |
retention |
它幫你留多久 | 從八天到十六個月都有 |
「同一天」在這個資料庫裡有三種意思。 這不是比喻,是三個時區。
而 retention 那一欄,是我長期觀測才搞懂的。
App Store Connect 的分析報表每次只給最近九到十一天,過了就沒有了。不是難查,是不存在。脆的帳號洞察大約留三十天。Google Search Console 十六個月。
這一個是十二個來源裡餘裕最薄的。我每七天更新一次,中間只剩幾天的緩衝。到目前為止沒有掉過東西,但它是唯一一個會掉的。

那些數字的歷史,不存在任何地方,除非我自己留。
而且這一欄本身就寫錯過。我在來源表裡填的是「三天滾動窗」,今天去數每次抓取實際寫進幾天,才發現是九到十一天。那句話從建庫起錯了兩個月,沒有人發現。
它還長了腳。我拿那個數字去跟人解釋自己的設計,寫進了技能檔,也差一點寫進這篇。更糟的是我順手補了一個因果:既然窗只有三天,那八月初缺的那五天一定是我漏抓造成的。查下去才知道,那五天從第一次回填就不在,跟我的更新頻率無關。
把上游的脾氣寫成欄位,不代表那個欄位是對的。 觀測值那邊有唯一索引擋著,描述來源的這幾欄沒有任何東西在驗,錯了也不會有人喊。抓到它的不是誰更努力,是後來加了一段會自己把證據印出來的檢查。
entity_attr,建庫同一天就加了。 App 的線上版本號是「1.3.1」,而 observation 的值欄位是數字,放不進字串。原本的設計假設「會隨時間變的東西都是數字」,第一次填真實資料就破功。
為什麼不丟進 annotation:那張表留給人工判斷,版本號是機器抓來的事實。混在一起,之後就分不清哪些數字是我決定的、哪些是平台給的。
event,八月二十日。 observation 只存得下「數字是多少」,存不下「我在哪一天改了什麼」。沒有這張表,四週後看到排名動了,我分不清是自己改標題的效果、是 Google 演算法更新,還是季節。
它最重要的欄位不是摘要,是 expectation:改動的當下就要把「我覺得會發生什麼」寫下來。事後才補一句「我早就覺得會這樣」是自我欺騙,寫在前面才驗得出來對不對。
app_review,九月二十八日。 評分數從 27 跳到 28,我對不出來是誰、寫了什麼。而且一則評論的內容不會變、回覆狀態會變,用「只新增不修改」的 observation 去表達「這一欄要原地改」很彆扭。在寫這篇時,四個APP 都有人評分了,我好欣慰。
會動的,整段重抓覆蓋。 脆的每日觀看重抓近十四天,因為它事後大幅上修。臉書重抓最近兩週,因為當週剛結束就抓會低估,九月二十八日那週十月四日抓到 4,721,十月十一日重抓是 5,194。ASC 的分析報表每次抓全部可得範圍,因為它只給九到十一天,而我一週抓一次,餘裕只剩幾天。
不會動的,只追加不回頭。 每日下載定版就不動。
凍結的,寫一次就不碰。
正式一點的講法,這叫依資料成熟度分層的增量載入。重抓那段叫回溯視窗,凍結那段就像是會計的關帳。
還有一條橫切所有來源的規則:值沒變就不寫。這看起來是效能考量,實際上是語意的,因為修訂紀錄要回答的是「這個數字改過幾次」,沒變就不算一次。
有了這些,才答得出來。
我的脆滿七天的貼文有103篇,累計觀看除以前七天觀看,中位數 1.020 倍。 PR75是 1.041,超過 1.10 倍的只有七篇。
一百零三篇裡有九十八篇,也就是 95%,前七天就拿走九成以上的流量。所以量體確實在七天內決定。但那不代表它死了。
〈眾神之島〉那則七天內衝到 33,387,到現在一個多月還在增加。
量體在七天內定生死,但少數文章的尾巴還持續增長。 這是有自己資料庫後可以大聲說的。
同場加映,我的部落格流量就完全不同:二○二○年以前的四十九篇文章,在最近兩個月裡,有四十九篇全部都在長。 不是有些還在長,是沒有一篇停下來。
七天就定案,和六年還在長,都不是都市傳說,是開始做資料快照之後我才敢確定的事。
至於流量集中在前三天還是前七天,這個資料庫現在答不出來,因為我是每週抓一次。想看前三天或前七天的流量佔比,自然就要留更多素材。抓取頻率決定了你日後問得出什麼問題。
踩了這麼多次之後我覺得有點煩,現在正規劃另一個資料架構師 Agent 幫我重新檢視整個架構:要有幾張表、每張表的角色、欄位怎麼設計、文章的唯一 ID、素材打標、標籤類別分群。
已經找出來要補的有三個。
三種時區還沒統一成一個報表日,每個查詢各自換算。比率類的指標只存了結果值,沒存分子和分母,所以誰都可以把轉換率加總。還有,我沒有保存上游的原始回應,解析邏輯一改就重算不回去。
還有一個更根本的:「只新增不修改」目前只是慣例,不是約束。SQLite 沒有權限系統,要靠觸發器才擋得住。講得出一條規則,跟證明這條規則沒有被違反,是兩回事。
這些事情在上班的時候叫同事做,要排好幾個月的工時。在 Vibe Coding 時代,是幾天的工作量。
一個人開發,缺的不只是團隊,還有職能。Day 19 那篇說過,沒有測試主管、沒有同儕審查、沒有弱點掃描。這一篇是同一件事的另一面:沒有資料架構師,你就得自己兼一個。
而這個職位做得好不好,檢驗標準不是你建了幾張表。
是半年後的你,能不能回答「這個數字當時是多少」。
這個系列同步寫在我的部落格:yojuhsu.com/blog
前一篇:Day 28,跟AI合作搭個自己的儀表板吧
下一篇:Day 30