From b003f1ee1722724c95a27cce76eaaad818f72008 Mon Sep 17 00:00:00 2001 From: Alexey Velikiy Date: Mon, 29 Nov 2021 09:12:49 +0300 Subject: [PATCH] seasonality iterations --- client/src/views/Home.vue | 8 +++++++- .../analytic_unit/anomaly_analytic_unit.rs | 19 ++++++++++--------- .../analytic_service/analytic_unit/types.rs | 5 ++++- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/client/src/views/Home.vue b/client/src/views/Home.vue index 817bae2..2f06222 100644 --- a/client/src/views/Home.vue +++ b/client/src/views/Home.vue @@ -41,6 +41,8 @@
Seasonality:
+ Seasonality iterations: +

@@ -117,7 +119,11 @@ export default defineComponent({ cfg.seasonality = parseFloat(e.target.value); this.$store.dispatch('patchConfig', { Anomaly: cfg }); }, - + seasonalityIterationsChange(e) { + let cfg = _.clone(this.analyticUnitConfig); + cfg.seasonality_iterations = Math.ceil(e.target.value); + this.$store.dispatch('patchConfig', { Anomaly: cfg }); + }, }, data: function () { return { diff --git a/server/src/services/analytic_service/analytic_unit/anomaly_analytic_unit.rs b/server/src/services/analytic_service/analytic_unit/anomaly_analytic_unit.rs index 57fc024..08a82c0 100644 --- a/server/src/services/analytic_service/analytic_unit/anomaly_analytic_unit.rs +++ b/server/src/services/analytic_service/analytic_unit/anomaly_analytic_unit.rs @@ -10,7 +10,6 @@ use chrono::prelude::*; // TODO: move to config const DETECTION_STEP: u64 = 10; -const SEASONALITY_ITERATIONS: u64 = 3; // TODO: better name // timerange offset in seconds backwards from end of ts in assumption that ts has no gaps fn get_value_with_offset(ts: &Vec<(u64, f64)>, offset: u64) -> Option<(u64, f64)>{ @@ -30,14 +29,16 @@ struct SARIMA { pub ts: Vec<(u64, f64)>, pub seasonality: u64, pub confidence: f64, + pub seasonality_iterations: u64 } impl SARIMA { - pub fn new(seasonality: u64, confidence: f64) -> SARIMA { + pub fn new(seasonality: u64, confidence: f64, seasonality_iterations: u64) -> SARIMA { return SARIMA { ts: Vec::new(), seasonality, - confidence + confidence, + seasonality_iterations }; } @@ -56,17 +57,17 @@ impl SARIMA { let to = ts.last().unwrap().0; let iter_steps = (self.seasonality / DETECTION_STEP) as usize; - if to - from != SEASONALITY_ITERATIONS * self.seasonality { - return Err(anyhow::format_err!("timeserie to learn from should be {} * sasonality", SEASONALITY_ITERATIONS)); + if to - from != self.seasonality_iterations * self.seasonality { + return Err(anyhow::format_err!("timeserie to learn from should be {} * sasonality", self.seasonality_iterations)); } for k in 0..iter_steps { let mut vts = Vec::new(); - for si in 0..SEASONALITY_ITERATIONS { + for si in 0..self.seasonality_iterations { vts.push(ts[k + iter_steps * si as usize].1); } let mut vt: f64 = vts.iter().sum(); - vt /= SEASONALITY_ITERATIONS as f64; + vt /= self.seasonality_iterations as f64; let t = ts[ts.len() - iter_steps + k].0; res_ts.push((t, vt)); } @@ -167,11 +168,11 @@ impl AnalyticUnit for AnomalyAnalyticUnit { } } async fn learn(&mut self, ms: MetricService, _ss: SegmentsService) -> LearningResult { - let mut sarima = SARIMA::new(self.config.seasonality, self.config.confidence); + let mut sarima = SARIMA::new(self.config.seasonality, self.config.confidence, self.config.seasonality_iterations); let utc: DateTime = Utc::now(); let to = utc.timestamp() as u64; - let from = to - self.config.seasonality * SEASONALITY_ITERATIONS; + let from = to - self.config.seasonality * self.config.seasonality_iterations; let mr = ms.query(from, to, DETECTION_STEP).await.unwrap(); if mr.data.keys().len() == 0 { diff --git a/server/src/services/analytic_service/analytic_unit/types.rs b/server/src/services/analytic_service/analytic_unit/types.rs index a32b7c7..11f2247 100644 --- a/server/src/services/analytic_service/analytic_unit/types.rs +++ b/server/src/services/analytic_service/analytic_unit/types.rs @@ -30,6 +30,7 @@ pub struct AnomalyConfig { pub alpha: f64, pub confidence: f64, pub seasonality: u64, // step in seconds, can be zero + pub seasonality_iterations: u64 } impl Default for AnomalyConfig { @@ -38,6 +39,7 @@ impl Default for AnomalyConfig { alpha: 0.5, confidence: 10.0, seasonality: 60 * 60, + seasonality_iterations: 3 } } } @@ -85,7 +87,8 @@ impl AnalyticUnitConfig { AnalyticUnitConfig::Anomaly(scfg) => { if tcfg.is_some() { let t = tcfg.as_ref().unwrap(); - let need_learning = t.seasonality != scfg.seasonality; + let mut need_learning = t.seasonality != scfg.seasonality; + need_learning |= t.seasonality_iterations != scfg.seasonality_iterations; return (AnalyticUnitConfig::Anomaly(tcfg.unwrap()), need_learning); } else { return (AnalyticUnitConfig::Anomaly(Default::default()), false);