@gscdump/engine 0.31.8 → 0.31.9
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 +29 -1
- package/dist/rollups.mjs +129 -31
- package/package.json +3 -3
package/dist/rollups.d.mts
CHANGED
|
@@ -364,6 +364,34 @@ declare const queryCanonicalVariantsRollup: RollupDef;
|
|
|
364
364
|
* `RunOptimizedQueryOptions.canonicalSource`).
|
|
365
365
|
*/
|
|
366
366
|
declare const queryCanonicalDailyRollup: RollupDef;
|
|
367
|
+
/**
|
|
368
|
+
* Resumable, cross-invocation build of `query_canonical_daily` for a high-
|
|
369
|
+
* cardinality site whose full windowed build exceeds one job reservation (300s).
|
|
370
|
+
*
|
|
371
|
+
* Each call builds the day-capped windows from `windowOffset` until `deadlineMs`,
|
|
372
|
+
* writes that batch's rows to a STAGING partial parquet (windows are disjoint by
|
|
373
|
+
* date, so partials never overlap), and returns `{ done:false, nextWindowOffset }`
|
|
374
|
+
* for the caller to re-enqueue. When the last window is built it MERGES every
|
|
375
|
+
* staging partial into the canonical `query_canonical_daily` parquet + envelope
|
|
376
|
+
* (the read path is unchanged — still one rollup file) and deletes the staging,
|
|
377
|
+
* returning `{ done:true }`. `builtAt` MUST be stable across the continuation chain
|
|
378
|
+
* (it versions both the staging keys and the final rollup key).
|
|
379
|
+
*/
|
|
380
|
+
declare function rebuildCanonicalDailyResumable(opts: {
|
|
381
|
+
engine: RollupEngine;
|
|
382
|
+
ctx: TenantCtx;
|
|
383
|
+
dataSource: DataSource;
|
|
384
|
+
searchType?: SearchType;
|
|
385
|
+
builtAt: number;
|
|
386
|
+
windowOffset: number;
|
|
387
|
+
deadlineMs: number;
|
|
388
|
+
}): Promise<{
|
|
389
|
+
done: boolean;
|
|
390
|
+
nextWindowOffset: number;
|
|
391
|
+
windowsTotal: number;
|
|
392
|
+
windowsBuilt: number;
|
|
393
|
+
rowsWritten: number;
|
|
394
|
+
}>;
|
|
367
395
|
/**
|
|
368
396
|
* Aggregates the per-URL Indexing API metadata entity store (populated by
|
|
369
397
|
* `gscdump entities indexing snapshot`) into daily counts of `URL_UPDATED`
|
|
@@ -449,4 +477,4 @@ declare const DEFAULT_ROLLUPS: readonly RollupDef[];
|
|
|
449
477
|
* (CLI: `gscdump rollups --with-canonical`).
|
|
450
478
|
*/
|
|
451
479
|
declare const CANONICAL_ROLLUPS: readonly RollupDef[];
|
|
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 };
|
|
480
|
+
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, rebuildCanonicalDailyResumable, rebuildDailyFromHourly, rebuildRollups, rollupKey, rollupParquetKey, runWindowed, sitemapChanges28dRollup, sitemapHealthRollup, topCountries28dRollup, topKeywords28dParquetRollup, topKeywords28dRollup, topPages28dRollup, weeklyTotalsRollup };
|
package/dist/rollups.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./_chunks/layout.mjs";
|
|
2
2
|
import { engineErrors } from "./errors.mjs";
|
|
3
|
-
import { encodeRowsToParquetFlex } from "./adapters/hyparquet.mjs";
|
|
3
|
+
import { decodeParquetToRows, encodeRowsToParquetFlex } from "./adapters/hyparquet.mjs";
|
|
4
4
|
import { createIndexingMetadataStore, createQueryDimStore, createSitemapStore, inspectionParquetKey, sitemapUrlsIndexPrefix } from "./_chunks/entities.mjs";
|
|
5
5
|
import { MS_PER_DAY } from "gscdump";
|
|
6
6
|
function rollupPrefix(ctx, searchType) {
|
|
@@ -713,37 +713,135 @@ const queryCanonicalDailyRollup = {
|
|
|
713
713
|
pageRows: ROLLUP_PAGE_ROWS_DAILY
|
|
714
714
|
},
|
|
715
715
|
maxWindowDays: 7,
|
|
716
|
-
sqlFor: useDim
|
|
717
|
-
|
|
718
|
-
${canonExpr} AS query_canonical,
|
|
719
|
-
CAST(q.date AS VARCHAR) AS date,
|
|
720
|
-
SUM(q.clicks)::BIGINT AS clicks,
|
|
721
|
-
SUM(q.impressions)::BIGINT AS impressions,
|
|
722
|
-
SUM(q.sum_position)::DOUBLE AS sum_position
|
|
723
|
-
FROM read_parquet({{FILES}}, union_by_name = true) q
|
|
724
|
-
LEFT JOIN read_parquet({{QUERY_DIM}}, union_by_name = true) qd ON q.query = qd.query
|
|
725
|
-
WHERE q.date >= '${w.start}' AND q.date <= '${w.end}'
|
|
726
|
-
GROUP BY ${canonExpr}, q.date
|
|
727
|
-
` : (w) => `
|
|
728
|
-
SELECT
|
|
729
|
-
${canonExpr} AS query_canonical,
|
|
730
|
-
CAST(date AS VARCHAR) AS date,
|
|
731
|
-
SUM(clicks)::BIGINT AS clicks,
|
|
732
|
-
SUM(impressions)::BIGINT AS impressions,
|
|
733
|
-
SUM(sum_position)::DOUBLE AS sum_position
|
|
734
|
-
FROM read_parquet({{FILES}}, union_by_name = true)
|
|
735
|
-
WHERE date >= '${w.start}' AND date <= '${w.end}'
|
|
736
|
-
GROUP BY ${canonExpr}, date
|
|
737
|
-
`
|
|
738
|
-
})).map((r) => ({
|
|
739
|
-
query_canonical: String(r.query_canonical),
|
|
740
|
-
date: String(r.date),
|
|
741
|
-
clicks: BigInt(r.clicks),
|
|
742
|
-
impressions: BigInt(r.impressions),
|
|
743
|
-
sum_position: Number(r.sum_position)
|
|
744
|
-
}));
|
|
716
|
+
sqlFor: dailyWindowSqlFor(useDim, canonExpr)
|
|
717
|
+
})).map(mapDailyRow);
|
|
745
718
|
}
|
|
746
719
|
};
|
|
720
|
+
function dailyWindowSqlFor(useDim, canonExpr) {
|
|
721
|
+
return useDim ? (w) => `
|
|
722
|
+
SELECT
|
|
723
|
+
${canonExpr} AS query_canonical,
|
|
724
|
+
CAST(q.date AS VARCHAR) AS date,
|
|
725
|
+
SUM(q.clicks)::BIGINT AS clicks,
|
|
726
|
+
SUM(q.impressions)::BIGINT AS impressions,
|
|
727
|
+
SUM(q.sum_position)::DOUBLE AS sum_position
|
|
728
|
+
FROM read_parquet({{FILES}}, union_by_name = true) q
|
|
729
|
+
LEFT JOIN read_parquet({{QUERY_DIM}}, union_by_name = true) qd ON q.query = qd.query
|
|
730
|
+
WHERE q.date >= '${w.start}' AND q.date <= '${w.end}'
|
|
731
|
+
GROUP BY ${canonExpr}, q.date
|
|
732
|
+
` : (w) => `
|
|
733
|
+
SELECT
|
|
734
|
+
${canonExpr} AS query_canonical,
|
|
735
|
+
CAST(date AS VARCHAR) AS date,
|
|
736
|
+
SUM(clicks)::BIGINT AS clicks,
|
|
737
|
+
SUM(impressions)::BIGINT AS impressions,
|
|
738
|
+
SUM(sum_position)::DOUBLE AS sum_position
|
|
739
|
+
FROM read_parquet({{FILES}}, union_by_name = true)
|
|
740
|
+
WHERE date >= '${w.start}' AND date <= '${w.end}'
|
|
741
|
+
GROUP BY ${canonExpr}, date
|
|
742
|
+
`;
|
|
743
|
+
}
|
|
744
|
+
function mapDailyRow(r) {
|
|
745
|
+
return {
|
|
746
|
+
query_canonical: String(r.query_canonical),
|
|
747
|
+
date: String(r.date),
|
|
748
|
+
clicks: BigInt(r.clicks),
|
|
749
|
+
impressions: BigInt(r.impressions),
|
|
750
|
+
sum_position: Number(r.sum_position)
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
const CANONICAL_DAILY_STAGING_STEM = "query_canonical_daily__staging";
|
|
754
|
+
async function rebuildCanonicalDailyResumable(opts) {
|
|
755
|
+
const { engine, ctx, dataSource, searchType, builtAt, windowOffset, deadlineMs } = opts;
|
|
756
|
+
const sType = searchType !== void 0 ? { searchType } : {};
|
|
757
|
+
const windows = planRollupWindows((await engine.listPartitions({
|
|
758
|
+
ctx,
|
|
759
|
+
table: "queries",
|
|
760
|
+
...sType
|
|
761
|
+
})).map((p) => ({
|
|
762
|
+
partition: p.partition,
|
|
763
|
+
bytes: p.bytes
|
|
764
|
+
})), void 0, 7);
|
|
765
|
+
const windowsTotal = windows.length;
|
|
766
|
+
const dimStore = createQueryDimStore({ dataSource });
|
|
767
|
+
const useDim = await dimStore.loadMeta(ctx) !== null;
|
|
768
|
+
const canonExpr = useDim ? `COALESCE(qd.query_canonical, NULLIF(q.query_canonical, ''), q.query)` : `COALESCE(NULLIF(query_canonical, ''), query)`;
|
|
769
|
+
const extraFileSets = useDim ? { QUERY_DIM: {
|
|
770
|
+
table: "queries",
|
|
771
|
+
keys: [dimStore.parquetKey(ctx)]
|
|
772
|
+
} } : void 0;
|
|
773
|
+
const sqlFor = dailyWindowSqlFor(useDim, canonExpr);
|
|
774
|
+
const cols = queryCanonicalDailyRollup.parquetColumns;
|
|
775
|
+
const sortKey = queryCanonicalDailyRollup.parquetSortKey;
|
|
776
|
+
const batchRows = [];
|
|
777
|
+
let i = windowOffset;
|
|
778
|
+
for (; i < windowsTotal; i++) {
|
|
779
|
+
const w = windows[i];
|
|
780
|
+
const winRows = await runPagedQuery({
|
|
781
|
+
engine,
|
|
782
|
+
ctx,
|
|
783
|
+
table: "queries",
|
|
784
|
+
...sType,
|
|
785
|
+
fileSets: {
|
|
786
|
+
FILES: {
|
|
787
|
+
table: "queries",
|
|
788
|
+
partitions: w.partitions
|
|
789
|
+
},
|
|
790
|
+
...extraFileSets
|
|
791
|
+
},
|
|
792
|
+
coreSql: sqlFor(w),
|
|
793
|
+
orderBy: "date, query_canonical",
|
|
794
|
+
pageRows: ROLLUP_PAGE_ROWS_DAILY
|
|
795
|
+
});
|
|
796
|
+
for (const r of winRows) batchRows.push(mapDailyRow(r));
|
|
797
|
+
if (Date.now() > deadlineMs) {
|
|
798
|
+
i++;
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const nextWindowOffset = i;
|
|
803
|
+
const stagingKey = rollupParquetKey(ctx, `${CANONICAL_DAILY_STAGING_STEM}__w${windowOffset}`, builtAt, searchType);
|
|
804
|
+
await dataSource.write(stagingKey, encodeRowsToParquetFlex(batchRows, {
|
|
805
|
+
columns: cols,
|
|
806
|
+
sortKey
|
|
807
|
+
}));
|
|
808
|
+
if (nextWindowOffset < windowsTotal) return {
|
|
809
|
+
done: false,
|
|
810
|
+
nextWindowOffset,
|
|
811
|
+
windowsTotal,
|
|
812
|
+
windowsBuilt: nextWindowOffset - windowOffset,
|
|
813
|
+
rowsWritten: batchRows.length
|
|
814
|
+
};
|
|
815
|
+
const stagingPrefix = rollupParquetKey(ctx, `${CANONICAL_DAILY_STAGING_STEM}__`, builtAt, searchType).replace(/__v\d+\.parquet$/, "");
|
|
816
|
+
const stagingKeys = (await dataSource.list(stagingPrefix.replace(/[^/]*$/, ""))).filter((k) => k.includes(`${CANONICAL_DAILY_STAGING_STEM}__w`) && k.includes(`__v${builtAt}.parquet`));
|
|
817
|
+
const merged = [];
|
|
818
|
+
for (const k of stagingKeys) merged.push(...await decodeParquetToRows(await dataSource.read(k), { columns: cols.map((c) => c.name) }));
|
|
819
|
+
const parquetKey = rollupParquetKey(ctx, CANONICAL_DAILY_ROLLUP_FINAL_ID, builtAt, searchType);
|
|
820
|
+
await dataSource.write(parquetKey, encodeRowsToParquetFlex(merged, {
|
|
821
|
+
columns: cols,
|
|
822
|
+
sortKey
|
|
823
|
+
}));
|
|
824
|
+
const envelope = {
|
|
825
|
+
version: 1,
|
|
826
|
+
id: CANONICAL_DAILY_ROLLUP_FINAL_ID,
|
|
827
|
+
builtAt,
|
|
828
|
+
windowDays: queryCanonicalDailyRollup.windowDays,
|
|
829
|
+
payload: {
|
|
830
|
+
parquetKey,
|
|
831
|
+
rowCount: merged.length
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
await dataSource.write(rollupKey(ctx, CANONICAL_DAILY_ROLLUP_FINAL_ID, builtAt, searchType), new TextEncoder().encode(JSON.stringify(envelope)));
|
|
835
|
+
await dataSource.delete(stagingKeys);
|
|
836
|
+
return {
|
|
837
|
+
done: true,
|
|
838
|
+
nextWindowOffset,
|
|
839
|
+
windowsTotal,
|
|
840
|
+
windowsBuilt: nextWindowOffset - windowOffset,
|
|
841
|
+
rowsWritten: merged.length
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
const CANONICAL_DAILY_ROLLUP_FINAL_ID = "query_canonical_daily";
|
|
747
845
|
const indexingMetadataRollup = {
|
|
748
846
|
id: "indexing_metadata",
|
|
749
847
|
windowDays: null,
|
|
@@ -1056,4 +1154,4 @@ const DEFAULT_ROLLUPS = [
|
|
|
1056
1154
|
sitemapChanges28dRollup
|
|
1057
1155
|
];
|
|
1058
1156
|
const CANONICAL_ROLLUPS = [queryCanonicalVariantsRollup, queryCanonicalDailyRollup];
|
|
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 };
|
|
1157
|
+
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, rebuildCanonicalDailyResumable, 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.9",
|
|
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
|
-
"
|
|
185
|
-
"gscdump": "0.31.
|
|
184
|
+
"gscdump": "0.31.9",
|
|
185
|
+
"@gscdump/contracts": "0.31.9"
|
|
186
186
|
},
|
|
187
187
|
"devDependencies": {
|
|
188
188
|
"@duckdb/duckdb-wasm": "^1.32.0",
|