diff options
Diffstat (limited to 'ml/Dimension.h')
-rw-r--r-- | ml/Dimension.h | 169 |
1 files changed, 60 insertions, 109 deletions
diff --git a/ml/Dimension.h b/ml/Dimension.h index d61d385fa7..eb37f0755a 100644 --- a/ml/Dimension.h +++ b/ml/Dimension.h @@ -3,155 +3,106 @@ #ifndef ML_DIMENSION_H #define ML_DIMENSION_H -#include "BitBufferCounter.h" +#include "Query.h" #include "Config.h" #include "ml-private.h" namespace ml { -class RrdDimension { -public: - RrdDimension(RRDDIM *RD) : RD(RD), Ops(&RD->tiers[0]->query_ops) { } - - RRDDIM *getRD() const { return RD; } - - time_t latestTime() { return Ops->latest_time(RD->tiers[0]->db_metric_handle); } - - time_t oldestTime() { return Ops->oldest_time(RD->tiers[0]->db_metric_handle); } +enum class MLResult { + Success = 0, + MissingData, + NaN, +}; - unsigned updateEvery() const { return RD->update_every; } +static inline std::string getMLDimensionID(RRDDIM *RD) { + RRDSET *RS = RD->rrdset; - const std::string getID() const { - RRDSET *RS = RD->rrdset; + std::stringstream SS; + SS << rrdset_context(RS) << "|" << rrdset_id(RS) << "|" << rrddim_name(RD); + return SS.str(); +} - std::stringstream SS; - SS << rrdset_context(RS) << "|" << rrdset_id(RS) << "|" << rrddim_name(RD); - return SS.str(); +class Dimension { +public: + Dimension(RRDDIM *RD, RRDSET *AnomalyRateRS) : + RD(RD), + AnomalyRateRD(rrddim_add(AnomalyRateRS, ml::getMLDimensionID(RD).c_str(), NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE)), + LastTrainedAt(Seconds(0)), + Trained(false), + ConstantModel(false), + AnomalyScore(0.0), + AnomalyBit(0), + AnomalyBitCounter(0) + { } + + RRDDIM *getRD() const { + return RD; } - bool isActive() const { - if (rrdset_flag_check(RD->rrdset, RRDSET_FLAG_OBSOLETE)) - return false; - - if (rrddim_flag_check(RD, RRDDIM_FLAG_OBSOLETE)) - return false; + unsigned updateEvery() const { + return RD->update_every; + } - return true; + time_t latestTime() const { + return Query(RD).latestTime(); } - void setAnomalyRateRD(RRDDIM *ARRD) { AnomalyRateRD = ARRD; } - RRDDIM *getAnomalyRateRD() const { return AnomalyRateRD; } + time_t oldestTime() const { + return Query(RD).oldestTime(); + } void setAnomalyRateRDName(const char *Name) const { rrddim_reset_name(AnomalyRateRD->rrdset, AnomalyRateRD, Name); } - virtual ~RrdDimension() {} - -private: - RRDDIM *RD; - RRDDIM *AnomalyRateRD; + RRDDIM *getAnomalyRateRD() const { + return AnomalyRateRD; + } - struct rrddim_query_ops *Ops; + bool isTrained() const { + return Trained; + } - std::string ID; -}; + bool isAnomalous() const { + return AnomalyBit; + } -enum class MLResult { - Success = 0, - MissingData, - NaN, -}; + bool shouldTrain(const TimePoint &TP) const; -class TrainableDimension : public RrdDimension { -public: - TrainableDimension(RRDDIM *RD) : - RrdDimension(RD), TrainEvery(Cfg.TrainEvery * updateEvery()) {} + bool isActive() const; MLResult trainModel(); - CalculatedNumber computeAnomalyScore(SamplesBuffer &SB) { - return Trained ? KM.anomalyScore(SB) : 0.0; - } + bool predict(CalculatedNumber Value, bool Exists); - bool shouldTrain(const TimePoint &TP) const { - if (ConstantModel) - return false; + void updateAnomalyBitCounter(RRDSET *RS, unsigned Elapsed, bool IsAnomalous); - return (LastTrainedAt + TrainEvery) < TP; - } + std::pair<bool, double> detect(size_t WindowLength, bool Reset); - bool isTrained() const { return Trained; } + std::array<KMeans, 1> getModels(); private: std::pair<CalculatedNumber *, size_t> getCalculatedNumbers(); public: - TimePoint LastTrainedAt{Seconds{0}}; - -protected: - std::atomic<bool> ConstantModel{false}; - -private: - Seconds TrainEvery; - KMeans KM; - - std::atomic<bool> Trained{false}; -}; - -class PredictableDimension : public TrainableDimension { -public: - PredictableDimension(RRDDIM *RD) : TrainableDimension(RD) {} - - std::pair<MLResult, bool> predict(); - - void addValue(CalculatedNumber Value, bool Exists); - - bool isAnomalous() { return AnomalyBit; } + RRDDIM *RD; + RRDDIM *AnomalyRateRD; - void updateAnomalyBitCounter(RRDSET *RS, unsigned Elapsed, bool IsAnomalous) { - AnomalyBitCounter += IsAnomalous; + TimePoint LastTrainedAt; + std::atomic<bool> Trained; + std::atomic<bool> ConstantModel; - if (Elapsed == Cfg.DBEngineAnomalyRateEvery) { - double AR = static_cast<double>(AnomalyBitCounter) / Cfg.DBEngineAnomalyRateEvery; - rrddim_set_by_pointer(RS, getAnomalyRateRD(), AR * 1000); - AnomalyBitCounter = 0; - } - } - -private: - CalculatedNumber AnomalyScore{0.0}; - std::atomic<bool> AnomalyBit{false}; - unsigned AnomalyBitCounter{0}; + CalculatedNumber AnomalyScore; + std::atomic<bool> AnomalyBit; + unsigned AnomalyBitCounter; std::vector<CalculatedNumber> CNs; + std::array<KMeans, 1> Models; + std::mutex Mutex; }; -class DetectableDimension : public PredictableDimension { -public: - DetectableDimension(RRDDIM *RD) : PredictableDimension(RD) {} - - std::pair<bool, double> detect(size_t WindowLength, bool Reset) { - bool AnomalyBit = isAnomalous(); - - if (Reset) - NumSetBits = BBC.numSetBits(); - - NumSetBits += AnomalyBit; - BBC.insert(AnomalyBit); - - double AnomalyRate = static_cast<double>(NumSetBits) / WindowLength; - return { AnomalyBit, AnomalyRate }; - } - -private: - BitBufferCounter BBC{static_cast<size_t>(Cfg.ADMinWindowSize)}; - size_t NumSetBits{0}; -}; - -using Dimension = DetectableDimension; - } // namespace ml #endif /* ML_DIMENSION_H */ |