Skip to content

Add Vector Sizing Calculator#2736

Open
john-wagster wants to merge 4 commits intomainfrom
feat/vector-sizing-calculator
Open

Add Vector Sizing Calculator#2736
john-wagster wants to merge 4 commits intomainfrom
feat/vector-sizing-calculator

Conversation

@john-wagster
Copy link
Copy Markdown

Add the React + EUI web component, directive examples, and integration docs under tools/vector_sizing_calculator to stage migration into docs-builder.

Gil-ad Gal and others added 2 commits February 18, 2026 17:45
Add the React + EUI web component, directive examples, and integration docs under tools/vector_sizing_calculator to stage migration into docs-builder.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move the vector sizing calculator React/EUI implementation into Elastic.Documentation.Site web-components and register it from the main asset entrypoint.

Co-authored-by: Cursor <cursoragent@cursor.com>
@john-wagster john-wagster requested a review from a team as a code owner February 18, 2026 16:10
@cla-checker-service
Copy link
Copy Markdown

cla-checker-service bot commented Feb 18, 2026

💚 CLA has been signed

).join('');

// Disk bar chart
const maxDisk = Math.max(...diskItems.map(i => i.value), 1);
Copy link
Copy Markdown
Member

@reakaleek reakaleek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What files are in tools folder? Are they still needed?

Also the *.cs files should probably be in https://github.com/elastic/docs-builder/tree/main/src/Elastic.Markdown/Myst/Directives

…rkdown

Move directive implementation from tools/ staging into Myst/Directives/VectorSizing.

- Register block in DirectiveBlockParser and render via Razor slice in DirectiveHtmlRenderer
- Add VectorSizingBlockTests
- Update tools/vector_sizing_calculator docs to point at in-repo source of truth; remove duplicate C# snippets from docs-builder-directive/

Made-with: Cursor
Add syntax doc with live directive block and TOC entry so docs-builder serve exposes a stable URL for design review (e.g. /syntax/vector-sizing-calculator). Link from directives index.

Made-with: Cursor
@itsalexcm itsalexcm requested a review from a team as a code owner April 13, 2026 12:04
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a vector sizing calculator feature that estimates disk and off-heap memory requirements for Elasticsearch dense_vector fields. It includes a new {vector-sizing-calculator} Myst directive and supporting infrastructure: a C# backend directive parser and renderer, a React-based web component with sizing computation logic and UI components (configuration panel, results display, breakdown charts, formula viewer), standalone HTML reference implementations in the tools directory, comprehensive documentation, and unit tests. The web component is dynamically loaded by the docs site and renders an interactive calculator with support for various vector configurations (element types, index structures, quantization, replicas, and tuning parameters).

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vector-sizing-calculator
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/vector-sizing-calculator
  • 🛠️ Update Documentation: Commit on current branch
  • 🛠️ Update Documentation: Create PR

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/calculations.ts`:
- Around line 66-113: The validate function currently omits checks for replicas,
hnswM, and vectorsPerCluster which leads to invalid math downstream; update
validate(inputs: CalculatorInputs) to also validate replicas (ensure replicas >=
0), hnswM (when indexType === 'hnsw' ensure hnswM >= 2), and vectorsPerCluster
(when indexType === 'disk_bbq' ensure vectorsPerCluster >= 1), and return {
valid: false } with a clear warning message (and optional warningLink) for each
violated constraint so calculate() never receives zero/negative/undefined
values; apply the same additions to the mirrored
tools/vector_sizing_calculator/web-component/src/calculations.ts validate
implementation.

In `@tools/vector_sizing_calculator/embed.html`:
- Around line 428-439: The early-return paths do not clear the same UI state as
the initial validation block, so stale results remain when D>4096 (and other
invalid inputs) trigger a return; update the D>4096 branch (and any other
early-return branch) to call the same UI-reset steps used when
isNaN(V)||isNaN(D)||V<=0||D<=0 — i.e., reset $('vscTotalDisk'),
$('vscTotalRam'), $('vscTotalDiskB'), $('vscTotalRamB'), $('vscDiskBD'),
$('vscRamBD'), $('vscDiskChart'), $('vscRamChart'), clear
$('vscFormulas').textContent and hide $('vscCluster') before showing the warning
via w.classList.add('vsc-visible') and setting wm.innerHTML; ensure the reset is
applied consistently wherever the function returns early.

In `@tools/vector_sizing_calculator/index.html`:
- Around line 394-398: The standalone preview must mirror the React calculators:
block selecting "disk_bbq" in the indexType select unless quantization is
"float" or "bfloat16", so update the indexType handling (select id="indexType")
and the preview recalculation path (e.g., the function that computes
byte/bit/preview results) to disable or remove the "disk_bbq" option when
quantization is not float/bfloat16 and re-select a valid index if needed;
additionally validate the bbqVpc input (bbqVpc) to require > 0 and short-circuit
the calculation (return an error/skip and avoid computing Infinity) when
invalid, and ensure any quantization change handler also re-sync indexType state
so the inline preview cannot compute bit/byte + disk_bbq combinations that the
shipped React calculators disallow.

In `@tools/vector_sizing_calculator/sizing-section.md`:
- Around line 326-335: The table's quantized column values and reduction factors
are inconsistent with the note that says "Bytes per vector include HNSW graph
overhead (+64 bytes)"; fix by choosing one canonical definition and applying it
consistently: either (A) add the 64-byte HNSW overhead to every quantized value
(e.g., change 384-dim int8 from 388 B/vec to 452 B/vec) and recompute the
reduction factors vs the unquantized baseline, or (B) change the note to state
that the table shows quantized vector bytes only (exclude the 64 B graph
overhead) and update the reduction factors to compare vector-only sizes; update
the rows for Dimensions (384, 768, 1024, 1536) and the reduction factor
parentheses accordingly so all values and the note use the same basis.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb1c8011-775f-4a4c-9883-392f1675ceb5

📥 Commits

Reviewing files that changed from the base of the PR and between 2a9d6f3 and 54bb5a7.

⛔ Files ignored due to path filters (2)
  • tools/vector_sizing_calculator/web-component/dist/vector-sizing-calculator.iife.js is excluded by !**/dist/**
  • tools/vector_sizing_calculator/web-component/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (40)
  • docs/_docset.yml
  • docs/syntax/directives.md
  • docs/syntax/vector-sizing-calculator.md
  • src/Elastic.Documentation.Site/Assets/main.ts
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/Calculator.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/VectorSizingCalculatorComponent.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/calculations.ts
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/components/BreakdownChart.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/components/ClusterTotals.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/components/ConfigurationPanel.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/components/FormulasPanel.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/components/ResultsPanel.tsx
  • src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/types.ts
  • src/Elastic.Markdown/Myst/Directives/DirectiveBlockParser.cs
  • src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs
  • src/Elastic.Markdown/Myst/Directives/VectorSizing/VectorSizingBlock.cs
  • src/Elastic.Markdown/Myst/Directives/VectorSizing/VectorSizingView.cshtml
  • src/Elastic.Markdown/Myst/Directives/VectorSizing/VectorSizingViewModel.cs
  • tests/Elastic.Markdown.Tests/Directives/VectorSizingBlockTests.cs
  • tools/vector_sizing_calculator/INTEGRATION.md
  • tools/vector_sizing_calculator/docs-builder-directive/DirectiveBlockParser.patch.md
  • tools/vector_sizing_calculator/docs-builder-directive/usage-in-docs-content.md
  • tools/vector_sizing_calculator/embed.html
  • tools/vector_sizing_calculator/index.html
  • tools/vector_sizing_calculator/sizing-section.md
  • tools/vector_sizing_calculator/web-component/index.html
  • tools/vector_sizing_calculator/web-component/package.json
  • tools/vector_sizing_calculator/web-component/src/Calculator.tsx
  • tools/vector_sizing_calculator/web-component/src/calculations.ts
  • tools/vector_sizing_calculator/web-component/src/components/BreakdownChart.tsx
  • tools/vector_sizing_calculator/web-component/src/components/ClusterTotals.tsx
  • tools/vector_sizing_calculator/web-component/src/components/ConfigurationPanel.tsx
  • tools/vector_sizing_calculator/web-component/src/components/FormulasPanel.tsx
  • tools/vector_sizing_calculator/web-component/src/components/ResultsPanel.tsx
  • tools/vector_sizing_calculator/web-component/src/eui-icons.d.ts
  • tools/vector_sizing_calculator/web-component/src/icon-cache.ts
  • tools/vector_sizing_calculator/web-component/src/main.tsx
  • tools/vector_sizing_calculator/web-component/src/types.ts
  • tools/vector_sizing_calculator/web-component/tsconfig.json
  • tools/vector_sizing_calculator/web-component/vite.config.ts

Comment on lines +66 to +113
export function validate(inputs: CalculatorInputs): ValidationResult {
const { numVectors, numDimensions, elementType, quantization, indexType } =
inputs;

if (
isNaN(numVectors) ||
isNaN(numDimensions) ||
numVectors <= 0 ||
numDimensions <= 0
) {
return { valid: false };
}

if (numDimensions > 4096) {
return {
valid: false,
warning:
'Elasticsearch supports a maximum of 4,096 dimensions for dense_vector fields.',
warningLink:
'https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params',
};
}

if (
(elementType === 'byte' || elementType === 'bit') &&
quantization !== 'none' &&
indexType !== 'disk_bbq'
) {
return {
valid: true,
warning: `Quantization is not applicable to ${elementType} element type.`,
};
}

if (
elementType === 'float' &&
numDimensions >= 384 &&
quantization === 'none' &&
indexType !== 'disk_bbq'
) {
return {
valid: true,
note: 'For float vectors with dimensions ≥ 384, Elastic strongly recommends using a quantized index to reduce memory footprint.',
};
}

return { valid: true };
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate every numeric input that feeds the formulas.

validate() never checks replicas, hnswM, or vectorsPerCluster, but Lines 178, 184, 256, and 293 use them directly. Clearing those fields or entering 0/negative values can therefore yield zero/negative copy counts or Infinity DiskBBQ totals. Please reject invalid values before calculate() runs, at least for replicas >= 0, hnswM >= 2 when indexType === 'hnsw', and vectorsPerCluster >= 1 when indexType === 'disk_bbq'. The mirrored tools/vector_sizing_calculator/web-component/src/calculations.ts copy needs the same fix.

Also applies to: 177-195, 255-304

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/calculations.ts`
around lines 66 - 113, The validate function currently omits checks for
replicas, hnswM, and vectorsPerCluster which leads to invalid math downstream;
update validate(inputs: CalculatorInputs) to also validate replicas (ensure
replicas >= 0), hnswM (when indexType === 'hnsw' ensure hnswM >= 2), and
vectorsPerCluster (when indexType === 'disk_bbq' ensure vectorsPerCluster >= 1),
and return { valid: false } with a clear warning message (and optional
warningLink) for each violated constraint so calculate() never receives
zero/negative/undefined values; apply the same additions to the mirrored
tools/vector_sizing_calculator/web-component/src/calculations.ts validate
implementation.

Comment on lines +428 to +439
if(isNaN(V)||isNaN(D)||V<=0||D<=0){
$('vscTotalDisk').textContent='—';$('vscTotalRam').textContent='—';
$('vscTotalDiskB').textContent='';$('vscTotalRamB').textContent='';
$('vscDiskBD').innerHTML='';$('vscRamBD').innerHTML='';
$('vscDiskChart').innerHTML='';$('vscRamChart').innerHTML='';
$('vscCluster').style.display='none';$('vscFormulas').textContent='';return;
}
if(D>4096){
w.classList.add('vsc-visible');
wm.innerHTML='Elasticsearch supports a maximum of 4,096 dimensions for dense_vector fields. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params" target="_blank" rel="noopener">See documentation</a>.';
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clear stale UI state before early returns

When inputs become invalid (including Line 435 dimension-limit case), the function returns without consistently clearing prior computed outputs/recommendation state, so stale sizing values can remain visible for an invalid config. Please reset result panels and note visibility before returning on invalid paths.

Proposed fix
   function calc(){
@@
-    if(isNaN(V)||isNaN(D)||V<=0||D<=0){
+    var noteEl=$('vscNote');
+    function clearOutputs() {
+      $('vscTotalDisk').textContent='—';$('vscTotalRam').textContent='—';
+      $('vscTotalDiskB').textContent='';$('vscTotalRamB').textContent='';
+      $('vscDiskBD').innerHTML='';$('vscRamBD').innerHTML='';
+      $('vscDiskChart').innerHTML='';$('vscRamChart').innerHTML='';
+      $('vscCluster').style.display='none';$('vscFormulas').textContent='';
+      noteEl.style.display='none';
+    }
+
+    if(isNaN(V)||isNaN(D)||V<=0||D<=0){
-      $('vscTotalDisk').textContent='—';$('vscTotalRam').textContent='—';
-      $('vscTotalDiskB').textContent='';$('vscTotalRamB').textContent='';
-      $('vscDiskBD').innerHTML='';$('vscRamBD').innerHTML='';
-      $('vscDiskChart').innerHTML='';$('vscRamChart').innerHTML='';
-      $('vscCluster').style.display='none';$('vscFormulas').textContent='';return;
+      clearOutputs();return;
     }
     if(D>4096){
+      clearOutputs();
       w.classList.add('vsc-visible');
       wm.innerHTML='Elasticsearch supports a maximum of 4,096 dimensions for dense_vector fields. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params" target="_blank" rel="noopener">See documentation</a>.';
       return;
     }
@@
-    var noteEl=$('vscNote');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(isNaN(V)||isNaN(D)||V<=0||D<=0){
$('vscTotalDisk').textContent='—';$('vscTotalRam').textContent='—';
$('vscTotalDiskB').textContent='';$('vscTotalRamB').textContent='';
$('vscDiskBD').innerHTML='';$('vscRamBD').innerHTML='';
$('vscDiskChart').innerHTML='';$('vscRamChart').innerHTML='';
$('vscCluster').style.display='none';$('vscFormulas').textContent='';return;
}
if(D>4096){
w.classList.add('vsc-visible');
wm.innerHTML='Elasticsearch supports a maximum of 4,096 dimensions for dense_vector fields. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params" target="_blank" rel="noopener">See documentation</a>.';
return;
}
var noteEl=$('vscNote');
function clearOutputs() {
$('vscTotalDisk').textContent='—';$('vscTotalRam').textContent='—';
$('vscTotalDiskB').textContent='';$('vscTotalRamB').textContent='';
$('vscDiskBD').innerHTML='';$('vscRamBD').innerHTML='';
$('vscDiskChart').innerHTML='';$('vscRamChart').innerHTML='';
$('vscCluster').style.display='none';$('vscFormulas').textContent='';
noteEl.style.display='none';
}
if(isNaN(V)||isNaN(D)||V<=0||D<=0){
clearOutputs();return;
}
if(D>4096){
clearOutputs();
w.classList.add('vsc-visible');
wm.innerHTML='Elasticsearch supports a maximum of 4,096 dimensions for dense_vector fields. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params" target="_blank" rel="noopener">See documentation</a>.';
return;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/vector_sizing_calculator/embed.html` around lines 428 - 439, The
early-return paths do not clear the same UI state as the initial validation
block, so stale results remain when D>4096 (and other invalid inputs) trigger a
return; update the D>4096 branch (and any other early-return branch) to call the
same UI-reset steps used when isNaN(V)||isNaN(D)||V<=0||D<=0 — i.e., reset
$('vscTotalDisk'), $('vscTotalRam'), $('vscTotalDiskB'), $('vscTotalRamB'),
$('vscDiskBD'), $('vscRamBD'), $('vscDiskChart'), $('vscRamChart'), clear
$('vscFormulas').textContent and hide $('vscCluster') before showing the warning
via w.classList.add('vsc-visible') and setting wm.innerHTML; ensure the reset is
applied consistently wherever the function returns early.

Comment on lines +394 to +398
<select id="indexType">
<option value="hnsw">HNSW</option>
<option value="flat">Flat (brute-force)</option>
<option value="disk_bbq">DiskBBQ</option>
</select>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Block unsupported disk_bbq states in the standalone preview.

Line 397 always exposes disk_bbq, and Lines 581-603 only re-sync quantization. That lets this page calculate byte/bit + disk_bbq, even though both React calculators only allow disk_bbq for float/bfloat16. The inline path also never rejects bbqVpc <= 0, so Line 707 can produce Infinity results. This preview URL will otherwise disagree with the shipped calculator on valid inputs and outputs.

Also applies to: 572-640, 707-714

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/vector_sizing_calculator/index.html` around lines 394 - 398, The
standalone preview must mirror the React calculators: block selecting "disk_bbq"
in the indexType select unless quantization is "float" or "bfloat16", so update
the indexType handling (select id="indexType") and the preview recalculation
path (e.g., the function that computes byte/bit/preview results) to disable or
remove the "disk_bbq" option when quantization is not float/bfloat16 and
re-select a valid index if needed; additionally validate the bbqVpc input
(bbqVpc) to require > 0 and short-circuit the calculation (return an error/skip
and avoid computing Infinity) when invalid, and ensure any quantization change
handler also re-sync indexType state so the inline preview cannot compute
bit/byte + disk_bbq combinations that the shipped React calculators disallow.

Comment on lines +326 to +335
| Dimensions | No quantization | `int8` | `int4` | `bbq` |
| --- | --- | --- | --- | --- |
| 384 | 1,600 B/vec | 388 B/vec (4.1×) | 196 B/vec (8.2×) | 62 B/vec (25.8×) |
| 768 | 3,136 B/vec | 772 B/vec (4.1×) | 388 B/vec (8.1×) | 110 B/vec (28.5×) |
| 1,024 | 4,160 B/vec | 1,028 B/vec (4.0×) | 516 B/vec (8.1×) | 142 B/vec (29.3×) |
| 1,536 | 6,208 B/vec | 1,540 B/vec (4.0×) | 772 B/vec (8.0×) | 206 B/vec (30.1×) |

:::{note}
Bytes per vector include HNSW graph overhead (64 bytes with `m = 16`). Reduction factors compare total per-vector RAM (vectors + graph) against the unquantized baseline.
:::
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Correct inconsistent RAM math assumptions in the quick-reference table.

Line 334 says values include HNSW graph overhead (+64 bytes), but the quantized entries at Lines 328-331 match quantized vector bytes only (for example, 384-dim int8 is shown as 388, not 452). This makes the reduction factors inconsistent with the stated formula basis and can misstate sizing guidance.

Please align the table values/factors and the note to one consistent definition before merge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/vector_sizing_calculator/sizing-section.md` around lines 326 - 335, The
table's quantized column values and reduction factors are inconsistent with the
note that says "Bytes per vector include HNSW graph overhead (+64 bytes)"; fix
by choosing one canonical definition and applying it consistently: either (A)
add the 64-byte HNSW overhead to every quantized value (e.g., change 384-dim
int8 from 388 B/vec to 452 B/vec) and recompute the reduction factors vs the
unquantized baseline, or (B) change the note to state that the table shows
quantized vector bytes only (exclude the 64 B graph overhead) and update the
reduction factors to compare vector-only sizes; update the rows for Dimensions
(384, 768, 1024, 1536) and the reduction factor parentheses accordingly so all
values and the note use the same basis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants