Skip to content

Commit 877dccb

Browse files
[ML] Implement new rules design (#119)
The ml-cpp side of the new rules implementation.
1 parent 50f57e2 commit 877dccb

25 files changed

+802
-1207
lines changed

docs/CHANGELOG.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
=== New Features
1515

16+
Detectors now support rules that allow the user to improve the results by providing some domain specific
17+
knowledge in the form of rule. ({pull}119[#119])
18+
1619
=== Enhancements
1720

1821
Improve and use periodic boundary condition for seasonal component modeling ({pull}84[#84])

include/api/CDetectionRulesJsonParser.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,22 @@ class API_EXPORT CDetectionRulesJsonParser {
3838
bool parseRules(const std::string& json, TDetectionRuleVec& rules);
3939

4040
private:
41+
bool parseRuleScope(const rapidjson::Value& ruleObject, model::CDetectionRule& rule);
4142
bool parseRuleConditions(const rapidjson::Value& ruleObject, model::CDetectionRule& rule);
42-
bool parseFilterId(const rapidjson::Value& conditionObject,
43-
model::CRuleCondition& ruleCondition);
4443

4544
static bool hasStringMember(const rapidjson::Value& object, const std::string& name);
4645
static bool hasArrayMember(const rapidjson::Value& object, const std::string& name);
46+
static bool hasDoubleMember(const rapidjson::Value& object, const std::string& name);
4747
static bool parseRuleActions(const rapidjson::Value& ruleObject,
4848
model::CDetectionRule& rule);
4949
static bool parseConditionsConnective(const rapidjson::Value& ruleObject,
5050
model::CDetectionRule& rule);
51-
static bool parseRuleConditionType(const rapidjson::Value& ruleConditionObject,
52-
model::CRuleCondition& ruleCondition);
53-
static bool parseCondition(const rapidjson::Value& ruleConditionObject,
54-
model::CRuleCondition& ruleCondition);
55-
static bool parseConditionOperator(const rapidjson::Value& conditionObject,
56-
model::CRuleCondition& ruleCondition);
57-
static bool parseConditionThreshold(const rapidjson::Value& conditionObject,
51+
static bool parseConditionAppliesTo(const rapidjson::Value& ruleConditionObject,
5852
model::CRuleCondition& ruleCondition);
53+
static bool parseConditionOperator(const rapidjson::Value& conditionObject,
54+
model::CRuleCondition& condition);
55+
static bool parseConditionValue(const rapidjson::Value& conditionObject,
56+
model::CRuleCondition& condition);
5957

6058
private:
6159
//! The filters per id used by categorical rule conditions.

include/model/CDetectionRule.h

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define INCLUDED_ml_model_CDetectionRule_h
99

1010
#include <model/CRuleCondition.h>
11+
#include <model/CRuleScope.h>
1112
#include <model/ImportExport.h>
1213
#include <model/ModelTypes.h>
1314

@@ -21,48 +22,33 @@ class CAnomalyDetectorModel;
2122
//! \brief A rule that dictates an action to be taken when certain conditions occur.
2223
//!
2324
//! DESCRIPTION:\n
24-
//! A rule describes an action to be taken and the conditions under which
25-
//! the action should be taken. A rule has an action and one or more conditions.
26-
//! The conditions are combined according to the rule's connective which can
27-
//! be either OR or AND. A rule can optionally have a target field specified.
28-
//! When such target is not specified, the rule applies to the series that is
29-
//! checked against the rule. When a target is specified, the rule applies to
30-
//! all series that are contained within the target. For example, if the target
31-
//! is the partition field and no targetFieldValue is specified, then if the
32-
//! conditions trigger the rule, the rule will apply to all series within the
33-
//! partition. However, when no target is specified, the rule will trigger only
34-
//! for series that are described in the conditions themselves.
25+
//! A rule describes actions to be taken when the scope and conditions are met.
26+
//! A rule has one or more actions, a scope and zero or more conditions.
27+
//! The scope dictates to which series the rule applies.
28+
//! When conditions are present, they dictate to which results the rule applies
29+
//! depending the result's values. Multiple conditions are combined with a logical AND.
3530
class MODEL_EXPORT CDetectionRule {
31+
3632
public:
3733
using TRuleConditionVec = std::vector<CRuleCondition>;
38-
using TDouble1Vec = core::CSmallVector<double, 1>;
3934

40-
//! Rule actions can apply to filtering results, skipping sampling or both.
35+
//! Rule actions can apply to skip results, skip model updates, or both.
4136
//! This is meant to work as a bit mask so added values should be powers of 2.
42-
enum ERuleAction { E_FilterResults = 1, E_SkipSampling = 2 };
43-
44-
enum EConditionsConnective { E_Or, E_And };
37+
enum ERuleAction { E_SkipResult = 1, E_SkipModelUpdate = 2 };
4538

4639
public:
47-
//! Default constructor.
48-
//! The rule's action defaults to FILTER_RESULTS and the connective to OR.
49-
CDetectionRule();
50-
5140
//! Set the rule's action.
5241
void action(int ruleAction);
5342

54-
//! Set the conditions' connective.
55-
void conditionsConnective(EConditionsConnective connective);
43+
//! Adds a requirement for \p field not to be in \p filter for the rule to apply
44+
void includeScope(const std::string& field, const core::CPatternSet& filter);
45+
46+
//! Adds a requirement for \p field not to be in \p filter for the rule to apply
47+
void excludeScope(const std::string& field, const core::CPatternSet& filter);
5648

5749
//! Add a condition.
5850
void addCondition(const CRuleCondition& condition);
5951

60-
//! Set the target field name.
61-
void targetFieldName(const std::string& targetFieldName);
62-
63-
//! Set the target field value.
64-
void targetFieldValue(const std::string& targetFieldValue);
65-
6652
//! Check whether the rule applies on a series.
6753
//! \p action is bitwise and'ed with the m_Action member
6854
bool apply(ERuleAction action,
@@ -77,30 +63,19 @@ class MODEL_EXPORT CDetectionRule {
7763
std::string print() const;
7864

7965
private:
80-
//! Check whether the given series is in the scope
81-
//! of the rule's target.
82-
bool isInScope(const CAnomalyDetectorModel& model, std::size_t pid, std::size_t cid) const;
83-
8466
std::string printAction() const;
85-
std::string printConditionsConnective() const;
8667

8768
private:
8869
//! The rule action. It works as a bit mask so its value
8970
//! may not match any of the declared enum values but the
9071
//! corresponding bit will be 1 when an action is enabled.
91-
int m_Action;
72+
int m_Action{E_SkipResult};
73+
74+
//! The rule scope.
75+
CRuleScope m_Scope;
9276

9377
//! The conditions that trigger the rule.
9478
TRuleConditionVec m_Conditions;
95-
96-
//! The way the rule's conditions are logically connected (i.e. OR, AND).
97-
EConditionsConnective m_ConditionsConnective;
98-
99-
//! The optional target field name. Empty when not specified.
100-
std::string m_TargetFieldName;
101-
102-
//! The optional target field value. Empty when not specified.
103-
std::string m_TargetFieldValue;
10479
};
10580
}
10681
}

include/model/CRuleCondition.h

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CPatternSet;
2121
namespace model {
2222
class CAnomalyDetectorModel;
2323

24-
//! \brief A condition that may trigger a rule.
24+
//! \brief A numeric condition that may trigger a rule.
2525
//!
2626
//! DESCRIPTION:\n
2727
//! A condition has a type that determines the calculation
@@ -34,52 +34,27 @@ class MODEL_EXPORT CRuleCondition {
3434
using TPatternSetCRef = boost::reference_wrapper<const core::CPatternSet>;
3535

3636
public:
37-
enum ERuleConditionType {
38-
E_CategoricalMatch,
39-
E_CategoricalComplement,
40-
E_NumericalActual,
41-
E_NumericalTypical,
42-
E_NumericalDiffAbs,
37+
enum ERuleConditionAppliesTo {
38+
E_Actual,
39+
E_Typical,
40+
E_DiffFromTypical,
4341
E_Time
4442
};
4543

46-
enum EConditionOperator { E_LT, E_LTE, E_GT, E_GTE };
47-
48-
struct SCondition {
49-
SCondition(EConditionOperator op, double threshold);
50-
51-
bool test(double value) const;
52-
53-
EConditionOperator s_Op;
54-
double s_Threshold;
55-
};
44+
enum ERuleConditionOperator { E_LT, E_LTE, E_GT, E_GTE };
5645

5746
public:
5847
//! Default constructor.
5948
CRuleCondition();
6049

61-
//! Set the condition type.
62-
void type(ERuleConditionType ruleType);
63-
64-
//! Set the field name. Empty means it is not specified.
65-
void fieldName(const std::string& fieldName);
50+
//! Set which value the condition applies to.
51+
void appliesTo(ERuleConditionAppliesTo appliesTo);
6652

67-
//! Set the field value. Empty means it is not specified.
68-
void fieldValue(const std::string& fieldValue);
53+
//! Set the condition operator.
54+
void op(ERuleConditionOperator op);
6955

70-
//! Get the numerical condition.
71-
SCondition& condition();
72-
73-
//! Set the value filter (used for categorical only).
74-
void valueFilter(const core::CPatternSet& valueFilter);
75-
76-
//! Is the condition categorical?
77-
//! Categorical conditions are pattern match conditions i.e.
78-
//! E_CategoricalMatch and E_CategoricalComplement
79-
bool isCategorical() const;
80-
81-
//! Is the condition numerical?
82-
bool isNumerical() const;
56+
//! Set the condition value.
57+
void value(double value);
8358

8459
//! Pretty-print the condition.
8560
std::string print() const;
@@ -88,35 +63,24 @@ class MODEL_EXPORT CRuleCondition {
8863
bool test(const CAnomalyDetectorModel& model,
8964
model_t::EFeature feature,
9065
const model_t::CResultType& resultType,
91-
bool isScoped,
9266
std::size_t pid,
9367
std::size_t cid,
9468
core_t::TTime time) const;
9569

9670
private:
97-
bool checkCondition(const CAnomalyDetectorModel& model,
98-
model_t::EFeature feature,
99-
model_t::CResultType resultType,
100-
std::size_t pid,
101-
std::size_t cid,
102-
core_t::TTime time) const;
103-
std::string print(ERuleConditionType type) const;
104-
std::string print(EConditionOperator op) const;
71+
bool testValue(double value) const;
72+
std::string print(ERuleConditionAppliesTo appliesTo) const;
73+
std::string print(ERuleConditionOperator op) const;
10574

10675
private:
107-
//! The condition type.
108-
ERuleConditionType m_Type;
109-
110-
//! The numerical condition.
111-
SCondition m_Condition;
112-
113-
//! The field name. Empty when not specified.
114-
std::string m_FieldName;
76+
//! The value the condition applies to.
77+
ERuleConditionAppliesTo m_AppliesTo;
11578

116-
//! The field value. Empty when not specified.
117-
std::string m_FieldValue;
79+
//! The condition operator.
80+
ERuleConditionOperator m_Operator;
11881

119-
TPatternSetCRef m_ValueFilter;
82+
//! The condition value.
83+
double m_Value;
12084
};
12185
}
12286
}

include/model/CRuleScope.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
#ifndef INCLUDED_ml_model_CRuleScope_h
7+
#define INCLUDED_ml_model_CRuleScope_h
8+
9+
#include <model/ImportExport.h>
10+
11+
#include <core/CPatternSet.h>
12+
#include <core/CTriple.h>
13+
14+
#include <boost/ref.hpp>
15+
16+
#include <string>
17+
#include <vector>
18+
19+
namespace ml {
20+
namespace model {
21+
22+
class CAnomalyDetectorModel;
23+
24+
//! \brief The scope of the rule. It dictates the series where the rule applies.
25+
//!
26+
//! DESCRIPTION:\n
27+
//! The rule scope allows to specify when a rule applies based on the series
28+
//! split fields (partition, over, by). When the scope is empty, the rule
29+
//! applies to all series. Fields can be specified to either be included in
30+
//! the scope or excluded from it depending on whether they are contained
31+
//! in a filter (i.e. a list of string patterns). Multiple fields are combined
32+
//! with a logical AND.
33+
class MODEL_EXPORT CRuleScope {
34+
public:
35+
enum ERuleScopeFilterType { E_Include, E_Exclude };
36+
37+
using TPatternSetCRef = boost::reference_wrapper<const core::CPatternSet>;
38+
using TStrPatternSetCRefFilterTypeTriple =
39+
core::CTriple<std::string, TPatternSetCRef, ERuleScopeFilterType>;
40+
using TStrPatternSetCRefFilterTypeTripleVec = std::vector<TStrPatternSetCRefFilterTypeTriple>;
41+
42+
public:
43+
//! Default constructor.
44+
CRuleScope() = default;
45+
46+
//! Adds a requirement for \p field to be in \p filter for the rule to apply
47+
void include(const std::string& field, const core::CPatternSet& filter);
48+
49+
//! Adds a requirement for \p field not to be in \p filter for the rule to apply
50+
void exclude(const std::string& field, const core::CPatternSet& filter);
51+
52+
//! Check whether the given series is in the rule scope.
53+
bool check(const CAnomalyDetectorModel& model, std::size_t pid, std::size_t cid) const;
54+
55+
//! Pretty-print the scope.
56+
std::string print() const;
57+
58+
private:
59+
//! A vector that holds the triple of the field, filter and its type.
60+
TStrPatternSetCRefFilterTypeTripleVec m_Scope;
61+
};
62+
}
63+
}
64+
65+
#endif // INCLUDED_ml_model_CRuleScope_h

0 commit comments

Comments
 (0)