把 USGS 速报流拉进本地:一次 5 万条事件的去重踩坑
手上要做一个按区域筛速报的小面板,数据源用的是 USGS 的 GeoJSON feed。环境是 Python 3.11 + requests,本地 SQLite。现象很具体:连续跑了两天,库里的记录比实际事件多了大约 1.7 倍,同一次地震出现两三条,时间戳差几秒。
我一开始以为是 feed 本身重复,后来发现是四个 feed(hour、day、week、month)我全拉了,同一次事件在不同窗口里各出现一次,而且 updated 字段不一样。做法改成先落原始 JSON 再归一:
import sqlite3, json, requests
FEEDS = {
'hour': 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson',
'day': '.../all_day.geojson',
'week': '.../all_week.geojson',
}
def upsert(conn, feat):
p = feat['properties']
g = feat['geometry']['coordinates']
conn.execute('''INSERT INTO quake(id, mag, lon, lat, depth, time_ms, updated_ms, place)
VALUES(?,?,?,?,?,?,?,?)
ON CONFLICT(id) DO UPDATE SET
mag=excluded.mag, updated_ms=excluded.updated_ms
WHERE excluded.updated_ms > quake.updated_ms''',
(feat['id'], p['mag'], g[0], g[1], g[2], p['time'], p['updated'], p['place']))
关键是主键用 USGS 的事件 id,不用时间或坐标做联合键。updated 用毫秒整数比较,别用字符串,我最早按字符串比,...999 和 ...1000 的排序会错。
为什么这么设计:feed 是滚动窗口,不是增量接口,同一事件会被反复推送,且震级和位置会被修订。以 id 为主键、只在新 updated 更大时覆盖,等于把「修订」当成版本推进,代价是库里的记录会随修订次数变化,历史版本不留存。我接受这个代价,面板只需要最新值。
失效的地方:all_hour 在序列刚开始时可能为空或落后,单靠它补不到 2 小时前的事件,所以小时级窗口和日级窗口要并行跑,最后合并。另外 USGS 偶尔返回 mag: null,插入时我留了 NULL,但下游按震级过滤的查询要显式处理,不然会被静默排除。还有一次我拿 place 字段做区域筛选,结果地名写法不统一(km SW of 和 km SSW of),筛漏了,后来改成按经纬度框选。
现在面板能跑,但有个问题一直没解决:小时 feed 的更新时间不固定,我用 5 分钟轮询,偶尔会漏掉只在窗口边缘出现一次的事件。你们是拉 feed 还是直接订阅某个增量接口?轮询间隔怎么定的?
0 条评论
还没有评论,写下第一条。