为什么我的眼里常含泪水?因为我对这土地爱得深沉……
本文基于Github :ad4j:Anomaly Detection For Java
项目中有完整代码示例,欢迎Star、Issue、提交PR,获得Contributor勋章,共同成长。
系列文章导航:
- 指标检测(一):绝对值/离群值异常检测
- 指标检测(二):波动异常检测-基于二阶导和距离寻找最大弯曲点
- 指标检测(三):趋势异常检测-基于Mann-Kendall检验
- 指标检测(四):业务阈值检测-基于规则引擎的业务异常检测
一、概述
概述请参考系列文章(一)的概述
本文将重点介绍 ad4j:Anomaly Detection For Java 项目中的基于规则引擎的检测算法。
本文主要介绍基于业务阈值设定的异常检测,作为自动化异常检测的业务补充监控方案。是的整套检测框架全面覆盖各种应用场景。
二、基于业务阈值的异常检测
1.原理
类似规则引擎的方案
-
(1)设定规则和规则集:
- 规则集:支持规则以任意逻辑形式(OR(||)、AND(&&))的组合成规则集,例如 R u l e 3 Rule3 Rule3 o r or or ( R u l e 1 Rule1 Rule1 a n d and and R u l e 2 Rule2 Rule2)
- 规则 R u l e Rule Rule: x i > F a c t o r ∗ S x_i >Factor * S xi>Factor∗S。
其中,比较符号支持(>,>=,=,<,<=) , F a c t o r Factor Factor是因子系数, S S S是指标数值统计量,支持:
S S S统计量类型 | 说明 |
---|---|
constant | 常量(即数值当前值) |
min | 最小值 |
max | 最大值 |
mean | 均值 |
var | 方差 |
std | 标准差 |
quantile | 分位值 |
- (2)循环递归检测
规则引擎内部解析规则后,会按照规则进行判定是否符合规则异常。
2.计算过程
- (1)解析规则:将规则配置解析为规则树
- (2)规则引擎判断:递归规则树,依次从叶子节点判定规则,将当前节点结果 与 同级节点结果进行逻辑(and,or)判断,逐步递归只根节点,获取到最终规则判定结果。
3.数据计算示例
数据准备:时间序列数据: X = 1.0 , 2.0 , 3.0 , 4.0 X={1.0,2.0,3.0,4.0} X=1.0,2.0,3.0,4.0。
- (1)设置规则:
>= 5 * constant || <= 1 * constant || (> 1 * min && < 1 * max)
- (2)解析规则:规则树如下
(3)循环遍历指标,从叶子节点(图中自左向右进行逻辑判断)开始判断,得到最终布尔值结果,即是否满足业务规则集。
计算可知:1.0,2.0,3.0
满足规则。
4.代码示例
代码来自Github开源项目 ad4j:Anomaly Detection For Java 欢迎star,欢迎提issue交流。
a.关键代码
完整代码可去项目中查看ADM_ThresholdRule.java
规则解析过程:
/**
* data case:{"logicType":"and","ruleGroup":[{"factor":100,"thresholdType":"std","compareType":">"}]}
* @param thresholdRuleSetJson adm.threshold_rule.set config json
* @return ThresholdRuleBase
*/
public static ThresholdRuleBase generalThresholdRule(JSONObject thresholdRuleSetJson) {
if (Objects.isNull(thresholdRuleSetJson)) {
return null;
}
if (thresholdRuleSetJson.containsKey("ruleGroup")) {
ThresholdRuleGroup ruleGroup = new ThresholdRuleGroup(LogicType.parse(thresholdRuleSetJson.getString("logicType")));
JSONArray jsonArr = thresholdRuleSetJson.getJSONArray("ruleGroup");
for (int i = 0; i < jsonArr.size(); i++) {
ThresholdRuleBase rb = generalThresholdRule(jsonArr.getJSONObject(i));
if(Objects.nonNull(rb)){
ruleGroup.addRules(rb);
}
}
return ruleGroup;
} else {
return new ThresholdRule(ThresholdType.parse(thresholdRuleSetJson.getString("thresholdType")), CompareType.parse(thresholdRuleSetJson.getString("compareType")), thresholdRuleSetJson.getDouble("factor"));
}
}
规则引擎计算过程:
private boolean judgeHasAnomaly(List<IndicatorSeries> sortList, DescriptiveStatistics stats, ThresholdRuleBase currentRule, IndicatorSeries currentIndicator) {
if (Objects.isNull(currentRule.getThresholdRules())) {
ThresholdRule rule = (ThresholdRule) currentRule;
return thresholdCompare(sortList, stats, rule, currentIndicator);
} else {
Boolean ruleGroupResult = null;
ThresholdRuleGroup ruleGroup = (ThresholdRuleGroup) currentRule;
for (ThresholdRuleBase rule : ruleGroup.getThresholdRules()) {
boolean hasAnomaly = judgeHasAnomaly(sortList, stats, rule, currentIndicator);
if (ruleGroup.getLogicType() == LogicType.AND) {
ruleGroupResult = ruleGroupResult == null ? hasAnomaly : ruleGroupResult && hasAnomaly;
} else if (ruleGroup.getLogicType() == LogicType.OR) {
ruleGroupResult = ruleGroupResult == null ? hasAnomaly : ruleGroupResult || hasAnomaly;
}
}
return Boolean.TRUE.equals(ruleGroupResult);
}
}
b.使用示例
- 手动组装规则方式
@Test
public void testADM_ThresholdRule(){
double[] data = new double[]{1.0,2.0,3.0,4.0};
List<IndicatorSeries> indicatorSeries = IndicatorSeriesUtil.transferFromArray(data);
AbstractADM model = new ADM_ThresholdRule();
AnomalyDetectionContext adContext = AnomalyDetectionContext.createDefault();
adContext.putConfig(ADMConfigs.ADM_THRESHOLD_RULE_USE, true);
ThresholdRuleGroup ruleGroupL2 = new ThresholdRuleGroup(LogicType.AND);
ThresholdRuleBase ruleBaseL2_1 = new ThresholdRule(ThresholdType.MIN, CompareType.GREATER, 1.0);
ThresholdRuleBase ruleBaseL2_2 = new ThresholdRule(ThresholdType.MAX, CompareType.LESS, 1.0);
ruleGroupL2.addRules(ruleBaseL2_1);
ruleGroupL2.addRules(ruleBaseL2_2);
ThresholdRuleBase ruleBaseL1_1 = new ThresholdRule(ThresholdType.CONSTANT, CompareType.GREATER_OR_EQ, 5.0);
ThresholdRuleBase ruleBaseL1_2 = new ThresholdRule(ThresholdType.CONSTANT, CompareType.LESS_OR_EQ, 1.0);
ThresholdRuleGroup ruleGroupL1 = new ThresholdRuleGroup(LogicType.OR);
ruleGroupL1.addRules(ruleBaseL1_1);
ruleGroupL1.addRules(ruleBaseL1_2);
ruleGroupL1.addRules(ruleGroupL2);
adContext.putConfig(ADMConfigs.ADM_THRESHOLD_RULE_SET, ruleGroupL1);
model.init(adContext);
model.checkCompatibility(indicatorSeries, log);
IndicatorEvaluateInfo evaluate = model.evaluate(indicatorSeries, log);
IndicatorSeriesUtil.print(evaluate);
}
如预期检测出结果:
INFLUENCE_NEGATIVE是相对于均值的比较,大于均值则INFLUENCE_POSITIVE,否则INFLUENCE_NEGATIVE,详细可去github源码查看,或评论区讨论。
anomalyDetectionModel='MODEL_ADM_ThresholdRule'
, anomalyType=TYPE_THRESHOLD
, hasAnomaly=true
, anomalySeriesList=[[INFLUENCE_NEGATIVE:0, 1.0, 0], [INFLUENCE_NEGATIVE:1, 2.0, 1], [INFLUENCE_POSITIVE:2, 3.0, 2]]
- json配置方式
后续将会优化直接解析这样的配置方案:
>= 5 * constant || <= 1 * constant || (> 1 * min && < 1 * max)
欢迎朋友们提交PR加入Contributor来实现这一Feature。
@Test
public void testADM_ThresholdRule2(){
double[] data = new double[]{1.0,2.0,3.0,4.0};
List<IndicatorSeries> indicatorSeries = IndicatorSeriesUtil.transferFromArray(data);
AbstractADM model = new ADM_ThresholdRule();
String propertiesJsonStr = "{\"adm.quantile.use\":false,\"adm.threshold_rule.use\":true,\"adm.threshold_rule.set\":{\"logicType\":\"or\",\"ruleGroup\":[{\"factor\":5.0,\"thresholdType\":\"constant\",\"compareType\":\">=\"},{\"factor\":1.0,\"thresholdType\":\"constant\",\"compareType\":\"<=\"}]}}";
JSONObject propertiesJson = JSONObject.parseObject(propertiesJsonStr);
AnomalyDetectionContext adContext = AnomalyDetectionContext.create(propertiesJson);
model.init(adContext);
model.checkCompatibility(indicatorSeries, log);
IndicatorEvaluateInfo evaluate = model.evaluate(indicatorSeries, log);
IndicatorSeriesUtil.print(evaluate);
}
三、总结
- 基于业务规则阈值判断的异常检测,是对无监督自动化异常检测的一种人工补充。
- 此方案依赖于专家规则的配置,建议搭配无监督自动化异常检测方案使用。