Skip to content

Commit 9dddb6e

Browse files
fix(bug): fix bug on update tick after tag unnesting
1 parent 171987a commit 9dddb6e

2 files changed

Lines changed: 33 additions & 28 deletions

File tree

osmsg/export/psql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def _push_changeset_hashtags(conn: duckdb.DuckDBPyConnection, where: str = "") -
116116
conn.execute(
117117
f"""
118118
INSERT INTO pg_target.changeset_hashtag (hashtag, changeset_id, created_at)
119-
SELECT lower(h), changeset_id, created_at FROM changesets AS c, unnest(c.hashtags) AS h {where}
119+
SELECT lower(h), changeset_id, created_at FROM changesets AS c, unnest(c.hashtags) AS t(h) {where}
120120
ON CONFLICT (hashtag, changeset_id) DO NOTHING
121121
"""
122122
)

osmsg/query.py

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,21 @@ def leaderboard(
268268
page_size = max(1, min(page_size, MAX_PAGE_SIZE))
269269
prefixes = _prefixes(hashtag)
270270
hsql, hp = _history(s, prefixes, start, end)
271-
# Materialize the deduped history once; _q_lb and the per-user tag attach both read it (avoids
272-
# re-scanning the rollup three times for a mega-hashtag page).
273-
con.execute(f"CREATE OR REPLACE TEMP TABLE _hist_cs AS SELECT * FROM ({hsql})", hp)
274-
rrel, rp = _recent_leaderboard(s, prefixes, start, end)
275-
con.execute(
276-
f"CREATE OR REPLACE TEMP TABLE _q_lb AS "
277-
f"SELECT uid, count(*) AS changesets, {_SUM_AS}, list(DISTINCT editor) AS editors FROM _hist_cs GROUP BY uid"
271+
count_sql, count_params = catalog.history_scope_count(
272+
s.history_rel, prefixes=prefixes, frontier=s.frontier, start=start, end=end
278273
)
274+
count_row = con.execute(count_sql, count_params).fetchone()
275+
small_history = (count_row[0] if count_row else 0) <= _MAX_TAG_ROWS
276+
_q_lb_agg = f"SELECT uid, count(*) AS changesets, {_SUM_AS}, list(DISTINCT editor) AS editors"
277+
if small_history:
278+
# Small history: materialize once and reuse it for the per-user tag attach.
279+
con.execute(f"CREATE OR REPLACE TEMP TABLE _hist_cs AS SELECT * FROM ({hsql})", hp)
280+
con.execute(f"CREATE OR REPLACE TEMP TABLE _q_lb AS {_q_lb_agg} FROM _hist_cs GROUP BY uid")
281+
else:
282+
# Mega history: stream the dedup straight into the per-user aggregate; materializing the wide
283+
# multi-million-row history would blow up.
284+
con.execute(f"CREATE OR REPLACE TEMP TABLE _q_lb AS {_q_lb_agg} FROM ({hsql}) GROUP BY uid", hp)
285+
rrel, rp = _recent_leaderboard(s, prefixes, start, end)
279286
search_pred, search_params = "", []
280287
if q:
281288
search_pred = " WHERE lower(name) LIKE ?"
@@ -311,12 +318,7 @@ def leaderboard(
311318
)
312319
for i, r in enumerate(rows):
313320
r["rank"] = offset + i + 1
314-
count_sql, count_params = catalog.history_scope_count(
315-
s.history_rel, prefixes=prefixes, frontier=s.frontier, start=start, end=end
316-
)
317-
count_row = con.execute(count_sql, count_params).fetchone()
318-
history_rows = count_row[0] if count_row else 0
319-
if history_rows <= _MAX_TAG_ROWS:
321+
if small_history:
320322
_attach_user_tags(con, rows, s, prefixes, start, end, hist_rel="_hist_cs")
321323
else:
322324
for r in rows:
@@ -504,23 +506,26 @@ def map_points(
504506
end: dt.datetime | None = None,
505507
) -> list[dict[str, Any]]:
506508
"""Changeset centroids `(changeset_id, uid, lon, lat)` for the hashtag union, up to `limit`, for a
507-
map. Optional [start, end) window. History centroids come from the rollup, recent from the base
508-
changesets bbox; the rollup must carry `lon`/`lat` (published rollups built after the map change do)."""
509+
map. Optional [start, end) window. Recent centroids come from the base changesets bbox; history
510+
centroids come from the rollup only when it carries `lon`/`lat` (older published rollups do not)."""
509511
prefixes = _prefixes(hashtag)
510512
if s.pg_attach:
511-
window_sql, window_params = catalog._window_clause(start, end)
512-
prefix_params = [bound for pair in prefixes for bound in pair]
513-
hist_pred = " OR ".join("(hashtag >= ? AND hashtag < ?)" for _ in prefixes)
514-
hist = (
515-
f"SELECT changeset_id, uid, lon, lat FROM {s.history_rel} "
516-
f"WHERE ({hist_pred}) AND created_at < ?{window_sql} AND lon IS NOT NULL"
517-
)
518513
rrel = catalog.recent_map_agg(s.pg_attach, prefixes=prefixes, frontier=s.frontier, start=start, end=end)
519-
sql = (
520-
f"SELECT DISTINCT ON (changeset_id) changeset_id, uid, lon, lat "
521-
f"FROM ({hist} UNION ALL SELECT changeset_id, uid, lon, lat FROM {rrel})"
522-
)
523-
res = con.execute(f"{sql} LIMIT ?", [*prefix_params, s.frontier, *window_params, limit])
514+
recent_sel = f"SELECT changeset_id, uid, lon, lat FROM {rrel}"
515+
history_cols = {d[0] for d in con.execute(f"SELECT * FROM {s.history_rel} LIMIT 0").description}
516+
if "lon" in history_cols and "lat" in history_cols:
517+
window_sql, window_params = catalog._window_clause(start, end)
518+
prefix_params = [bound for pair in prefixes for bound in pair]
519+
hist_pred = " OR ".join("(hashtag >= ? AND hashtag < ?)" for _ in prefixes)
520+
hist = (
521+
f"SELECT changeset_id, uid, lon, lat FROM {s.history_rel} "
522+
f"WHERE ({hist_pred}) AND created_at < ?{window_sql} AND lon IS NOT NULL"
523+
)
524+
sql = f"SELECT DISTINCT ON (changeset_id) changeset_id, uid, lon, lat FROM ({hist} UNION ALL {recent_sel})"
525+
res = con.execute(f"{sql} LIMIT ?", [*prefix_params, s.frontier, *window_params, limit])
526+
else:
527+
sql = f"SELECT DISTINCT ON (changeset_id) changeset_id, uid, lon, lat FROM ({recent_sel})"
528+
res = con.execute(f"{sql} LIMIT ?", [limit])
524529
return _rows(res)
525530
sql, params = map_scope(
526531
s.history_rel, s.recent_changesets_rel, prefixes=prefixes, frontier=s.frontier, start=start, end=end

0 commit comments

Comments
 (0)