Running a Local Shake Alert Log Through Postgres, Not a Spreadsheet

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

During the 2023 swarm near our county line I was keeping a hand-typed CSV of every felt report my neighbors sent in: roughly 1,400 rows over nine days, timestamps in three different formats, and a column of “was it loud?” notes. The spreadsheet choked at about 900 rows and I lost an afternoon re-sorting. The environment is boring: one old laptop, Postgres 15, no cloud, no dashboard. That was enough.

The fix was to stop treating the log as a document. I made three tables and a view, and the whole thing fits in about 40 lines:

create table felt_report (
  id bigserial primary key,
  reported_at timestamptz not null,
  lat double precision,
  lon double precision,
  intensity smallint check (intensity between 1 and 12),
  note text
);

create table event (
  id bigserial primary key,
  origin_time timestamptz not null,
  mag numeric(3,1),
  depth_km numeric(5,1)
);

create view report_with_event as
select r.*, e.mag, e.depth_km,
       extract(epoch from (r.reported_at - e.origin_time)) as lag_s
from felt_report r
join lateral (
  select * from event e
  where e.origin_time <= r.reported_at
  order by e.origin_time desc limit 1
) e on true;

Then the only rule I enforce is that every entry goes through \copy from a pipe-delimited file, never through typing into a GUI. The pipe file is ugly but stable: 2023-09-14T02:11:07-07|34.02|-117.31|4|dog woke up.

What this buys is the lag column. Before, I could tell you a report was “around 2am”; with lag_s I can see that the loud-note reports cluster between 8 and 25 seconds after origin time, while the ones marked “gentle” show up 40 seconds to several minutes later. That is not a scientific finding, it is a sorting property of how people type, but it changed how I read the pile. The cost is real: I have to maintain the event table by hand, and a wrong magnitude or a missed event quietly corrupts every join for that window. I have done that twice.

The approach fails when reports are not tied to a single event, which is exactly what happens in a swarm. My lateral join assigns each report to the most recent origin, so during overlapping events the lag is meaningless and I have to fall back to reading notes. It also fails if anyone sends a report with no timestamp or a local time without an offset; Postgres will accept a naive string and silently assume the server timezone. I lost two days of reports to that before I added set timezone = 'UTC' at the top of the load script.

What I would like to know from people who log felt reports: do you keep one row per report, or one row per report per event, and how do you decide which event a late-arriving report belongs to when the origin times are minutes apart?

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

0 条评论

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

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