Skip to main content

uqa_storage/diskann_index/metadata/
statistics.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7use super::{DiskANNCanonicalCounts, DiskANNQueryMetadata};
8use crate::diskann_index::{
9    format::PAGE_BYTES,
10    metric::{exact_reason, norms},
11    ExactVectorReason,
12};
13use crate::{read_control::StorageReadControl, StorageBackendResult};
14use uqa_core::{
15    DiskANNIndexStats, DiskANNQueryStats, VectorGeneration, VectorPopulationStats,
16    VectorQueryRoute, VectorReadStats,
17};
18
19impl DiskANNQueryMetadata {
20    /// Project stored physical facts and classify the query with the same canonical norm calculation as execution, without normalizing coordinates or reading artifact bodies.
21    pub fn query_statistics(
22        &self,
23        query: &[f32],
24        control: &StorageReadControl,
25    ) -> StorageBackendResult<DiskANNQueryStats> {
26        let input = self.manifest.input();
27        let (norm, _) = norms(input.dimensions, query, control)?;
28        let query_route = match exact_reason(norm) {
29            None => VectorQueryRoute::Approximate,
30            Some(ExactVectorReason::ZeroNorm) => VectorQueryRoute::ExactZeroNorm,
31            Some(ExactVectorReason::NonFiniteNorm) => VectorQueryRoute::ExactNonFiniteNorm,
32        };
33        Ok(DiskANNQueryStats {
34            index: self.index_statistics(control)?,
35            query_route,
36        })
37    }
38
39    /// Project the selected field without evaluating query arguments or preparing search artifacts.
40    pub fn index_statistics(
41        &self,
42        control: &StorageReadControl,
43    ) -> StorageBackendResult<DiskANNIndexStats> {
44        control.check()?;
45        let input = self.manifest.input();
46        let generation = input.generation;
47        let layout = self.manifest.layout();
48        let pq_centroids = if input.nodes == 0 {
49            Some(0)
50        } else {
51            self.manifest.build_provenance().map(|provenance| {
52                let options = provenance.training();
53                input
54                    .nodes
55                    .min(u64::from(options.max_samples))
56                    .min(u64::from(options.max_centroids)) as u16
57            })
58        };
59        control.check()?;
60        Ok(DiskANNIndexStats {
61            generation: VectorGeneration {
62                database: generation.database(),
63                table: generation.table(),
64                index: generation.index(),
65                generation: generation.generation(),
66            },
67            dimensions: input.dimensions,
68            max_degree: input.parameters.max_degree,
69            search_list_size: input.parameters.search_list_size,
70            beam_width: input.parameters.beam_width,
71            pq_bytes: input.parameters.pq_bytes,
72            pq_centroids,
73            node_slot_bytes: layout.slot_bytes(),
74            node_fragments: if input.nodes == 0 {
75                0
76            } else {
77                layout.node_address(0)?.fragments
78            },
79            graph_pages: layout.page_count(),
80            graph_edges: self
81                .manifest
82                .build_provenance()
83                .map(crate::diskann_index::format::DiskANNBuildProvenance::edges),
84            page_bytes: PAGE_BYTES,
85            populations: VectorPopulationStats {
86                base_documents: self
87                    .manifest
88                    .origins()
89                    .map(crate::diskann_index::format::DiskANNOriginSummary::documents),
90                base_vectors: input.coverage.vector_count(),
91                graph_nodes: input.nodes,
92                side_vectors: input.side_vectors,
93                current_vectors: self
94                    .canonical_counts
95                    .map(DiskANNCanonicalCounts::current_vectors),
96                changed_vectors: self
97                    .canonical_counts
98                    .map(DiskANNCanonicalCounts::changed_vectors),
99            },
100            reads: VectorReadStats {
101                resident_bytes: self.read_limits.resident_bytes,
102                cache_bytes: self.read_limits.cache_bytes,
103                max_record_bytes: self.read_limits.max_record_bytes,
104                max_in_flight_page_bytes: self.read_limits.max_in_flight_page_bytes,
105                max_batch_pages: self.read_capabilities.max_batch_pages(),
106                read_concurrency: self.read_capabilities.read_concurrency(),
107            },
108        })
109    }
110}