uqa_storage/diskann_index/metadata/
statistics.rs1use 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 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 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}