diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 8890f03eb..745033239 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -130,7 +130,7 @@ jobs:
python3 -m unittest -v test_viewer test_server
- name: Run the DAG viewer's Node tests
- run: node --test tools/dag-viewer/stages.test.mjs
+ run: node --test tools/dag-viewer/stages.test.mjs tools/dag-viewer/enumeration.test.mjs
# A PromQL-only runtime builds asap-planner without DataFusion or MetricsQL.
- name: Check and test asap-planner with the PromQL frontend alone
diff --git a/tools/dag-viewer/README.md b/tools/dag-viewer/README.md
index c6fb938ef..de40e2759 100644
--- a/tools/dag-viewer/README.md
+++ b/tools/dag-viewer/README.md
@@ -76,6 +76,28 @@ To run it, see [RUNNING.md](RUNNING.md).
for the newest), a `TimeRange` of one pane and the pane's build with its
window (`window t−40 s … t−20 s`), and clicking a pane folds them back.
This is display only: the document keeps the chain.
+- **Enumerated DAGs**, between the Stage 0 and Stage 1 lanes, shown only
+ when the document has `memo.enumeration`: the complete candidate DAGs the
+ memo stands for. The header counts them after each memo step (`Stage 0: 1 ·
+ Pass 1: 49 · Pass 2: ≥ 1000 · concrete states: ≥ 1000`; `≥` and the limit when counting stopped), says how
+ many of the enumerated step's DAGs the document lists, and, when they were
+ priced, how many are cheaper than the selected plan. Each row names the
+ groups whose candidate differs from the selected plan's choice
+ (`G7 → #2 CountSketch+heap (pass1)`: group, candidate index, its label and
+ origin when the step's memo lists the candidate; a group a choice does not
+ name takes candidate 0). The selected choice is over the last memo step;
+ when an earlier step was enumerated, the header says so and only each
+ row's own groups are compared. A row also shows `budget share < 1` when
+ a chosen candidate shares its budget, and, when priced, its cost and
+ validity (`✗ invalid` with the cause). A row cheaper than the selected
+ plan is red; the selected choice says `✓ selected`. Clicking a row draws
+ its DAG in the Stage 1 lane; the document holds every listed choice's
+ composed DAG, so the page composes nothing. Such a DAG has no Stage 2
+ plan, so the Stage 2 lane is cleared. Its roots are its root groups, in
+ increasing group id; the lane draws each as the root of the queries in its
+ group's `roots_of`, or labels it `root group #n` when that cannot be
+ matched (the enumerated step's memo is not in the document). When the enumerated step is earlier than the last
+ one, no row is marked selected.
- **Highlighting**: the **highlight query** menu dims, in every lane, what
that query's root does not reach. Clicking a node dims everything but
what it reads and what reads it, directly or through other nodes; clicking
@@ -340,8 +362,10 @@ are ignored, `stage_pipeline`'s default.
The viewer checks the document before showing it: one root per query, node,
edge and root references, `scalar_roots` positions, `from_logical`, the Stage 3 ids, costs and
`per_node` keys, the data workload's shape, and each materialized view's fields
-and `stage2_node_id`. Documents written before these sections are still
-shown. If a check fails, it shows the problems instead.
+and `stage2_node_id`, and, when present, `memo.enumeration`: per-step
+counts, the listed choices' ids, group → candidate maps, DAGs (one root per
+root group) and the optional pricing fields. Documents written before these
+sections are still shown. If a check fails, it shows the problems instead.
## Files
@@ -349,6 +373,10 @@ shown. If a check fails, it shows the problems instead.
- `stages.js`: document checks, the candidate list, lane elements and node
labels, pane-chain expansion, the queries reaching each node and the
highlighted neighborhoods; no DOM. `stages.test.mjs`: its Node tests.
+- `enumeration.js`: the Enumerated DAGs panel and the checks of
+ `memo.enumeration`. `enumeration.test.mjs`: its Node tests, over
+ `test-fixtures/memo-enumeration-small.json` (a hand-written priced memo
+ for Example 1).
- `node-style.js`: the operator-kind table (`KIND_CATEGORY_JSON`, checked
against the IR by `crates/devtools/tests/viewer_contract.rs`) and the
node groups.
@@ -399,7 +427,7 @@ python3 -m unittest test_viewer test_server
cytoscape (headless), from the repository root:
```bash
-node --test tools/dag-viewer/stages.test.mjs
+node --test tools/dag-viewer/stages.test.mjs tools/dag-viewer/enumeration.test.mjs
```
The JavaScript runs in V8 through `py_mini_racer` (`pip install
diff --git a/tools/dag-viewer/app.js b/tools/dag-viewer/app.js
index 076b3cf8e..1b7603050 100644
--- a/tools/dag-viewer/app.js
+++ b/tools/dag-viewer/app.js
@@ -53,10 +53,11 @@
// The query whose path the lanes highlight ('' for none).
let highlightedQuery = '';
- function render(i, dag, physical, costPerNode) {
+ // `ids` names the queries of `dag.roots` in order (default: the workload's).
+ function render(i, dag, physical, costPerNode, ids = queryIds) {
if (cys[i]) cys[i].destroy();
- drawn[i] = { dag, physical, costPerNode };
- const elements = stageLaneElements(dag, { physical, costPerNode, queryIds, expandedChains: [...expandedOf(dag)] })
+ drawn[i] = { dag, physical, costPerNode, ids };
+ const elements = stageLaneElements(dag, { physical, costPerNode, queryIds: ids, expandedChains: [...expandedOf(dag)] })
.map((el) => ({ data: el.data, classes: [el.classes, el.data.rootFor && el.data.rootFor.length ? 'root' : ''].join(' ').trim() }));
laneElements[i] = elements;
const cy = cytoscape({
@@ -72,7 +73,7 @@
dim(i, queryKeep(i));
}
- function redraw(i) { const d = drawn[i]; render(i, d.dag, d.physical, d.costPerNode); }
+ function redraw(i) { const d = drawn[i]; render(i, d.dag, d.physical, d.costPerNode, d.ids); }
// A PaneChain expands into its panes; a pane collapses its chain; any
// other node is shown and its upstream and downstream highlighted.
@@ -179,6 +180,7 @@
// Choose Stage 1 candidate `id`: show its physical plan when it has one;
// a pruned or uncomposed candidate has none, so Stage 2 is cleared.
function selectLogical(id) {
+ pressEnumeratedRow(null);
const physical = doc.stage2_physical_asap_optimization.candidates.find((p) => p.from_logical === id);
if (physical) { selectPhysical(physical.id); return; }
showLogical(id);
@@ -205,7 +207,23 @@
}
}
+ // Draw enumerated DAG `id` of `memo.enumeration` (enumeration.js) in
+ // lane 1; the document has no physical plan for it.
+ function showEnumerated(id, dag, description, perQueryDag) {
+ current = { logical: null, physical: null };
+ $('pick1').value = '';
+ $('pick2').value = '';
+ // Its roots are its root groups; drawn per query when they map to queries.
+ if (perQueryDag) render(1, perQueryDag, false, null);
+ else render(1, dag, false, null, dag.roots.map((_, k) => `root group #${k + 1}`));
+ $('lane1-meta').innerHTML = `enumerated DAG ${esc(id)} · ${esc(description)} · ${dag.nodes.length} nodes` +
+ (perQueryDag ? '' : ' · roots not matched to queries');
+ clearLane(2, 'no physical plan for an enumerated DAG');
+ renderRanking();
+ }
+
function selectPhysical(id) {
+ pressEnumeratedRow(null);
current.physical = id;
$('pick2').value = id;
const c = physicalById.get(id);
@@ -230,7 +248,7 @@
// Show one stage document; `source` names it, `story` explains it.
function showDocument(data, source, story) {
- const errors = validateStagePipeline(data);
+ const errors = validateStagePipeline(data).concat(validateMemoEnumeration(data));
if (errors.length) throw new Error(errors.slice(0, 3).join('; '));
doc = data;
current = { logical: null, physical: null };
@@ -284,6 +302,7 @@
}
renderMaterializedViews();
renderMemoSearch();
+ renderEnumeration(doc, showEnumerated);
}
const table = (head, body) => `
${head.map((h) => `
${esc(h)}
`).join('')}
${body}
`;
diff --git a/tools/dag-viewer/enumeration.js b/tools/dag-viewer/enumeration.js
new file mode 100644
index 000000000..a1ea331a5
--- /dev/null
+++ b/tools/dag-viewer/enumeration.js
@@ -0,0 +1,233 @@
+// The Enumerated DAGs panel: `memo.enumeration` of an asap-stage-pipeline/v1
+// document, the complete candidate DAGs the memo stands for, as `stage_pipeline`
+// enumerated and composed them. The document holds each listed choice's DAG,
+// so the page composes nothing: a clicked row's `dag` is drawn in the Stage 1
+// lane by app.js. The checks and the rows are DOM-free (enumeration.test.mjs);
+// renderEnumeration fills the panel. Reads validateLogicalDag and uniqueIds
+// from stages.js.
+
+// Memo steps in pipeline order, with the names the header uses.
+const MEMO_STEP_NAMES = { stage0: 'Stage 0', pass1: 'Pass 1', pass2: 'Pass 2', concrete_states: 'concrete states' };
+
+function memoStepName(step) {
+ return MEMO_STEP_NAMES[step] || step;
+}
+
+const enumerationIsObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
+const enumerationIsCount = (value) => Number.isInteger(value) && value >= 0;
+
+// A `MemoChoice`: group id (a string of digits) → candidate index.
+function isMemoChoice(choice) {
+ return enumerationIsObject(choice) && Object.entries(choice).every(([group, index]) => /^\d+$/.test(group) && enumerationIsCount(index));
+}
+
+// Every shape problem of `memo.enumeration`, as readable strings; empty when
+// the document has none (a document without `memo` has none).
+function validateMemoEnumeration(doc) {
+ const memo = doc && doc.memo;
+ if (memo === undefined) return [];
+ if (!enumerationIsObject(memo)) return ['memo must be an object'];
+ const enumeration = memo.enumeration;
+ if (enumeration === undefined) return [];
+ const at = 'memo.enumeration';
+ if (!enumerationIsObject(enumeration)) return [`${at} must be an object`];
+ const errors = [];
+ const perStep = enumeration.per_step;
+ if (!enumerationIsObject(perStep)) errors.push(`${at}.per_step must be an object`);
+ else {
+ Object.entries(perStep).forEach(([step, entry]) => {
+ if (!entry || !enumerationIsCount(entry.count) || typeof entry.complete !== 'boolean') errors.push(`${at}.per_step.${step} needs a count and complete`);
+ });
+ }
+ if (typeof enumeration.step !== 'string' || !enumerationIsObject(perStep) || !(enumeration.step in perStep)) {
+ errors.push(`${at}.step must name a step of per_step`);
+ }
+ if (!Number.isInteger(enumeration.limit) || enumeration.limit < 1) errors.push(`${at}.limit must be a positive integer`);
+ const priced = enumeration.priced;
+ if (priced !== undefined && priced !== null && !(enumerationIsObject(priced) && enumerationIsCount(priced.count) && enumerationIsCount(priced.cheaper_than_selected)
+ && (priced.selected_cost_per_second === null || Number.isFinite(priced.selected_cost_per_second)))) {
+ errors.push(`${at}.priced must be null or {count, cheaper_than_selected, selected_cost_per_second}`);
+ }
+ if (!Array.isArray(enumeration.choices)) return errors.concat(`${at}.choices must be an array`);
+ uniqueIds(enumeration.choices, `${at}.choices`, errors);
+ const counted = enumerationIsObject(perStep) && perStep[enumeration.step];
+ if (counted && enumerationIsCount(counted.count) && enumeration.choices.length > counted.count) {
+ errors.push(`${at}: ${enumeration.choices.length} choices listed but per_step.${enumeration.step} counts ${counted.count}`);
+ }
+ enumeration.choices.forEach((entry, index) => {
+ if (!enumerationIsObject(entry)) return;
+ const where = `${at}.choices[${index}]`;
+ if (!isMemoChoice(entry.choice)) errors.push(`${where}.choice must map group ids to candidate indices`);
+ // A choice that does not compose has no DAG but its error.
+ if (entry.dag === null) {
+ if (typeof entry.error !== 'string' || !entry.error) errors.push(`${where}: needs a dag or an error`);
+ } else {
+ // One root per root group, which need not be one per query.
+ const roots = entry.dag && Array.isArray(entry.dag.roots) ? entry.dag.roots.length : 0;
+ errors.push(...validateLogicalDag(entry.dag, where, roots));
+ }
+ ['budget_share_1', 'selected'].forEach((field) => {
+ if (typeof entry[field] !== 'boolean') errors.push(`${where}.${field} must be true or false`);
+ });
+ // Present only when the run priced the enumerated DAGs.
+ ['valid', 'cheaper_than_selected'].forEach((field) => {
+ if (entry[field] !== undefined && typeof entry[field] !== 'boolean') errors.push(`${where}.${field} must be true or false`);
+ });
+ if (entry.rejection !== undefined && entry.rejection !== null && typeof entry.rejection !== 'string') errors.push(`${where}.rejection must be a string or null`);
+ if (entry.cost_per_second !== undefined && entry.cost_per_second !== null && !Number.isFinite(entry.cost_per_second)) {
+ errors.push(`${where}.cost_per_second must be a number or null`);
+ }
+ });
+ return errors;
+}
+
+// "49", or "≥ 1000" when the count stopped at the limit.
+function enumerationCountText(entry, limit) {
+ return entry.complete ? String(entry.count) : `≥ ${limit}`;
+}
+
+// The panel's content, or null for a document without `memo.enumeration`:
+// `counts` ("Stage 0: 1 · Pass 1: 49 · Pass 2: ≥ 1000"), `listing` (what the
+// rows are), `priced` (the pricing summary, "" when not priced), and one row
+// per listed choice. A row's `changes` are the groups whose candidate differs
+// from `selected_choice` (every group of the choice when there is none), each
+// with the candidate's origin and label when the enumerated step's memo
+// lists that candidate. Both choices are sparse: a group a choice does not
+// name takes candidate 0. `selected_choice` is over the last memo step; when
+// the enumerated step is an earlier one, only the row's own groups are
+// compared and `against` says the comparison crosses steps.
+function enumerationView(doc) {
+ const memo = doc && doc.memo;
+ const enumeration = memo && memo.enumeration;
+ if (!enumeration) return null;
+ const known = Object.keys(MEMO_STEP_NAMES);
+ const steps = Object.keys(enumeration.per_step)
+ .sort((a, b) => (known.indexOf(a) + 1 || known.length + 1) - (known.indexOf(b) + 1 || known.length + 1));
+ const counts = steps.map((step) => `${memoStepName(step)}: ${enumerationCountText(enumeration.per_step[step], enumeration.limit)}`).join(' · ');
+ const total = enumeration.per_step[enumeration.step];
+ const name = memoStepName(enumeration.step);
+ const shown = enumeration.choices.length;
+ const listing = total.complete && shown === total.count
+ ? `listed: all ${shown} ${name} DAGs`
+ : `listed: the first ${shown} of ${enumerationCountText(total, enumeration.limit)} ${name} DAGs`;
+ const priced = enumeration.priced
+ ? `${enumeration.priced.count} priced · ${enumeration.priced.cheaper_than_selected} cheaper than the selected plan` +
+ (enumeration.priced.selected_cost_per_second === null ? '' : ` (${Number(enumeration.priced.selected_cost_per_second.toPrecision(4))})`)
+ : '';
+
+ const selected = enumerationIsObject(memo.selected_choice) ? memo.selected_choice : null;
+ const step = (Array.isArray(memo.steps) ? memo.steps : []).find((s) => s && s.step === enumeration.step);
+ const candidateOf = (group, index) => {
+ const g = step && Array.isArray(step.groups) ? step.groups.find((x) => x && String(x.id) === group) : null;
+ return g && Array.isArray(g.candidates) ? g.candidates.find((c) => c && c.index === index) : null;
+ };
+ const memoSteps = Array.isArray(memo.steps) ? memo.steps.filter((s) => s && typeof s.step === 'string') : [];
+ const lastStep = memoSteps.length ? memoSteps[memoSteps.length - 1].step : steps[steps.length - 1];
+ const sameStep = enumeration.step === lastStep;
+ const rows = enumeration.choices.map((entry) => {
+ const groups = new Set(Object.keys(entry.choice));
+ if (selected && sameStep) Object.keys(selected).forEach((group) => groups.add(group));
+ const changes = [...groups]
+ .filter((group) => !selected || (entry.choice[group] ?? 0) !== (selected[group] ?? 0))
+ .sort((a, b) => Number(a) - Number(b))
+ .map((group) => {
+ // A group of the selected choice this DAG does not read.
+ if (!(group in entry.choice)) return { group: Number(group), index: null, origin: null, label: null };
+ const index = entry.choice[group];
+ const candidate = candidateOf(group, index);
+ return { group: Number(group), index, origin: candidate ? candidate.origin : null, label: candidate ? candidate.label : null };
+ });
+ return {
+ id: entry.id,
+ changes,
+ text: changes.length
+ ? changes.map((c) => (c.index === null ? `G${c.group} not read`
+ : `G${c.group} → #${c.index}${c.label ? ` ${c.label}` : ''}${c.origin ? ` (${c.origin})` : ''}`)).join(' · ')
+ : 'the selected choice',
+ nodes: entry.dag ? entry.dag.nodes.length : null,
+ error: entry.dag ? null : entry.error,
+ budgetShare1: entry.budget_share_1,
+ selected: entry.selected,
+ priced: 'valid' in entry,
+ valid: entry.valid,
+ rejection: entry.rejection || null,
+ cost: typeof entry.cost_per_second === 'number' ? entry.cost_per_second : null,
+ cheaper: entry.cheaper_than_selected === true,
+ };
+ });
+ const against = !selected
+ ? `every group's candidate (no selected choice${memo.selected_choice_unavailable ? `: ${memo.selected_choice_unavailable}` : ''})`
+ : sameStep ? 'groups whose candidate differs from the selected plan’s choice'
+ : `groups whose candidate differs from the selected plan’s choice, which is over the ${memoStepName(lastStep)} memo: its group ids and candidate indices may not match ${name}'s, and “selected” is not meaningful`;
+ // `compose` writes one root per root group, in increasing group id: root k
+ // is the k-th group with `roots_of`, the query positions it answers. Null
+ // when the enumerated step's memo is not in the document.
+ const rootQueries = step && Array.isArray(step.groups)
+ ? step.groups.filter((g) => g && Array.isArray(g.roots_of) && g.roots_of.length).sort((a, b) => a.id - b.id).map((g) => g.roots_of) : null;
+ return { counts, listing, priced, against, rows: sameStep ? rows : rows.map((r) => ({ ...r, selected: false })), rootQueries };
+}
+
+// `dag` with one root per workload query (query q's root is the root of the
+// group whose `roots_of` holds q), the shape the lanes draw; null when
+// `rootQueries` does not cover every query with one root each.
+function enumeratedDagPerQuery(dag, rootQueries, queryCount) {
+ if (!rootQueries || rootQueries.length !== dag.roots.length) return null;
+ const roots = new Array(queryCount).fill(null);
+ rootQueries.forEach((queries, k) => queries.forEach((q) => { if (q >= 0 && q < queryCount) roots[q] = dag.roots[k]; }));
+ return roots.every(Boolean) ? { ...dag, roots } : null;
+}
+
+// The panel's state: the document's view, the row drawn in the Stage 1
+// lane, and app.js's function that draws an enumerated DAG there.
+const enumerationPanel = { doc: null, view: null, pressed: null, draw: null, bound: false };
+
+function enumerationRowHtml(row, pressed) {
+ const esc = (s) => String(s).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
+ const chips = [
+ row.selected ? '✓ selected' : '',
+ row.cheaper ? 'cheaper than selected' : '',
+ row.priced && row.valid === false ? '✗ invalid' : '',
+ row.priced && row.valid === true && !row.selected && !row.cheaper ? 'valid' : '',
+ row.budgetShare1 ? '' : 'budget share < 1',
+ ].join('');
+ const cost = row.cost === null ? (row.priced ? '—' : '') : String(Number(row.cost.toPrecision(4)));
+ return ``;
+}
+
+// Mark row `id` (null: none) as the one the Stage 1 lane draws.
+function pressEnumeratedRow(id) {
+ const state = enumerationPanel;
+ state.pressed = id;
+ if (state.view) document.getElementById('enumRows').innerHTML = state.view.rows.map((row) => enumerationRowHtml(row, id)).join('');
+}
+
+// Fill the panel for `doc` (hidden without `memo.enumeration`); a click on a
+// row calls `draw(id, dag, description, perQueryDag)` (perQueryDag: `dag`
+// with one root per query, or null when the roots cannot be matched to
+// queries) and marks the row.
+function renderEnumeration(doc, draw) {
+ const $ = (id) => document.getElementById(id);
+ const state = enumerationPanel;
+ state.doc = doc;
+ state.view = enumerationView(doc);
+ state.draw = draw;
+ $('enumPanel').hidden = !state.view;
+ if (!state.view) { state.pressed = null; $('enumRows').innerHTML = ''; return; }
+ $('enum-meta').textContent = [state.view.counts, state.view.listing, state.view.priced, `each row: ${state.view.against}`].filter(Boolean).join(' · ');
+ pressEnumeratedRow(null);
+ if (state.bound) return;
+ state.bound = true;
+ // One listener for every document: rows are rewritten on each load.
+ $('enumRows').addEventListener('click', (event) => {
+ const button = event.target && event.target.closest ? event.target.closest('button[data-id]') : null;
+ if (!button || !state.view) return;
+ const choice = state.doc.memo.enumeration.choices.find((c) => c.id === button.dataset.id);
+ if (!choice.dag) return;
+ const row = state.view.rows.find((r) => r.id === button.dataset.id);
+ state.draw(choice.id, choice.dag, row.text,
+ enumeratedDagPerQuery(choice.dag, state.view.rootQueries, state.doc.workload.queries.length));
+ pressEnumeratedRow(choice.id);
+ });
+}
diff --git a/tools/dag-viewer/enumeration.test.mjs b/tools/dag-viewer/enumeration.test.mjs
new file mode 100644
index 000000000..7cf19f73b
--- /dev/null
+++ b/tools/dag-viewer/enumeration.test.mjs
@@ -0,0 +1,155 @@
+// Node tests of enumeration.js (no DOM): the checks of `memo.enumeration` and
+// the Enumerated DAGs panel's rows, over a hand-written priced memo on #509
+// Example 1 (test-fixtures/memo-enumeration-small.json). Run from the
+// repository root: `node --test tools/dag-viewer/enumeration.test.mjs`.
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+import vm from 'node:vm';
+
+const here = new URL('.', import.meta.url);
+const context = vm.createContext({ console: { warn() {} } });
+for (const file of ['node-style.js', 'stages.js', 'enumeration.js']) {
+ vm.runInContext(readFileSync(new URL(file, here), 'utf8'), context, { filename: file });
+}
+const call = (name, ...args) => JSON.parse(JSON.stringify(context[name](...args)));
+const read = (path) => JSON.parse(readFileSync(new URL(path, here), 'utf8'));
+const example1 = read('examples/planner-layering-example1.json');
+const priced = () => ({ ...structuredClone(example1), ...read('test-fixtures/memo-enumeration-small.json') });
+// The same memo as a run without --price-enumerated writes it.
+const unpriced = () => {
+ const doc = priced();
+ doc.memo.enumeration.priced = null;
+ doc.memo.enumeration.choices.forEach((c) => { delete c.valid; delete c.rejection; delete c.cost_per_second; delete c.cheaper_than_selected; });
+ return doc;
+};
+
+test('documents without memo, or memo without enumeration, have no enumeration problems', () => {
+ assert.deepEqual(call('validateMemoEnumeration', example1), []);
+ assert.deepEqual(call('validateMemoEnumeration', { ...example1, memo: { steps: [] } }), []);
+ assert.equal(call('enumerationView', example1), null);
+});
+
+test('the priced and unpriced fixtures are valid', () => {
+ assert.deepEqual(call('validateMemoEnumeration', priced()), []);
+ assert.deepEqual(call('validateMemoEnumeration', unpriced()), []);
+});
+
+test('each broken field of memo.enumeration is reported', () => {
+ const cases = {
+ 'memo must be an object': (d) => { d.memo = []; },
+ 'per_step.pass1 needs a count and complete': (d) => { d.memo.enumeration.per_step.pass1.complete = 'yes'; },
+ 'step must name a step of per_step': (d) => { d.memo.enumeration.step = 'pass9'; },
+ 'limit must be a positive integer': (d) => { d.memo.enumeration.limit = 0; },
+ 'choices must be an array': (d) => { d.memo.enumeration.choices = {}; },
+ 'duplicate id E1': (d) => { d.memo.enumeration.choices[1].id = 'E1'; },
+ '5 choices listed but per_step.pass1 counts 4': (d) => { d.memo.enumeration.choices.push({ ...d.memo.enumeration.choices[0], id: 'E5' }); },
+ 'choices[0].choice must map group ids to candidate indices': (d) => { d.memo.enumeration.choices[0].choice = { G7: 0 }; },
+ 'choices[0]: node 1 reads missing node 42': (d) => { Object.values(d.memo.enumeration.choices[0].dag.nodes[1].operator)[0].TimeRange.child = 42; },
+ 'choices[0]: dag needs nodes and roots': (d) => { delete d.memo.enumeration.choices[0].dag; },
+ 'choices[0].budget_share_1 must be true or false': (d) => { delete d.memo.enumeration.choices[0].budget_share_1; },
+ 'choices[0].cheaper_than_selected must be true or false': (d) => { d.memo.enumeration.choices[0].cheaper_than_selected = 1; },
+ 'choices[0].cost_per_second must be a number or null': (d) => { d.memo.enumeration.choices[0].cost_per_second = 'cheap'; },
+ 'choices[0].rejection must be a string or null': (d) => { d.memo.enumeration.choices[0].rejection = 3; },
+ 'priced must be null or': (d) => { d.memo.enumeration.priced = { count: 4 }; },
+ };
+ for (const [message, breakIt] of Object.entries(cases)) {
+ const doc = priced();
+ breakIt(doc);
+ const errors = call('validateMemoEnumeration', doc);
+ assert.ok(errors.some((e) => e.includes(message)), `${message}: got ${JSON.stringify(errors)}`);
+ }
+});
+
+test('the header counts every step, with ≥ and the limit when the count stopped', () => {
+ const view = call('enumerationView', unpriced());
+ assert.equal(view.counts, 'Stage 0: 1 · Pass 1: 4');
+ assert.equal(view.listing, 'listed: all 4 Pass 1 DAGs');
+ assert.equal(view.priced, '');
+ const capped = unpriced();
+ capped.memo.enumeration.per_step.pass1 = { count: 1000, complete: false };
+ capped.memo.enumeration.per_step.pass2 = { count: 1000, complete: false };
+ const cappedView = call('enumerationView', capped);
+ assert.equal(cappedView.counts, 'Stage 0: 1 · Pass 1: ≥ 1000 · Pass 2: ≥ 1000');
+ assert.equal(cappedView.listing, 'listed: the first 4 of ≥ 1000 Pass 1 DAGs');
+});
+
+test('choices are sparse: a group either choice leaves out takes candidate 0', () => {
+ const doc = unpriced();
+ doc.memo.selected_choice = { 7: 1 };
+ const choices = doc.memo.enumeration.choices;
+ choices[0].choice = { 3: 0, 7: 0 };
+ delete choices[1].choice[2];
+ choices[2].choice = { 7: 2, 2: 0 };
+ const rows = call('enumerationView', doc).rows;
+ assert.equal(rows[0].text, 'G7 → #0 exact accumulator (pass1)');
+ assert.equal(rows[1].text, 'the selected choice');
+ assert.equal(rows[2].text, 'G7 → #2 CountSketch+heap (pass1)');
+});
+
+test('a group of the selected choice that a DAG does not read is named', () => {
+ const doc = unpriced();
+ doc.memo.selected_choice = { 7: 1, 9: 2 };
+ assert.equal(call('enumerationView', doc).rows[1].text, 'G9 not read');
+});
+
+test('a selected choice over a later step than the enumerated one is flagged', () => {
+ const doc = unpriced();
+ doc.memo.steps.push({ step: 'pass2', title: 'Pass 2', groups: [] });
+ doc.memo.enumeration.per_step.pass2 = { count: 1000, complete: false };
+ doc.memo.selected_choice = { 7: 1, 9: 2 };
+ const view = call('enumerationView', doc);
+ assert.match(view.against, /over the Pass 2 memo/);
+ assert.ok(view.rows.every((r) => !r.selected));
+ // Only the row's own groups are compared across steps.
+ assert.equal(view.rows[1].text, 'the selected choice');
+});
+
+test('a row names the groups whose candidate differs from the selected choice, with origin and label', () => {
+ const rows = call('enumerationView', unpriced()).rows;
+ assert.deepEqual(rows.map((r) => r.id), ['E1', 'E2', 'E3', 'E4']);
+ assert.equal(rows[0].text, 'G7 → #0 exact accumulator (pass1)');
+ assert.equal(rows[1].text, 'the selected choice');
+ assert.equal(rows[1].selected, true);
+ assert.equal(rows[3].text, 'G7 → #3 CMS+heap shared build (shared_build)');
+ assert.equal(rows[3].budgetShare1, false);
+ assert.ok(rows.every((r) => !r.priced && r.cost === null && !r.cheaper));
+});
+
+test('a choice that does not compose has its error instead of a DAG and is not clickable', () => {
+ const doc = unpriced();
+ doc.memo.enumeration.choices[3].dag = null;
+ assert.ok(call('validateMemoEnumeration', doc).some((e) => e.includes('choices[3]: needs a dag or an error')));
+ doc.memo.enumeration.choices[3].error = 'cycle';
+ assert.deepEqual(call('validateMemoEnumeration', doc), []);
+ const row = call('enumerationView', doc).rows[3];
+ assert.equal(row.error, 'cycle');
+ assert.match(context.enumerationRowHtml(row, null), /disabled>.*does not compose: cycle/);
+});
+
+test('without the step in memo.steps a row names only the candidate index', () => {
+ const doc = unpriced();
+ doc.memo.steps = [];
+ assert.equal(call('enumerationView', doc).rows[2].text, 'G7 → #2');
+});
+
+test('without a selected choice a row names every group of its choice', () => {
+ const doc = unpriced();
+ doc.memo.selected_choice = null;
+ doc.memo.selected_choice_unavailable = 'no plan selected';
+ const view = call('enumerationView', doc);
+ assert.equal(view.rows[0].changes.length, 8);
+ assert.match(view.against, /no plan selected/);
+});
+
+test('a priced row carries its cost, validity and whether it is cheaper than the selected plan', () => {
+ const view = call('enumerationView', priced());
+ assert.equal(view.priced, '4 priced · 1 cheaper than the selected plan (2)');
+ const byId = Object.fromEntries(view.rows.map((r) => [r.id, r]));
+ assert.deepEqual([byId.E3.cost, byId.E3.valid, byId.E3.cheaper], [1.5, true, true]);
+ assert.deepEqual([byId.E4.cost, byId.E4.valid, byId.E4.rejection], [null, false, 'accuracy_target_missed']);
+ const html = context.enumerationRowHtml(view.rows[2], null);
+ assert.match(html, /class="cheaper"/);
+ assert.match(html, /cheaper than selected/);
+ assert.doesNotMatch(context.enumerationRowHtml(view.rows[0], null), /cheaper/);
+});
diff --git a/tools/dag-viewer/index.html b/tools/dag-viewer/index.html
index 632630368..886f94b4c 100644
--- a/tools/dag-viewer/index.html
+++ b/tools/dag-viewer/index.html
@@ -83,6 +83,10 @@
.chip.selected { color: var(--ok); background: var(--ok-soft); }
.chip.invalid { color: var(--bad); background: var(--bad-soft); }
.chip.costlier { color: var(--warn); background: var(--warn-soft); }
+/* Enumerated DAGs: a row cheaper than the selected plan is red. */
+#enumRows { max-height: 360px; }
+.rank button.cheaper { border-color: var(--bad); background: var(--bad-soft); }
+.chip.cheaper { color: var(--bad); border: 1px solid var(--bad); }
/* Stage 0, 1 and 2 stack top to bottom, each as wide as the page allows. */
.lanes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; min-width: 0; }
.lane .panel-head { align-items: center; }
@@ -217,6 +221,11 @@
ASAPPlanner Stage Viewer
+
+
Memo · complete candidate DAGs
Enumerated DAGs
click a row to draw it in Stage 1
+
+
+
Stage 1
Logical ASAP candidate
@@ -264,6 +273,7 @@
ASAPPlanner Stage Viewer
+
diff --git a/tools/dag-viewer/test-fixtures/memo-enumeration-small.json b/tools/dag-viewer/test-fixtures/memo-enumeration-small.json
new file mode 100644
index 000000000..9e29756f4
--- /dev/null
+++ b/tools/dag-viewer/test-fixtures/memo-enumeration-small.json
@@ -0,0 +1 @@
+{"memo":{"steps":[{"step":"stage0","title":"Stage 0","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[]}]},{"step":"pass1","title":"Stage 1, Pass 1","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[0],"children":[],"origin":"pass1","budget_share":1,"added":true,"label":"Scan http_requests_total","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"group_of_node":{}}]},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[1],"children":[0],"origin":"pass1","budget_share":1,"added":true,"label":"TimeRange 1m","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"group_of_node":{"0":0}}]},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[2],"children":[1],"origin":"pass1","budget_share":1,"added":true,"label":"rate per series","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"group_of_node":{"1":1}}]},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[3],"children":[2],"origin":"pass1","budget_share":1,"added":true,"label":"sum by (job)","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"group_of_node":{"2":2}}]},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[4],"children":[],"origin":"pass1","budget_share":1,"added":true,"label":"Scan http_requests_total","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":0}]},"group_of_node":{}}]},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[5],"children":[4],"origin":"pass1","budget_share":1,"added":true,"label":"TimeRange 1m","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":1}]},"group_of_node":{"0":4}}]},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[6],"children":[5],"origin":"pass1","budget_share":1,"added":true,"label":"sum_over_time per series","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"roots":[{"Operator":2}]},"group_of_node":{"1":5}}]},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"candidate_count":4,"candidate_count_by_origin":{"pass1":3,"shared_build":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[7],"children":[6],"origin":"pass1","budget_share":1,"added":true,"label":"exact accumulator","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"group_of_node":{"2":6}},{"index":1,"implements":[7],"children":[6],"origin":"pass1","budget_share":1,"added":true,"label":"CMS+heap","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"group_of_node":{"2":6}},{"index":2,"implements":[7],"children":[6],"origin":"pass1","budget_share":1,"added":true,"label":"CountSketch+heap","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"group_of_node":{"2":6}},{"index":3,"implements":[7],"children":[6],"origin":"shared_build","budget_share":0.5,"added":true,"label":"CMS+heap shared build","dag":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":3}]},"group_of_node":{"2":6}}]}]}],"selected_choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"enumeration":{"step":"pass1","per_step":{"stage0":{"count":1,"complete":true},"pass1":{"count":4,"complete":true}},"limit":1000,"choices":[{"id":"E1","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0},"dag":{"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":9,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null}],"roots":[{"Operator":5},{"Operator":10}]},"budget_share_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":3.0,"cheaper_than_selected":false},{"id":"E2","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"dag":{"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":9,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null}],"roots":[{"Operator":5},{"Operator":10}]},"budget_share_1":true,"selected":true,"valid":true,"rejection":null,"cost_per_second":2.0,"cheaper_than_selected":false},{"id":"E3","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":2},"dag":{"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":9,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null}],"roots":[{"Operator":5},{"Operator":10}]},"budget_share_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":1.5,"cheaper_than_selected":true},{"id":"E4","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":3},"dag":{"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":6}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":7,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null}],"roots":[{"Operator":5},{"Operator":8}]},"budget_share_1":false,"selected":false,"valid":false,"rejection":"accuracy_target_missed","cost_per_second":null,"cheaper_than_selected":false}],"priced":{"count":4,"cheaper_than_selected":1,"selected_cost_per_second":2.0}}}}
diff --git a/tools/dag-viewer/test_viewer.py b/tools/dag-viewer/test_viewer.py
index 5ef731d63..7cc2be847 100644
--- a/tools/dag-viewer/test_viewer.py
+++ b/tools/dag-viewer/test_viewer.py
@@ -28,6 +28,12 @@
# workload-01 (nine repeating PromQL queries), planned with the default
# search as the MVP deployment; its selected plan keeps panes at ingestion.
SEED862 = HERE / "examples" / "random-mixed-seed-862-workload-01.json"
+# A hand-written priced `memo` section for Example 1: four enumerated
+# Pass 1 DAGs, E2 selected, E3 cheaper than it, E4 invalid.
+MEMO_ENUMERATION = HERE / "test-fixtures" / "memo-enumeration-small.json"
+# stage_pipeline's memo example (#1003): the ratio of quantiles, with its
+# Pass 1 memo enumerated (49 = 7 × 7 candidate DAGs).
+MEMO_RATIO = HERE / "examples" / "memo-ratio-of-quantiles.json"
WORKLOADS = HERE / "workloads"
# Standalone scalar queries at positions 0, 2 and 4 (first, middle, last):
# scalar(sum(m)), sum(n), time(), sum by (job) (k), 1 + 2.
@@ -762,7 +768,7 @@ def test_scripts_exist(self):
def test_every_element_the_scripts_use_is_on_the_page(self):
page = (HERE / "index.html").read_text()
ids = set(re.findall(r'id="([^"]+)"', page))
- for script in ("app.js", "editor.js"):
+ for script in ("app.js", "editor.js", "enumeration.js"):
used = set(re.findall(r"\$\('([^']+)'\)", (HERE / script).read_text()))
with self.subTest(script):
self.assertLessEqual(used, ids)
@@ -884,7 +890,7 @@ class AppTests(unittest.TestCase):
def page(self, search="", files=None, hash_=""):
js = py_mini_racer.MiniRacer()
js.eval(STUB_DOM)
- for name in ("node-style.js", "stages.js"):
+ for name in ("node-style.js", "stages.js", "enumeration.js"):
js.eval((HERE / name).read_text())
for url, text in (files or {}).items():
js.eval(f"__files[{json.dumps(url)}] = {json.dumps(text)};")
@@ -1059,6 +1065,105 @@ def test_tapping_a_node_highlights_its_neighborhood_and_lists_its_queries(self):
js.eval("__taps['cy2 background']({ target: { isNode: false } })")
self.assertEqual(js.eval("__dimmed.cy2.length"), 0)
+ def test_a_document_without_memo_hides_the_enumerated_dags(self):
+ js = self.page("?doc=e1.json", {"e1.json": EXAMPLE1.read_text()})
+ self.assertTrue(js.eval("__els.enumPanel.hidden"))
+ self.assertEqual(js.eval("__els.enumRows.innerHTML"), "")
+
+ def test_clicking_an_enumerated_dag_draws_it_in_the_stage1_lane(self):
+ """The panel lists the enumerated choices; a click draws the
+ choice's composed DAG in lane 1 and clears lane 2."""
+ doc = {**example1(), **json.loads(MEMO_ENUMERATION.read_text())}
+ js = self.page("?doc=d.json", {"d.json": json.dumps(doc)})
+ self.assertFalse(js.eval("__els.enumPanel.hidden"))
+ meta = js.eval("__els['enum-meta'].textContent")
+ self.assertIn("Pass 1: 4", meta)
+ self.assertIn("1 cheaper than the selected plan", meta)
+ rows = js.eval("__els.enumRows.innerHTML")
+ self.assertEqual(rows.count("
"), 4)
+ self.assertIn('data-id="E3" aria-pressed="false" class="cheaper"', rows)
+ e3 = doc["memo"]["enumeration"]["choices"][2]
+ js.eval("__els.enumRows.__on.click({ target: { closest() { return { dataset: { id: 'E3' } }; } } })")
+ drawn = [e for e in self.ev(js, "__rendered.cy1") if "source" not in e["data"]]
+ self.assertEqual(len(drawn), len(e3["dag"]["nodes"]))
+ self.assertIn("enumerated DAG E3", self.text(js, "lane1-meta"))
+ self.assertIn("no physical plan for an enumerated DAG", js.eval("__els['lane2-meta'].textContent"))
+ self.assertIn('data-id="E3" aria-pressed="true"', js.eval("__els.enumRows.innerHTML"))
+ # Choosing a Stage 1 candidate again releases the row.
+ js.eval("__els.pick1.__on.change({ target: { value: 'L2' } })")
+ self.assertNotIn('aria-pressed="true"', js.eval("__els.enumRows.innerHTML"))
+
+ def enumerated_roots(self, doc, choice_id):
+ js = self.page("?doc=d.json", {"d.json": json.dumps(doc)})
+ js.eval(f"__els.enumRows.__on.click({{ target: {{ closest() {{ return {{ dataset: {{ id: {json.dumps(choice_id)} }} }}; }} }} }})")
+ roots = {e["data"]["nodeId"]: e["data"]["rootFor"] for e in self.ev(js, "__rendered.cy1") if e["data"].get("rootFor")}
+ return roots, self.text(js, "lane1-meta")
+
+ def test_enumerated_roots_are_named_by_their_root_groups_queries(self):
+ """Roots come in increasing root-group id, not query order: with G3
+ the root of q2 and G7 the root of q1, the first root is q2's."""
+ doc = {**example1(), **json.loads(MEMO_ENUMERATION.read_text())}
+ groups = {g["id"]: g for g in doc["memo"]["steps"][1]["groups"]}
+ groups[3]["roots_of"], groups[7]["roots_of"] = [1], [0]
+ dag = doc["memo"]["enumeration"]["choices"][0]["dag"]
+ first, second = (r["Operator"] for r in dag["roots"])
+ roots, _ = self.enumerated_roots(doc, "E1")
+ self.assertEqual(roots, {first: ["q2"], second: ["q1"]})
+
+ def test_a_root_group_shared_by_two_queries_is_both_queries_root(self):
+ """One root group answering q1 and q2: its root is the root of both,
+ and highlighting q2 keeps it bright."""
+ doc = {**example1(), **json.loads(MEMO_ENUMERATION.read_text())}
+ groups = {g["id"]: g for g in doc["memo"]["steps"][1]["groups"]}
+ groups[3]["roots_of"], groups[7]["roots_of"] = [0, 1], []
+ choice = doc["memo"]["enumeration"]["choices"][0]
+ choice["dag"]["roots"] = choice["dag"]["roots"][:1]
+ root = choice["dag"]["roots"][0]["Operator"]
+ js = self.page("?doc=d.json", {"d.json": json.dumps(doc)})
+ js.eval("__els.enumRows.__on.click({ target: { closest() { return { dataset: { id: 'E1' } }; } } })")
+ roots = {e["data"]["nodeId"]: e["data"]["rootFor"] for e in self.ev(js, "__rendered.cy1") if e["data"].get("rootFor")}
+ self.assertEqual(roots, {root: ["q1", "q2"]})
+ js.eval("__els.queryPick.__on.change({ target: { value: 'q2' } })")
+ self.assertNotIn(f"n{root}", self.ev(js, "__dimmed.cy1"))
+ self.assertNotIn("not matched", self.text(js, "lane1-meta"))
+
+ def test_enumerated_roots_without_the_steps_memo_name_no_query(self):
+ doc = {**example1(), **json.loads(MEMO_ENUMERATION.read_text())}
+ doc["memo"]["steps"] = doc["memo"]["steps"][:1]
+ roots, meta = self.enumerated_roots(doc, "E1")
+ self.assertEqual(sorted(roots.values()), [["root group #1"], ["root group #2"]])
+ self.assertIn("roots not matched to queries", meta)
+
+ def test_the_ratio_of_quantiles_example_lists_its_pass1_dags_and_draws_one(self):
+ """On stage_pipeline's own example the panel counts 49 Pass 1 DAGs,
+ lists them all, and a click redraws the Stage 1 lane with that DAG
+ and clears Stage 2."""
+ doc = json.loads(MEMO_RATIO.read_text())
+ js = self.page("?doc=m.json", {"m.json": json.dumps(doc)})
+ self.assertFalse(js.eval("__els.enumPanel.hidden"))
+ meta = js.eval("__els['enum-meta'].textContent")
+ self.assertIn("Pass 1: 49", meta)
+ self.assertIn("listed: all 49 Pass 1 DAGs", meta)
+ # The selected choice is over the last step (concrete states), not Pass 1.
+ self.assertIn("over the concrete states memo", meta)
+ self.assertNotIn("✓ selected", js.eval("__els.enumRows.innerHTML"))
+ self.assertEqual(js.eval("__els.enumRows.innerHTML").count("
"), 49)
+ before = self.ev(js, "__rendered.cy1")
+ choice = doc["memo"]["enumeration"]["choices"][1]
+ js.eval(f"__els.enumRows.__on.click({{ target: {{ closest() {{ return {{ dataset: {{ id: {json.dumps(choice['id'])} }} }}; }} }} }})")
+ after = self.ev(js, "__rendered.cy1")
+ self.assertNotEqual(after, before)
+ self.assertEqual(len([e for e in after if "source" not in e["data"]]), len(choice["dag"]["nodes"]))
+ self.assertEqual([e["data"]["rootFor"] for e in after if e["data"].get("rootFor")], [[doc["workload"]["queries"][0]["id"]]])
+ self.assertIn(f"enumerated DAG {choice['id']}", self.text(js, "lane1-meta"))
+ self.assertIn("no physical plan for an enumerated DAG", js.eval("__els['lane2-meta'].textContent"))
+
+ def test_a_broken_enumeration_refuses_the_document(self):
+ doc = {**example1(), **json.loads(MEMO_ENUMERATION.read_text())}
+ doc["memo"]["enumeration"]["limit"] = 0
+ js = self.page("?doc=d.json", {"d.json": json.dumps(doc)})
+ self.assertIn("limit must be a positive integer", js.eval("__els.queries.innerHTML"))
+
def test_an_invalid_document_shows_an_error(self):
js = self.page("?doc=bad.json", {"bad.json": json.dumps({"format": "nope"})})
self.assertIn("Could not load", js.eval("__els.queries.innerHTML"))