Skip to main content

uqa_sql/schema/indexes/options/
diskann.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7use crate::SQLError;
8
9/// Raw options; Storage resolves defaults and validates them against the target dimension.
10#[derive(Debug, Default, PartialEq)]
11pub struct DiskANNIndexOptions {
12    pub max_degree: Option<usize>,
13    pub build_list_size: Option<usize>,
14    pub search_list_size: Option<usize>,
15    pub alpha: Option<f64>,
16    pub beam_width: Option<usize>,
17    pub pq_bytes: Option<usize>,
18    pub seed: Option<u64>,
19}
20
21pub fn parse_diskann_index_options(
22    options: &[(String, String)],
23) -> Result<DiskANNIndexOptions, SQLError> {
24    let mut params = DiskANNIndexOptions::default();
25    let mut seen = std::collections::BTreeSet::new();
26    for (key, value) in options {
27        let canonical = match key.to_ascii_lowercase().as_str() {
28            "max_degree" => "max_degree",
29            "build_list_size" => "build_list_size",
30            "search_list_size" => "search_list_size",
31            "alpha" => "alpha",
32            "beam_width" => "beam_width",
33            "pq_bytes" => "pq_bytes",
34            "seed" => "seed",
35            _ => {
36                return Err(SQLError::Unsupported(format!(
37                    "CREATE INDEX USING diskann option `{key}` is not supported"
38                )));
39            }
40        };
41        super::claim_index_option(&mut seen, canonical, "diskann", key)?;
42        if canonical == "alpha" {
43            let parsed = value.parse::<f64>().ok().filter(|value| value.is_finite());
44            params.alpha = Some(parsed.ok_or_else(|| {
45                SQLError::TypeMismatch(format!(
46                    "CREATE INDEX USING diskann option `{key}` must be a finite real number"
47                ))
48            })?);
49        } else if canonical == "seed" {
50            params.seed = Some(value.parse::<u64>().map_err(|_| {
51                SQLError::TypeMismatch(format!(
52                    "CREATE INDEX USING diskann option `{key}` must be an unsigned integer"
53                ))
54            })?);
55        } else {
56            let target = match canonical {
57                "max_degree" => &mut params.max_degree,
58                "build_list_size" => &mut params.build_list_size,
59                "search_list_size" => &mut params.search_list_size,
60                "beam_width" => &mut params.beam_width,
61                "pq_bytes" => &mut params.pq_bytes,
62                _ => unreachable!(),
63            };
64            *target = Some(super::parse_positive_usize_option("diskann", key, value)?);
65        }
66    }
67    Ok(params)
68}
69
70#[cfg(test)]
71mod tests;