Initiales Ingest-Repo (aus gdelt-bot/ingest überführt)
Poller, Schema, Quadlet-Units und Quellenregister aus dem Monorepo gdelt-bot in ein eigenes Repo ausgelagert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VzNVf1KaHPZ1fzJT2jd18j
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
-- Schema fuer den Ingest.
|
||||
--
|
||||
-- Grundregel: raw_items ist append-only und wird nie ueberschrieben.
|
||||
-- Kodierungen sind eine getrennte Stufe mit eigener Versionierung, damit die
|
||||
-- gesamte Historie neu kodiert werden kann, ohne einen Feed erneut abzurufen.
|
||||
|
||||
create extension if not exists pg_trgm;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- Quellen: aus ingest/sources.toml synchronisiert, nie von Hand pflegen.
|
||||
-- --------------------------------------------------------------------------
|
||||
create table if not exists quellen (
|
||||
id text primary key,
|
||||
name text not null,
|
||||
typ text not null check (typ in ('rss', 'telegram')),
|
||||
url text not null,
|
||||
land text not null,
|
||||
traeger text,
|
||||
ressort text,
|
||||
lizenz_status text not null
|
||||
check (lizenz_status in ('offen','gesperrt','ungeprueft')),
|
||||
robots_geprueft_am date,
|
||||
aktiv boolean not null default false,
|
||||
notiz text,
|
||||
|
||||
-- Poller-Zustand, nicht aus der TOML
|
||||
etag text,
|
||||
last_modified text,
|
||||
zuletzt_geprueft timestamptz,
|
||||
zuletzt_geaendert timestamptz
|
||||
);
|
||||
|
||||
comment on column quellen.zuletzt_geprueft is 'letzter Abruf, auch wenn 304';
|
||||
comment on column quellen.zuletzt_geaendert is 'letzter Abruf mit neuen Items';
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- Rohdaten. Append-only. RSS-Feeds haben kein Archiv: was hier fehlt, ist
|
||||
-- unwiederbringlich weg.
|
||||
-- --------------------------------------------------------------------------
|
||||
create table if not exists raw_items (
|
||||
id bigserial primary key,
|
||||
quelle text not null references quellen(id),
|
||||
item_key text not null, -- guid/link, nur innerhalb der Quelle eindeutig
|
||||
url text,
|
||||
titel text not null,
|
||||
titel_norm text not null, -- normalisiert, fuer Clustering
|
||||
teaser text,
|
||||
autor text,
|
||||
pubdate timestamptz, -- Angabe der Quelle, kann fehlen/luegen
|
||||
abgerufen_am timestamptz not null default now(),
|
||||
slot timestamptz not null, -- auf 15 min abgerundet, GDELT-kompatibel
|
||||
sprache text not null default 'de',
|
||||
roh jsonb not null, -- alle geparsten Feldwerte, unveraendert
|
||||
|
||||
unique (quelle, item_key)
|
||||
);
|
||||
|
||||
create index if not exists raw_items_slot_idx on raw_items (slot desc);
|
||||
create index if not exists raw_items_pubdate_idx on raw_items (pubdate desc nulls last);
|
||||
create index if not exists raw_items_quelle_idx on raw_items (quelle, abgerufen_am desc);
|
||||
-- Titel-Clustering laeuft ueber Trigramm-Aehnlichkeit in SQL, nicht in Python
|
||||
create index if not exists raw_items_titelnorm_trgm
|
||||
on raw_items using gin (titel_norm gin_trgm_ops);
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- Kodierungen. Eine Zeile pro (Item, Kodierer-Version). Die Nutzlast bleibt
|
||||
-- absichtlich jsonb, solange nicht gemessen ist, bis zu welcher CAMEO-Ebene
|
||||
-- das gewaehlte Modell traegt.
|
||||
-- --------------------------------------------------------------------------
|
||||
create table if not exists codings (
|
||||
id bigserial primary key,
|
||||
raw_item_id bigint not null references raw_items(id) on delete cascade,
|
||||
coder_version text not null, -- z.B. 'qwen3-14b-q4/prompt-3'
|
||||
kodiert_am timestamptz not null default now(),
|
||||
ebene text not null -- erreichte CAMEO-Ebene
|
||||
check (ebene in ('keine','quad','root','base','event')),
|
||||
konfidenz real,
|
||||
nutzlast jsonb not null,
|
||||
|
||||
unique (raw_item_id, coder_version)
|
||||
);
|
||||
|
||||
create index if not exists codings_version_idx on codings (coder_version, kodiert_am desc);
|
||||
|
||||
-- Arbeitsvorrat fuer Yantra: was diese Kodierer-Version noch nicht gesehen hat.
|
||||
-- Aufruf: select * from unkodiert('qwen3-14b-q4/prompt-3') limit 500;
|
||||
create or replace function unkodiert(v text)
|
||||
returns setof raw_items language sql stable as $$
|
||||
select r.* from raw_items r
|
||||
where not exists (
|
||||
select 1 from codings c
|
||||
where c.raw_item_id = r.id and c.coder_version = v
|
||||
)
|
||||
order by r.id
|
||||
$$;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
-- Betriebsprotokoll. Damit der Watchdog eine stillstehende Quelle bemerkt,
|
||||
-- bevor Tage fehlen.
|
||||
-- --------------------------------------------------------------------------
|
||||
create table if not exists poll_laeufe (
|
||||
id bigserial primary key,
|
||||
quelle text not null references quellen(id),
|
||||
slot timestamptz not null,
|
||||
begonnen_am timestamptz not null default now(),
|
||||
dauer_ms integer,
|
||||
http_status integer, -- 304 = unveraendert
|
||||
items_gesehen integer not null default 0,
|
||||
items_neu integer not null default 0,
|
||||
fehler text
|
||||
);
|
||||
|
||||
create index if not exists poll_laeufe_slot_idx on poll_laeufe (slot desc);
|
||||
create index if not exists poll_laeufe_quelle_idx on poll_laeufe (quelle, begonnen_am desc);
|
||||
|
||||
-- Welche aktive Quelle hat seit ueber sechs Stunden nichts Neues geliefert?
|
||||
create or replace view quellen_stillstand as
|
||||
select q.id, q.name, max(r.abgerufen_am) as letztes_item,
|
||||
now() - max(r.abgerufen_am) as stille
|
||||
from quellen q
|
||||
left join raw_items r on r.quelle = q.id
|
||||
where q.aktiv
|
||||
group by q.id, q.name
|
||||
having max(r.abgerufen_am) is null
|
||||
or now() - max(r.abgerufen_am) > interval '6 hours'
|
||||
order by stille desc nulls first;
|
||||
Reference in New Issue
Block a user