Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/_docset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ toc:
- file: images.md
- file: kbd.md
- file: math.md
- file: vector-sizing-calculator.md
- file: diagrams.md
- file: lists.md
- file: line_breaks.md
Expand Down
3 changes: 2 additions & 1 deletion docs/syntax/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,5 @@ The following directives are available:
- [Stepper](stepper.md) - Step-by-step content
- [Tabs](tabs.md) - Tabbed content organization
- [Tables](tables.md) - Data tables
- [Version blocks](version-variables.md) - API version information
- [Version blocks](version-variables.md) - API version information
- [Vector sizing calculator](vector-sizing-calculator.md) - Interactive dense_vector sizing estimates
21 changes: 21 additions & 0 deletions docs/syntax/vector-sizing-calculator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Vector sizing calculator

The `{vector-sizing-calculator}` directive embeds an interactive calculator for estimating disk and off-heap memory for `dense_vector` fields. The docs site loads the React/EUI web component that registers the `<vector-sizing-calculator>` custom element.

## Usage

```markdown
:::{vector-sizing-calculator}
:::
```

No body content or options are required. Configuration happens in the widget UI.

## Live preview

:::{vector-sizing-calculator}
:::

## Requirements

This directive only produces useful output where the assembled documentation site includes the vector sizing bundle (see `src/Elastic.Documentation.Site/Assets/web-components/VectorSizingCalculator/`).
1 change: 1 addition & 0 deletions src/Elastic.Documentation.Site/Assets/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { initSmoothScroll } from './smooth-scroll'
import { initTabs } from './tabs'
import { initializeOtel } from './telemetry/instrumentation'
import { initTocNav } from './toc-nav'
import './web-components/VectorSizingCalculator/VectorSizingCalculatorComponent'
import 'htmx-ext-head-support'
import 'htmx-ext-preload'
import * as katex from 'katex'
Expand Down
1 change: 1 addition & 0 deletions src/Elastic.Documentation.Site/Assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
@import './markdown/agent-skill.css';
@import './markdown/contributors.css';
@import './api-docs.css';
@import './web-components/VectorSizingCalculator/vector-sizing-calculator.css';
@import 'tippy.js/dist/tippy.css';

html {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import {
calculate,
validate,
getAvailableQuantizations,
getQuantizationInsightText,
} from './calculations'
import { ConfigurationPanel } from './components/ConfigurationPanel'
import { ResultsPanel } from './components/ResultsPanel'
import { parseVectorCount } from './parseVectorCount'
import type {
ElementType,
IndexType,
Quantization,
CalculatorInputs,
} from './types'
import { useState, useMemo, useEffect } from 'react'

function getAvailableIndexTypes(elementType: ElementType) {
const options = [
{ value: 'hnsw', text: 'HNSW' },
{ value: 'flat', text: 'Flat (brute-force)' },
]
if (elementType === 'float' || elementType === 'bfloat16') {
options.push({ value: 'disk_bbq', text: 'DiskBBQ' })
}
return options
}

export function Calculator() {
const [vectorsText, setVectorsText] = useState('1,000,000')
const [numDimensions, setNumDimensions] = useState<number | string>(768)
const [elementType, setElementType] = useState<ElementType>('float')
const [indexType, setIndexType] = useState<IndexType>('hnsw')
const [quantization, setQuantization] = useState<Quantization>('bbq')
const [replicas, setReplicas] = useState(2)
const [hnswM, setHnswM] = useState(4)
const efConstruction = 100
const vectorsPerCluster = 384

const indexTypeOptions = useMemo(
() => getAvailableIndexTypes(elementType),
[elementType]
)
const quantOptions = useMemo(
() => getAvailableQuantizations(elementType, indexType),
[elementType, indexType]
)

useEffect(() => {
const available = indexTypeOptions.map((o) => o.value)
if (!available.includes(indexType)) {
setIndexType(available[0] as IndexType)
}
}, [indexTypeOptions, indexType])

useEffect(() => {
const available = quantOptions.map((o) => o.value)
if (!available.includes(quantization)) {
setQuantization(available[0] as Quantization)
}
}, [quantOptions, quantization])

const inputs: CalculatorInputs = useMemo(
() => ({
numVectors: parseVectorCount(vectorsText),
numDimensions:
typeof numDimensions === 'number' ? numDimensions : NaN,
elementType,
indexType,
quantization,
replicas,
hnswM,
efConstruction,
vectorsPerCluster,
}),
[
vectorsText,
numDimensions,
elementType,
indexType,
quantization,
replicas,
hnswM,
efConstruction,
vectorsPerCluster,
]
)

const validation = useMemo(() => validate(inputs), [inputs])
const result = useMemo(
() => (validation.valid ? calculate(inputs) : null),
[inputs, validation]
)

const quantizationLabel = useMemo(
() => quantOptions.find((o) => o.value === quantization)?.label ?? '',
[quantOptions, quantization]
)

const inputsValid = Boolean(validation.valid && result !== null)

const quantizationInsightText = useMemo(() => {
if (!validation.valid || result === null) return null
return getQuantizationInsightText(inputs, result)
}, [inputs, result, validation.valid])

return (
<div className="vectorSizingCalc">
<div className="vectorSizingCalc__grid">
<ConfigurationPanel
vectorsText={vectorsText}
onVectorsChange={setVectorsText}
numDimensions={numDimensions}
onDimensionsChange={setNumDimensions}
elementType={elementType}
onElementTypeChange={setElementType}
indexType={indexType}
onIndexTypeChange={setIndexType}
indexTypeOptions={indexTypeOptions}
quantization={quantization}
onQuantizationChange={setQuantization}
quantOptions={quantOptions}
replicas={replicas}
onReplicasChange={setReplicas}
hnswM={hnswM}
onHnswMChange={setHnswM}
validation={validation}
/>

<ResultsPanel
result={result}
inputsValid={inputsValid}
quantizationLabel={quantizationLabel}
replicas={replicas}
quantization={quantization}
validation={validation}
quantizationInsightText={quantizationInsightText}
/>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import '../../eui-icons-cache'
import { Calculator } from './Calculator'
import { EuiProvider } from '@elastic/eui'
import r2wc from '@r2wc/react-to-web-component'
import * as React from 'react'
import { StrictMode } from 'react'

const VectorSizingCalculatorWrapper = () => {
return (
<StrictMode>
<EuiProvider
colorMode="light"
globalStyles={false}
utilityClasses={false}
>
<Calculator />
</EuiProvider>
</StrictMode>
)
}

if (!customElements.get('vector-sizing-calculator')) {
customElements.define(
'vector-sizing-calculator',
r2wc(VectorSizingCalculatorWrapper)
)
}
Loading
Loading