[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-poor-partitioning-turns-spark-into-tax-zh":3,"article-related-poor-partitioning-turns-spark-into-tax-zh":30,"series-tools-68dc7491-96f5-4b4b-b625-b82220f215f3":75},{"id":4,"slug":5,"title":6,"content":7,"summary":8,"source":9,"source_url":10,"author":11,"image_url":12,"cover_image":12,"category":13,"language":14,"translated_content":11,"related_article_id":15,"keywords":16,"key_takeaways":22,"views":26,"created_at":27,"published_at":28,"topic_cluster_id":29},"68dc7491-96f5-4b4b-b625-b82220f215f3","poor-partitioning-turns-spark-into-tax-zh","分區選錯讓 Spark 變稅","\u003Cp data-speakable=\"summary\">分區選錯會讓分散式工作慢、貴、又難維護，我把它拆成可直接檢查的做法。\u003C\u002Fp>\u003Cp>我跑 Spark 跟數倉 pipeline 跑久了，最常遇到的不是模型不準，也不是 SQL 寫爛，而是系統看起來很忙，實際上忙得很冤。UI 顯示 executor 都在動，job 也終究會跑完，dashboard 甚至還能裝得像沒事。但成本單子很誠實，SLA 也很誠實，最後就是每個「看起來很簡單」的查詢，都變成一場小型分散式內耗。\u003C\u002Fp>\u003Cp>我後來越看越覺得，問題常常不是 Spark 本身，而是 partitioning。不是那種架構圖上拿來交差的名詞，而是很土、很實際、很決定命運的東西：資料怎麼落盤、查詢掃多少、task 怎麼分、哪個 executor 先死。很多團隊會先罵引擎、罵 storage、罵網路，結果真正的元兇只是資料切法把整個系統帶歪了。\u003C\u002Fp>\u003Cp>這次我拆的是 Seshendranath Balla 在 HackerNoon 的文章 \u003Ca href=\"https:\u002F\u002Fhackernoon.com\u002Fthe-hidden-cost-of-poor-data-partitioning-in-distributed-systems\">The Hidden Cost of Poor Data Partitioning in Distributed Systems\u003C\u002Fa>。我會注意到它，不是因為它講得多玄，而是它很務實地在講：分區不是附屬設定，是你每次跑 job 都在付的隱形稅。\u003C\u002Fp>\u003Ch2>分區不是資料表註解，是工作量控制器\u003C\u002Fh2>\u003Cblockquote>\u003Cp>“Poor partitioning can lead to significant performance degradation, increased resource consumption, and higher operational costs.”\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1779593784342-4gsy.png\" alt=\"分區選錯讓 Spark 變稅\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003C\u002Fblockquote>\u003Cp>翻譯一下就是：分區決定每次查詢要做多少工，也決定這些工分得公不公平。切得爛，engine 就得掃太多資料、shuffle 太多資料，或者卡在某個超大 partition 上乾等，其他 executor 看起來很忙，其實只是陪跑。\u003C\u002Fp>\u003Cp>我以前踩過一個很典型的坑。某條 Spark pipeline 在紙面上看起來很乾淨，我們用了「業務上很合理」的欄位當 partition key。這種話通常就是麻煩的開頭。結果資料切出來一邊超大、一邊超小，daily job 表現像抽籤。有時快得像沒事，有時慢到像在懲罰整個團隊。儲存格式沒變，資料量也沒暴增，問題就是 layout 錯了。\u003C\u002Fp>\u003Cp>這篇文章真正有用的地方，在於它把 partitioning 拉回控制面來看。它影響 scan pruning、parallelism、shuffle volume、task skew，還有 storage efficiency。你如果把它當成一次性的 schema 決策，後面每次跑 pipeline 都是在替當初那個決定繳利息。\u003C\u002Fp>\u003Cp>實操上我會這樣做：先看最常見的 filter、join、access path 是\u003Ca href=\"\u002Fnews\u002Fwhy-claude-code-and-qoder-beat-chatty-ai-coding-tools-zh\">什麼\u003C\u002Fa>，再決定 partition key。使用者如果總是用 date 和 tenant 查，那就比 ER 圖上哪個欄位好看重要得多。要是你講不出這個 key 到底幫了什麼 workload，那八成不是好 key。\u003C\u002Fp>\u003Cul>\u003Cli>先優化讀取模式，不要先追求命名漂亮。\u003C\u002Fli>\u003Cli>只要有單一值可能吃掉大量資料，就先懷疑 skew。\u003C\u002Fli>\u003Cli>查詢模式會變，partition 也要跟著重看。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>熱分區不是例外，是瓶頸換了個名字\u003C\u002Fh2>\u003Cp>文章有提到 data skew，這才是很多人低估的地方。某個 partition 吃掉太多流量、太多資料、或太多相同 key 的 records，其他 partition 就算正常，整個 job 還是會被那一包拖死。\u003Ca href=\"\u002Ftag\u002F分散式系統\">分散式系統\u003C\u002Fa>很殘酷，平均值不重要，最慢的那個 task 才決定你什麼時候下班。\u003C\u002Fp>\u003Cp>所以一個 oversized partition 不只是慢而已，它會直接拉長 runtime、增加 memory pressure、提高 retry 機率，最後讓整個 pipeline 看起來像壞掉，但其實只是被一個熱點卡住。\u003C\u002Fp>\u003Cp>我也看過時間分區把人騙得很慘。大家都愛按天切，直到某一天剛好是黑五、月底結帳、產品上線，某個 partition 突然變成其他天的 20 倍大。這時候你原本自以為平衡的設計，就會變成一個很貴的笑話。\u003C\u002Fp>\u003Cp>白話講，partitioning 不能只靠直覺。你得先看 cardinality、頻率分布、以及資料隨時間的形狀。不然系統會很有禮貌地把不均勻藏起來，直到 production 才讓你一次看清楚。\u003C\u002Fp>\u003Cp>實操上我會先抽樣 key distribution，至少看 top values、最大最小 partition size、以及 ratio。只要少數 key 吃掉大部分 rows，我就會開始想 composite partitioning、salting、bucketing，或乾脆換另一種 access strategy。\u003C\u002Fp>\u003Cul>\u003Cli>不要只看 distinct count，要看頻率分布。\u003C\u002Fli>\u003Cli>用接近 production 的資料測，不要只拿乾淨樣本。\u003C\u002Fli>\u003Cli>假設某個特殊日或特殊 tenant 早晚會打爆平衡。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>小分區看起來整齊，其實是在逼 scheduler 加班\u003C\u002Fh2>\u003Cp>分區不是只有太大會出事，太小也一樣煩。這是同一個問題的另一面，而且很常被忽略。scheduler 有成本，metadata layer 有成本，file \u003Ca href=\"\u002Fnews\u002Fwhy-opentelemetry-won-observability-war-zh\">open\u003C\u002Fa> 也有成本。你如果切出一堆超小 partition，系統就會把時間花在管理工作，不是在做工作。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1779593786521-a5zd.png\" alt=\"分區選錯讓 Spark 變稅\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>這種情況最討厭，因為團隊很容易以為 engine 很慢，實際上是自己把 overhead 做爆了。我看過 job 花超久在 launch tasks、讀 tiny files、跟 metadata 纏鬥。單一 task 都不重，所以更難抓。cluster 看起來很忙，但忙的是行政雜務，不是計算。\u003C\u002Fp>\u003Cp>HackerNoon 那篇提到 operational cost，我覺得這點很準。poor partitioning 不一定會立刻炸出 outage，它更常見的是慢慢漏血。每個 job 慢一點、每次 query 多吃一點、每次 compaction 久一點，幾百次之後，雲端帳單就會替你把問題寫出來。\u003C\u002Fp>\u003Cp>實操上我不會迷信「分越細越平行」這種說法。partition 數量要跟資料大小和 workload 形狀對齊。Spark 裡面 partition 太多跟太少都很煩；lakehouse table 也是，太多小檔案和太多小 partition，plan 跟 compaction 都會痛苦得要命。\u003C\u002Fp>\u003Cp>我自己調 job 時，會盯著一個很土但很實用的平衡點：partition 要夠大，才能壓掉管理成本；又不能大到把 cluster 餵不飽。這件事沒有漂亮答案，只有量測。\u003C\u002Fp>\u003Ch2>Partition pruning 只有在你切對地方才有用\u003C\u002Fh2>\u003Cp>好的 partitioning 有一個很實際的好處：query engine 可以跳過不需要的資料。壞消息是，這只有在查詢 filter 跟 partition layout 對得上的時候才成立。兩邊不對齊，engine 還是得多掃很多資料，partition 再多也只是多一層儀式感。\u003C\u002Fp>\u003Cp>很多團隊會自己騙自己：table 有 partition，所以一定有優化。不是。partition key 選錯的 table，只是多了管理成本的 table。如果查詢一直是 customer_id，但你卻按 ingestion date partition，pipeline 也許比較好寫，但真正的查詢不會因此變便宜。\u003C\u002Fp>\u003Cp>我以前在 analytics 系統就被這個坑過。ETL 團隊愛那個 partition key，因為好寫、好落地；分析團隊則很不爽，因為每次查詢都還是掃一大堆不必要的資料。這種 hidden tax 最煩的地方在於，系統沒有壞，只是每天都差一點，差久了就是錢。\u003C\u002Fp>\u003Cp>實操上我會把 top queries 跟 partition layout 一一對起來。常見 filters 如果重複出現，就應該反映在 physical design 上。若有兩種以上主流 access pattern，就別硬塞進單一 partition key，該考慮不同表設計或不同物理策略就要考慮。\u003C\u002Fp>\u003Cul>\u003Cli>只有真實 filter 對得上，pruning 才會有感。\u003C\u002Fli>\u003Cli>把 ingest 方便跟 query 效率分開看。\u003C\u002Fli>\u003Cli>業務問題變了，partition 也要重審。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Cardinality 不是數學題，是踩雷清單\u003C\u002Fh2>\u003Cp>文章的 tag 裡有 cardinality-trap，我覺得這名字很準。cardinality 很容易讓人以為只是挑一個 distinct value 數量漂亮的欄位。高 cardinality 會帶來太多 partition、太多 metadata、太多碎片；低 cardinality 又會讓 partition 巨大、skew 嚴重、pruning 很差。兩邊都不是什麼好下場。\u003C\u002Fp>\u003Cp>白話講，partitioning 不是在找一個看起來數字漂亮的欄位，而是在找一個在你的 workload 下穩定、可用、可預期的欄位。樣本裡看起來很平均的 key，上 production 可能瞬間歪掉；一個 pruning 潛力很好的 key，也可能因為寫入太頻繁而造成很糟的 write amplification。\u003C\u002Fp>\u003Cp>我看過不少團隊在那邊追求「完美 cardinality」，結果反而忽略更大的問題：這個 key 有沒有穩定性？會不會隨時間變形？會不會讓流量集中在少數值？只要這三件事答案不漂亮，再好看的 spreadsheet 都救不了你。\u003C\u002Fp>\u003Cp>實操上我會把候選 key 拿去看時間維度，不只看 row 數。按 hour、day、tenant、region 去看它怎麼變，再對照 workload。很多時候最好的答案不是單一 partition key，而是 composite、bucketing，甚至是不 partition。對，很多表根本不該硬切，這句我講得很認真。\u003C\u002Fp>\u003Cp>我寧可跟團隊說「這張表不要 partition」，也不要看他們做出一套脆到不行的切法，然後接下來半年都在維護它。\u003C\u002Fp>\u003Ch2>真正的成本不是慢，是慢到沒人敢承認\u003C\u002Fh2>\u003Cp>這篇文章最有價值的一點，是它把 poor partitioning 從 performance 問題拉成 operational cost 問題。那包含 compute waste、storage inefficiency、job time 拉長、retry 變多，還有工程師花時間追查本來不該存在的 slowdown。\u003C\u002Fp>\u003Cp>最麻煩的是，這通常不是那種會被記進 incident 的大爆炸，而是慢性出血。每個 job 只慢一點，每個 query 多吃一點資源，每次 compaction 多花一點時間。等到某一季財務問雲端帳單為什麼跳了，大家才發現原來是幾百個小問題疊成一個大洞。\u003C\u002Fp>\u003Cp>我也解釋過這種帳單，真的很難看。你沒辦法指著一個 spectacular failure 說就是它。你只能指著一個設計決策，說它讓所有事情都稍微變差。這就是為什麼 partitioning 應該被當成架構層級的事，不是 implementation 細節。\u003C\u002Fp>\u003Cp>實操上我會把 partition health 放進例行 data review。看 file size、partition count、skew、scan volume、job runtime。最好有人固定盯著 layout 有沒有跟 workload 脫節。只要脫節，就先改 layout，不要先加更多 compute 然後假裝問題解掉了。\u003C\u002Fp>\u003Cul>\u003Cli>看 job 成本，不要只看 job 成功。\u003C\u002Fli>\u003Cli>追蹤 partition size 是否隨時間漂移。\u003C\u002Fli>\u003Cli>如果根因是 layout，優先重設計，不要只會加機器。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>可抄的模板\u003C\u002Fh2>\u003Cp>下面這份是我會直接拿去做 design review 的版本。它的目的很簡單：把討論從「感覺上應該可以」拉回「這個 key 到底幫了什麼 workload」。你可以直接複製，改欄位名稱就能用。\u003C\u002Fp>\u003Cpre>\u003Ccode># Data partitioning review template\n\n## 1) Workload summary\n- Primary readers:\n- Top queries:\n- Top joins:\n- Write pattern:\n- Freshness requirement:\n\n## 2) Candidate partition key\n- Proposed key:\n- Why we chose it:\n- What queries it helps:\n- What writes it hurts:\n\n## 3) Distribution check\n- Distinct values:\n- Top 10 values by frequency:\n- Largest partition size:\n- Smallest partition size:\n- Skew ratio:\n- Hot key risk:\n\n## 4) Engine fit\n- Partition pruning benefit:\n- Shuffle reduction benefit:\n- File count impact:\n- Metadata overhead risk:\n- Compaction needs:\n\n## 5) Failure modes\n- What happens on peak days:\n- What happens with new tenants or regions:\n- What happens when the access pattern changes:\n- What happens if the key becomes too sparse:\n\n## 6) Decision\n- Keep as-is:\n- Change key:\n- Use composite partitioning:\n- Use bucketing\u002Fsalting:\n- Do not partition:\n\n## 7) Validation plan\n- Sample dataset used:\n- Query benchmark:\n- Runtime baseline:\n- Cost baseline:\n- Recheck date:\n\n## 8) Review checklist\n- [ ] Partition key matches real filters\n- [ ] No obvious hot partitions\n- [ ] Partition count is manageable\n- [ ] File sizes are healthy\n- [ ] Query pruning is measurable\n- [ ] Cost impact is documented\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>我會把這份模板塞進設計審查、table 建立前，還有上 production 後第一週再跑一次。partitioning 不是「設定完就不用管」的東西，它是會跟著使用方式一起變的。\u003C\u002Fp>\u003Cp>原始來源是 \u003Ca href=\"https:\u002F\u002Fhackernoon.com\u002Fthe-hidden-cost-of-poor-data-partitioning-in-distributed-systems\">HackerNoon 文章\u003C\u002Fa>，作者是 Seshendranath Balla。上面這篇是我根據原文做的拆解與實務化\u003Ca href=\"\u002Fnews\u002Fgoogle-cloud-latest-updates-ai-storage-gke-zh\">整理\u003C\u002Fa>，模板則是我另外整理出來的可直接套用版本，不是原文逐字搬運。\u003C\u002Fp>\u003Cp>我在看這類議題時也會順手對照 \u003Ca href=\"https:\u002F\u002Fspark.apache.org\u002F\">Apache Spark\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fdelta.io\u002F\">Delta Lake\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fwww.databricks.com\u002Fglossary\u002Fdata-skew\">data skew\u003C\u002Fa>，還有 \u003Ca href=\"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-partitioning.html\">PostgreSQL partitioning docs\u003C\u002Fa>。這些連結不是拿來裝飾，是拿來把話講實在一點。\u003C\u002Fp>","我拆解為什麼分區設錯會默默燒掉 Spark 成本、時間與叢集健康，最後給你可直接套用的審查模板。","hackernoon.com","https:\u002F\u002Fhackernoon.com\u002Fthe-hidden-cost-of-poor-data-partitioning-in-distributed-systems",null,"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1779593784342-4gsy.png","tools","zh","63ff7db4-5338-4e1b-9202-5880d4da9e3c",[17,18,19,20,21],"Spark","partitioning","data skew","partition pruning","distributed systems",[23,24,25],"分區不是細節，它直接控制 scan、shuffle、skew 與成本。","熱分區和小分區都會拖慢 job，問題常常是 layout 不是引擎。","先用工作負載與分布檢查決定 partition key，再用模板做審查。",3,"2026-05-24T03:35:57.152031+00:00","2026-05-24T03:35:57.066+00:00","c3c88dd2-a940-438a-b359-0e5a24562273",{"tags":31,"relatedLang":34,"relatedPosts":38},[32],{"name":21,"slug":33},"distributed-systems",{"id":15,"slug":35,"title":36,"language":37},"poor-partitioning-turns-spark-into-tax-en","Poor Partitioning Turns Spark Into a Tax","en",[39,45,51,57,63,69],{"id":40,"slug":41,"title":42,"cover_image":43,"image_url":43,"created_at":44,"category":13},"419deb6d-ea65-4fa7-9dd1-73763f373b53","bailian-token-plan-agent-credits-guide-zh","百炼Token Plan把Agent接入变简单","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783929835818-cyp6.png","2026-07-13T08:03:24.024727+00:00",{"id":46,"slug":47,"title":48,"cover_image":49,"image_url":49,"created_at":50,"category":13},"5c5c6733-6f41-49ca-b61e-c0a53399c327","one-api-gateway-turns-six-ai-apis-into-one-zh","一個閘道把六個 AI API 收成一套","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783883027640-gz6i.png","2026-07-12T19:03:22.171684+00:00",{"id":52,"slug":53,"title":54,"cover_image":55,"image_url":55,"created_at":56,"category":13},"953466bc-6d94-4ffe-944b-ac7728d09184","fde-playbook-fixes-broken-agent-projects-zh","FDE 讓烂尾 Agent 回正軌","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783881221882-yw1n.png","2026-07-12T18:33:16.193979+00:00",{"id":58,"slug":59,"title":60,"cover_image":61,"image_url":61,"created_at":62,"category":13},"bd3b5d5c-02d9-49c4-8ca4-dcb6df373374","ai-zaobao-template-daily-to-reusable-report-zh","AI 早报拆成可复用周报","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783879420413-rlwb.png","2026-07-12T18:03:11.617929+00:00",{"id":64,"slug":65,"title":66,"cover_image":67,"image_url":67,"created_at":68,"category":13},"33302498-49ec-4a00-8e2c-61b6f9fc3ece","claude-reflect-turns-usage-into-retention-zh","Claude Reflect 把使用變留存","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783793005956-n1ea.png","2026-07-11T18:03:01.486301+00:00",{"id":70,"slug":71,"title":72,"cover_image":73,"image_url":73,"created_at":74,"category":13},"5f08bf54-0ddb-4884-b541-75e33ad21b30","midjourney-turns-prompt-ideas-into-art-zh","Midjourney 把提示詞變成可重用流程","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783694003831-eilt.png","2026-07-10T14:32:55.765266+00:00",[76,81,86,91,96,101,106,111,116,121],{"id":77,"slug":78,"title":79,"created_at":80},"855cd52f-6fab-46cc-a7c1-42195e8a0de4","surepath-real-time-mcp-policy-controls-zh","SurePath 推出即時 MCP 政策控管","2026-03-26T07:57:40.77233+00:00",{"id":82,"slug":83,"title":84,"created_at":85},"9b19ab54-edef-4dbd-9ce4-a51e4bae4ebb","mcp-in-2026-the-ai-tool-layer-teams-use-zh","2026 年 MCP：團隊真的在用的 AI 工具層","2026-03-26T08:01:46.589694+00:00",{"id":87,"slug":88,"title":89,"created_at":90},"af9c46c3-7a28-410b-9f04-32b3de30a68c","prompting-in-2026-what-actually-works-zh","2026 提示工程，真正有用的是什麼","2026-03-26T08:08:12.453028+00:00",{"id":92,"slug":93,"title":94,"created_at":95},"05553086-6ed0-4758-81fd-6cab24b575e0","garry-tan-open-sources-claude-code-toolkit-zh","Garry Tan 開源 Claude Code 工具包","2026-03-26T08:26:20.068737+00:00",{"id":97,"slug":98,"title":99,"created_at":100},"042a73a2-18a2-433d-9e8f-9802b9559aac","github-ai-projects-to-watch-in-2026-zh","2026 必看 20 個 GitHub AI 專案","2026-03-26T08:28:09.619964+00:00",{"id":102,"slug":103,"title":104,"created_at":105},"a5f94120-ac0d-4483-9a8b-63590071ac6a","claude-code-vs-cursor-2026-zh","Claude Code 與 Cursor 深度對比：202…","2026-03-26T13:27:14.279193+00:00",{"id":107,"slug":108,"title":109,"created_at":110},"0975afa1-e0c7-4130-a20d-d890eaed995e","practical-github-guide-learning-ml-2026-zh","2026 機器學習入門 GitHub 實用指南","2026-03-27T01:16:49.712576+00:00",{"id":112,"slug":113,"title":114,"created_at":115},"bfdb467a-290f-4a80-b3a9-6f081afb6dff","aiml-2026-student-ai-ml-lab-repo-review-zh","AIML-2026：像課綱的學生實驗 Repo","2026-03-27T01:21:51.467798+00:00",{"id":117,"slug":118,"title":119,"created_at":120},"80cabc3e-09fc-4ff5-8f07-b8d68f5ae545","ai-trending-github-repos-and-research-feeds-zh","AI Trending：把 AI 資源收成一張表","2026-03-27T01:31:35.262183+00:00",{"id":122,"slug":123,"title":124,"created_at":125},"3ce6e6e2-bac5-463e-9f8d-45caabcc61f7","awesome-ai-for-science-research-tools-map-zh","AI 科研工具清單，開始像地圖了","2026-03-27T01:46:50.521945+00:00"]