把P-alert和USGS速報做時間對齊時,我踩到的那個坑

这篇内容暂时只有 繁體中文 版本,以下是原文。

前陣子為了把社群通報的震度資料和 USGS 的 event 資料對起來,我在一台 4 核 8G 的 VPS 上跑了一支 Python 小管線。資料量不大:一天大概兩三百筆 event、社群端每分鐘幾十則訊息,跑一週也才幾萬筆。理論上這種規模不該出問題,但它就是出了。

問題現象是:同一筆地震,USGS 那邊的 origin time 和社群通報的時間常常差 5 到 20 秒,我原本直接拿兩邊時間戳做 join,結果配對率低到大概六成,而且配錯的比配對的還難抓。

我的做法是先把時間統一成 UTC 的 epoch 秒,再做一層「容忍窗」配對。程式大概長這樣:

from datetime import timedelta

def pair_events(usgs, reports, window_sec=30):
    usgs = sorted(usgs, key=lambda e: e["origin_epoch"])
    out = []
    for r in reports:
        t = r["report_epoch"]
        lo = t - window_sec
        hi = t + window_sec
        cand = [e for e in usgs if lo <= e["origin_epoch"] <= hi]
        if len(cand) == 1:
            out.append((r, cand[0]))
        elif len(cand) > 1:
            # 多筆候選就取時間最近的那筆,但要記錄下來
            best = min(cand, key=lambda e: abs(e["origin_epoch"] - t))
            out.append((r, best, "multi"))
    return out

為什麼是 30 秒?因為我實際看了一週的資料,社群端從感覺到發訊息的延遲中位數大概十幾秒,而 USGS 的 origin time 是發震時間,不是發佈時間。兩邊根本不是同一個物理量,硬對就是會錯。用容忍窗的代價是:當兩筆地震在 30 秒內先後發生,配對就會曖昧,所以我留了 multi 標記,人工抽查。

會失效的地方很具體:第一,規模小的地震 USGS 常常晚很久才出,甚至不出,這時候容忍窗再大也配不到;第二,跨日界線時如果我一開始用本地時區做字串比對,就會整批偏移,我一開始就是這樣踩的;第三,社群端如果有重複轉發,同一則訊息會被配到不同 event,我去重是用 (report_id, event_id) 當 key,但 report_id 本身不保證唯一,這點我到現在還不確定該怎麼解。

另外一個實際的坑是時區。我一開始想說「反正都轉 UTC 就好」,結果某一批資料的來源欄位其實是本地時間卻沒標時區,整批早了 8 小時,我對了半天才發現是來源端的問題,不是我的程式。

現在我的做法是:配對結果一律保留原始時間戳和配對理由,出問題時可以回頭查,而不是只留一個配好的 pair。

你們在對不同來源的地震時間時,容忍窗是固定值還是會隨規模或距離調整?我目前是固定 30 秒,但總覺得偏鄉或海域事件應該放寬,卻沒有好方法決定放多寬。

0
赞同度 100% · 0 条评论 · 2 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。