oxirs_arq/optimizer/
statistics.rs1use std::collections::HashMap;
6use std::time::Duration;
7
8use super::execution_tracking::{ExecutionRecord, OptimizationDecision, OptimizationType};
9use super::index_types::{IndexStatistics, IndexType};
10use crate::algebra::Variable;
11
12#[derive(Debug, Clone, Default)]
14pub struct Statistics {
15 pub index_stats: HashMap<IndexType, IndexStatistics>,
17 pub join_selectivities: HashMap<String, f64>,
19 pub filter_selectivities: HashMap<String, f64>,
21 pub execution_times: HashMap<String, Duration>,
23 pub cardinalities: HashMap<String, usize>,
25 pub pattern_cardinality: HashMap<String, usize>,
27 pub predicate_frequency: HashMap<String, usize>,
29 pub subject_cardinality: HashMap<String, usize>,
31 pub object_cardinality: HashMap<String, usize>,
33 pub variable_selectivity: HashMap<Variable, f64>,
35 pub optimization_success_rates: HashMap<OptimizationType, f64>,
37 pub total_queries: usize,
39 pub total_optimization_time: Duration,
41}
42
43impl Statistics {
44 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn update_with_execution(&mut self, record: &ExecutionRecord) {
51 self.total_queries += 1;
52
53 for decision in &record.optimization_decisions {
55 self.update_optimization_success_rate(decision);
56 }
57
58 let query_hash = record.query_hash.to_string();
60 self.execution_times
61 .insert(query_hash.clone(), record.execution_time);
62 self.cardinalities.insert(query_hash, record.cardinality);
63 }
64
65 pub fn update_index_stats(&mut self, index_type: IndexType, stats: IndexStatistics) {
67 self.index_stats.insert(index_type, stats);
68 }
69
70 pub fn get_join_selectivity(&self, join_pattern: &str) -> Option<f64> {
72 self.join_selectivities.get(join_pattern).copied()
73 }
74
75 pub fn set_join_selectivity(&mut self, join_pattern: String, selectivity: f64) {
77 self.join_selectivities.insert(join_pattern, selectivity);
78 }
79
80 pub fn get_filter_selectivity(&self, filter_pattern: &str) -> Option<f64> {
82 self.filter_selectivities.get(filter_pattern).copied()
83 }
84
85 pub fn set_filter_selectivity(&mut self, filter_pattern: String, selectivity: f64) {
87 self.filter_selectivities
88 .insert(filter_pattern, selectivity);
89 }
90
91 pub fn get_estimated_cardinality(&self, pattern: &str) -> Option<usize> {
93 self.cardinalities.get(pattern).copied()
94 }
95
96 pub fn get_optimization_success_rate(&self, opt_type: &OptimizationType) -> f64 {
98 self.optimization_success_rates
99 .get(opt_type)
100 .copied()
101 .unwrap_or(0.5) }
103
104 pub fn add_optimization_time(&mut self, duration: Duration) {
106 self.total_optimization_time += duration;
107 }
108
109 pub fn average_optimization_time(&self) -> Duration {
111 if self.total_queries > 0 {
112 self.total_optimization_time / self.total_queries as u32
113 } else {
114 Duration::default()
115 }
116 }
117
118 fn update_optimization_success_rate(&mut self, decision: &OptimizationDecision) {
119 let current_rate = self
120 .optimization_success_rates
121 .get(&decision.optimization_type)
122 .copied()
123 .unwrap_or(0.5);
124
125 let alpha = 0.1;
127 let success_value = if decision.success { 1.0 } else { 0.0 };
128 let new_rate = alpha * success_value + (1.0 - alpha) * current_rate;
129
130 self.optimization_success_rates
131 .insert(decision.optimization_type.clone(), new_rate);
132 }
133}
134
135impl PartialEq for OptimizationType {
137 fn eq(&self, other: &Self) -> bool {
138 std::mem::discriminant(self) == std::mem::discriminant(other)
139 }
140}
141
142impl Eq for OptimizationType {}
143
144impl std::hash::Hash for OptimizationType {
145 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
146 std::mem::discriminant(self).hash(state);
147 }
148}