@gscdump/engine 0.31.5 → 0.31.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rollups.d.mts +6 -3
- package/dist/rollups.mjs +56 -35
- package/package.json +3 -3
package/dist/rollups.d.mts
CHANGED
|
@@ -220,6 +220,8 @@ declare const WINDOW_BYTE_BUDGET: number;
|
|
|
220
220
|
*/
|
|
221
221
|
declare const ROLLUP_PAGE_ROWS = 50000;
|
|
222
222
|
declare const ROLLUP_PAGE_ROWS_WIDE = 20000;
|
|
223
|
+
declare const ROLLUP_PAGE_ROWS_DAILY = 90000;
|
|
224
|
+
declare const DAILY_MAX_WINDOW_DAYS = 7;
|
|
223
225
|
/**
|
|
224
226
|
* UTC day-aligned [startMs, endMs] span a partition covers. Returns null for
|
|
225
227
|
* `hourly/` partitions and anything unrecognised — those are excluded from
|
|
@@ -240,7 +242,7 @@ declare function planRollupWindows(parts: Array<{
|
|
|
240
242
|
}>, clampRange?: {
|
|
241
243
|
start: string;
|
|
242
244
|
end: string;
|
|
243
|
-
}): Array<{
|
|
245
|
+
}, maxWindowDays?: number): Array<{
|
|
244
246
|
start: string;
|
|
245
247
|
end: string;
|
|
246
248
|
partitions: string[];
|
|
@@ -280,7 +282,8 @@ declare function runWindowed(opts: {
|
|
|
280
282
|
paginate?: {
|
|
281
283
|
orderBy: string;
|
|
282
284
|
pageRows: number;
|
|
283
|
-
};
|
|
285
|
+
}; /** Cap each window's day span (output-cardinality bound). See `planRollupWindows`. */
|
|
286
|
+
maxWindowDays?: number;
|
|
284
287
|
}): Promise<Row$1[]>;
|
|
285
288
|
/**
|
|
286
289
|
* Daily totals across the full history. One row per (date, table) with
|
|
@@ -446,4 +449,4 @@ declare const DEFAULT_ROLLUPS: readonly RollupDef[];
|
|
|
446
449
|
* (CLI: `gscdump rollups --with-canonical`).
|
|
447
450
|
*/
|
|
448
451
|
declare const CANONICAL_ROLLUPS: readonly RollupDef[];
|
|
449
|
-
export { CANONICAL_ROLLUPS, DEFAULT_ROLLUPS, ParquetRollupPointer, ROLLUP_PAGE_ROWS, ROLLUP_PAGE_ROWS_WIDE, RebuildDailyFromHourlyOptions, RebuildRollupResult, RebuildRollupsOptions, RollupBucket, RollupCtx, RollupDef, RollupEngine, RollupEnvelope, WINDOW_BYTE_BUDGET, dailyTotalsRollup, indexPercentRollup, indexingHealthRollup, indexingMetadataRollup, partitionDaySpan, partitionsInRange, planRollupWindows, queryCanonicalDailyRollup, queryCanonicalVariantsRollup, readLatestRollup, rebuildDailyFromHourly, rebuildRollups, rollupKey, rollupParquetKey, runWindowed, sitemapChanges28dRollup, sitemapHealthRollup, topCountries28dRollup, topKeywords28dParquetRollup, topKeywords28dRollup, topPages28dRollup, weeklyTotalsRollup };
|
|
452
|
+
export { CANONICAL_ROLLUPS, DAILY_MAX_WINDOW_DAYS, DEFAULT_ROLLUPS, ParquetRollupPointer, ROLLUP_PAGE_ROWS, ROLLUP_PAGE_ROWS_DAILY, ROLLUP_PAGE_ROWS_WIDE, RebuildDailyFromHourlyOptions, RebuildRollupResult, RebuildRollupsOptions, RollupBucket, RollupCtx, RollupDef, RollupEngine, RollupEnvelope, WINDOW_BYTE_BUDGET, dailyTotalsRollup, indexPercentRollup, indexingHealthRollup, indexingMetadataRollup, partitionDaySpan, partitionsInRange, planRollupWindows, queryCanonicalDailyRollup, queryCanonicalVariantsRollup, readLatestRollup, rebuildDailyFromHourly, rebuildRollups, rollupKey, rollupParquetKey, runWindowed, sitemapChanges28dRollup, sitemapHealthRollup, topCountries28dRollup, topKeywords28dParquetRollup, topKeywords28dRollup, topPages28dRollup, weeklyTotalsRollup };
|
package/dist/rollups.mjs
CHANGED
|
@@ -129,6 +129,8 @@ function utcDateMinusDays(at, days) {
|
|
|
129
129
|
const WINDOW_BYTE_BUDGET = 10 * 1024 * 1024;
|
|
130
130
|
const ROLLUP_PAGE_ROWS = 5e4;
|
|
131
131
|
const ROLLUP_PAGE_ROWS_WIDE = 2e4;
|
|
132
|
+
const ROLLUP_PAGE_ROWS_DAILY = 9e4;
|
|
133
|
+
const DAILY_MAX_WINDOW_DAYS = 7;
|
|
132
134
|
const DAY_RE = /^daily\/(\d{4})-(\d{2})-(\d{2})$/;
|
|
133
135
|
const WEEK_RE = /^weekly\/(\d{4})-(\d{2})-(\d{2})$/;
|
|
134
136
|
const MONTH_RE = /^monthly\/(\d{4})-(\d{2})$/;
|
|
@@ -177,7 +179,7 @@ function partitionDaySpan(partition) {
|
|
|
177
179
|
function clamp(n, lo, hi) {
|
|
178
180
|
return Math.max(lo, Math.min(hi, n));
|
|
179
181
|
}
|
|
180
|
-
function planRollupWindows(parts, clampRange) {
|
|
182
|
+
function planRollupWindows(parts, clampRange, maxWindowDays) {
|
|
181
183
|
const clampStartMs = clampRange ? Date.parse(`${clampRange.start}T00:00:00Z`) : void 0;
|
|
182
184
|
const clampEndMs = clampRange ? Date.parse(`${clampRange.end}T00:00:00Z`) : void 0;
|
|
183
185
|
const spans = [];
|
|
@@ -202,7 +204,8 @@ function planRollupWindows(parts, clampRange) {
|
|
|
202
204
|
const totalBytes = spans.reduce((a, s) => a + s.bytes, 0);
|
|
203
205
|
const spanDays = Math.floor((rangeEndMs - rangeStartMs) / MS_PER_DAY) + 1;
|
|
204
206
|
const bytesPerDay = Math.max(1, totalBytes / spanDays);
|
|
205
|
-
const
|
|
207
|
+
const byteWindowDays = clamp(Math.floor(WINDOW_BYTE_BUDGET / bytesPerDay), 7, 400);
|
|
208
|
+
const windowDays = maxWindowDays != null ? Math.max(1, Math.min(byteWindowDays, maxWindowDays)) : byteWindowDays;
|
|
206
209
|
const windows = [];
|
|
207
210
|
let cursorMs = rangeStartMs;
|
|
208
211
|
while (cursorMs <= rangeEndMs) {
|
|
@@ -248,7 +251,7 @@ async function runWindowed(opts) {
|
|
|
248
251
|
ctx: opts.ctx,
|
|
249
252
|
table: opts.table,
|
|
250
253
|
...opts.searchType !== void 0 ? { searchType: opts.searchType } : {}
|
|
251
|
-
}));
|
|
254
|
+
}), void 0, opts.maxWindowDays);
|
|
252
255
|
const rows = [];
|
|
253
256
|
for (const w of windows) {
|
|
254
257
|
const fileSets = {
|
|
@@ -603,44 +606,61 @@ const queryCanonicalVariantsRollup = {
|
|
|
603
606
|
});
|
|
604
607
|
if (parts.length === 0) return [];
|
|
605
608
|
const partitions = parts.map((p) => p.partition);
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
609
|
+
const byCanonical = /* @__PURE__ */ new Map();
|
|
610
|
+
let cursor = null;
|
|
611
|
+
for (;;) {
|
|
612
|
+
const after = cursor === null ? "" : `AND query > '${cursor.replace(/'/g, "''")}'`;
|
|
613
|
+
const { rows } = await engine.runSQL({
|
|
614
|
+
ctx,
|
|
612
615
|
table: "queries",
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
616
|
+
...searchType !== void 0 ? { searchType } : {},
|
|
617
|
+
fileSets: { FILES: {
|
|
618
|
+
table: "queries",
|
|
619
|
+
partitions
|
|
620
|
+
} },
|
|
621
|
+
sql: `
|
|
619
622
|
SELECT
|
|
620
623
|
COALESCE(NULLIF(query_canonical, ''), query) AS joinKey,
|
|
621
624
|
query AS query,
|
|
622
625
|
SUM(clicks) AS clicks,
|
|
623
626
|
SUM(impressions) AS impressions,
|
|
624
|
-
SUM(sum_position) AS sum_pos
|
|
625
|
-
ROW_NUMBER() OVER (PARTITION BY COALESCE(NULLIF(query_canonical, ''), query) ORDER BY SUM(clicks) DESC) AS rn,
|
|
626
|
-
COUNT(*) OVER (PARTITION BY COALESCE(NULLIF(query_canonical, ''), query)) AS variantCount
|
|
627
|
+
SUM(sum_position) AS sum_pos
|
|
627
628
|
FROM read_parquet({{FILES}}, union_by_name = true)
|
|
629
|
+
WHERE query IS NOT NULL ${after}
|
|
628
630
|
GROUP BY COALESCE(NULLIF(query_canonical, ''), query), query
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
631
|
+
ORDER BY query
|
|
632
|
+
LIMIT ${ROLLUP_PAGE_ROWS_WIDE}
|
|
633
|
+
`
|
|
634
|
+
});
|
|
635
|
+
for (const r of rows) {
|
|
636
|
+
const joinKey = String(r.joinKey);
|
|
637
|
+
const list = byCanonical.get(joinKey);
|
|
638
|
+
const v = {
|
|
639
|
+
query: String(r.query),
|
|
640
|
+
clicks: Number(r.clicks),
|
|
641
|
+
impressions: Number(r.impressions),
|
|
642
|
+
sumPos: Number(r.sum_pos)
|
|
643
|
+
};
|
|
644
|
+
if (list) list.push(v);
|
|
645
|
+
else byCanonical.set(joinKey, [v]);
|
|
646
|
+
}
|
|
647
|
+
if (rows.length < 2e4) break;
|
|
648
|
+
cursor = String(rows[rows.length - 1].query);
|
|
649
|
+
}
|
|
650
|
+
const out = [];
|
|
651
|
+
for (const [joinKey, variants] of byCanonical) {
|
|
652
|
+
variants.sort((a, b) => b.clicks - a.clicks || a.query.localeCompare(b.query));
|
|
653
|
+
const canonicalName = variants[0]?.query ?? null;
|
|
654
|
+
const top = variants.slice(0, 10).filter((v) => v.impressions > 0);
|
|
655
|
+
const variantsStr = top.length === 0 ? null : top.map((v) => `${v.query}:::${v.clicks}:::${v.impressions}:::${(v.sumPos / v.impressions + 1).toFixed(1)}`).join("||");
|
|
656
|
+
out.push({
|
|
657
|
+
joinKey,
|
|
658
|
+
variantCount: BigInt(variants.length),
|
|
659
|
+
canonicalName,
|
|
660
|
+
variants: variantsStr
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return out;
|
|
644
664
|
}
|
|
645
665
|
};
|
|
646
666
|
const queryCanonicalDailyRollup = {
|
|
@@ -690,8 +710,9 @@ const queryCanonicalDailyRollup = {
|
|
|
690
710
|
} } } : {},
|
|
691
711
|
paginate: {
|
|
692
712
|
orderBy: "date, query_canonical",
|
|
693
|
-
pageRows:
|
|
713
|
+
pageRows: ROLLUP_PAGE_ROWS_DAILY
|
|
694
714
|
},
|
|
715
|
+
maxWindowDays: 7,
|
|
695
716
|
sqlFor: useDim ? (w) => `
|
|
696
717
|
SELECT
|
|
697
718
|
${canonExpr} AS query_canonical,
|
|
@@ -1035,4 +1056,4 @@ const DEFAULT_ROLLUPS = [
|
|
|
1035
1056
|
sitemapChanges28dRollup
|
|
1036
1057
|
];
|
|
1037
1058
|
const CANONICAL_ROLLUPS = [queryCanonicalVariantsRollup, queryCanonicalDailyRollup];
|
|
1038
|
-
export { CANONICAL_ROLLUPS, DEFAULT_ROLLUPS, ROLLUP_PAGE_ROWS, ROLLUP_PAGE_ROWS_WIDE, WINDOW_BYTE_BUDGET, dailyTotalsRollup, indexPercentRollup, indexingHealthRollup, indexingMetadataRollup, partitionDaySpan, partitionsInRange, planRollupWindows, queryCanonicalDailyRollup, queryCanonicalVariantsRollup, readLatestRollup, rebuildDailyFromHourly, rebuildRollups, rollupKey, rollupParquetKey, runWindowed, sitemapChanges28dRollup, sitemapHealthRollup, topCountries28dRollup, topKeywords28dParquetRollup, topKeywords28dRollup, topPages28dRollup, weeklyTotalsRollup };
|
|
1059
|
+
export { CANONICAL_ROLLUPS, DAILY_MAX_WINDOW_DAYS, DEFAULT_ROLLUPS, ROLLUP_PAGE_ROWS, ROLLUP_PAGE_ROWS_DAILY, ROLLUP_PAGE_ROWS_WIDE, WINDOW_BYTE_BUDGET, dailyTotalsRollup, indexPercentRollup, indexingHealthRollup, indexingMetadataRollup, partitionDaySpan, partitionsInRange, planRollupWindows, queryCanonicalDailyRollup, queryCanonicalVariantsRollup, readLatestRollup, rebuildDailyFromHourly, rebuildRollups, rollupKey, rollupParquetKey, runWindowed, sitemapChanges28dRollup, sitemapHealthRollup, topCountries28dRollup, topKeywords28dParquetRollup, topKeywords28dRollup, topPages28dRollup, weeklyTotalsRollup };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.31.
|
|
4
|
+
"version": "0.31.7",
|
|
5
5
|
"description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -181,8 +181,8 @@
|
|
|
181
181
|
"dependencies": {
|
|
182
182
|
"drizzle-orm": "1.0.0-rc.3",
|
|
183
183
|
"proper-lockfile": "^4.1.2",
|
|
184
|
-
"gscdump": "0.31.
|
|
185
|
-
"
|
|
184
|
+
"@gscdump/contracts": "0.31.7",
|
|
185
|
+
"gscdump": "0.31.7"
|
|
186
186
|
},
|
|
187
187
|
"devDependencies": {
|
|
188
188
|
"@duckdb/duckdb-wasm": "^1.32.0",
|