Browse Source

Segment info #693 (#700)

pull/1/head
Alexandr Velikiy 5 years ago committed by Evgeny Smyshlyaev
parent
commit
5374c45b36
  1. 6
      analytics/analytics/analytic_types/segment.py
  2. 1
      analytics/analytics/detectors/anomaly_detector.py
  3. 30
      analytics/analytics/detectors/threshold_detector.py
  4. 1
      analytics/analytics/utils/common.py
  5. 7
      analytics/tests/test_detectors.py
  6. 4
      server/src/controllers/analytics_controller.ts
  7. 8
      server/src/models/segment_model.ts
  8. 14
      server/src/services/alert_service.ts
  9. 2
      server/src/services/notification_service.ts

6
analytics/analytics/analytic_types/segment.py

@ -5,14 +5,16 @@ class Segment:
Used for segment manipulation instead of { 'from': ..., 'to': ... } dict
'''
def __init__(self, from_timestamp: int, to_timestamp: int):
def __init__(self, from_timestamp: int, to_timestamp: int, message: str = None):
if to_timestamp < from_timestamp:
raise ValueError(f'Can`t create segment with to < from: {to_timestamp} < {from_timestamp}')
self.from_timestamp = from_timestamp
self.to_timestamp = to_timestamp
self.message = message
def to_json(self):
return {
'from': self.from_timestamp,
'to': self.to_timestamp
'to': self.to_timestamp,
'message': self.message
}

1
analytics/analytics/detectors/anomaly_detector.py

@ -116,6 +116,7 @@ class AnomalyDetector(ProcessingDetector):
segments = [Segment(
utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[0]]),
utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[1]]),
f'{data[segment[0]]} out of bound'
) for segment in segments]
last_dataframe_time = dataframe.iloc[-1]['timestamp']

30
analytics/analytics/detectors/threshold_detector.py

@ -1,5 +1,6 @@
import logging as log
import operator
import pandas as pd
import numpy as np
from typing import Optional, List
@ -49,24 +50,23 @@ class ThresholdDetector(Detector):
# TODO: merge segments
if pd.isnull(current_value):
if condition == 'NO_DATA':
segment.message = 'NO_DATA detected'
segments.append(segment)
continue
if condition == '>':
if current_value > value:
segments.append(segment)
elif condition == '>=':
if current_value >= value:
segments.append(segment)
elif condition == '=':
if current_value == value:
segments.append(segment)
elif condition == '<=':
if current_value <= value:
segments.append(segment)
elif condition == '<':
if current_value < value:
segments.append(segment)
comparators = {
'>': operator.gt,
'<': operator.lt,
'=': operator.eq,
'>=': operator.ge,
'<=': operator.le
}
assert condition in comparators.keys(), f'condition {condition} not allowed'
if comparators[condition](current_value, value):
segment.message = f"{current_value} {condition} threshold's value {value}"
segments.append(segment)
last_entry = dataframe.iloc[-1]
last_detection_time = utils.convert_pd_timestamp_to_ms(last_entry['timestamp'])

1
analytics/analytics/utils/common.py

@ -137,6 +137,7 @@ def merge_intersecting_segments(segments: List[Segment], time_step: int) -> List
previous_segment = segments[0]
for i in range(1, len(segments)):
if segments[i].from_timestamp <= previous_segment.to_timestamp + time_step:
segments[i].message = segments[-1].message
segments[i].from_timestamp = min(previous_segment.from_timestamp, segments[i].from_timestamp)
segments[i].to_timestamp = max(previous_segment.to_timestamp, segments[i].to_timestamp)
segments[i - 1] = None

7
analytics/tests/test_detectors.py

@ -2,6 +2,7 @@ import unittest
import pandas as pd
from detectors import pattern_detector, threshold_detector, anomaly_detector
from analytic_types.detector_typing import DetectionResult
class TestPatternDetector(unittest.TestCase):
@ -44,6 +45,8 @@ class TestAnomalyDetector(unittest.TestCase):
'timeStep': 1
}
detector = anomaly_detector.AnomalyDetector('test_id')
detect_result = detector.detect(dataframe, cache)
detect_result: DetectionResult = detector.detect(dataframe, cache)
detected_segments = list(map(lambda s: {'from': s.from_timestamp, 'to': s.to_timestamp}, detect_result.segments))
result = [{ 'from': 1523889000005.0, 'to': 1523889000005.0 }]
self.assertEqual(result, detect_result.to_json()['segments'])
self.assertEqual(result, detected_segments)

4
server/src/controllers/analytics_controller.ts

@ -451,9 +451,9 @@ async function processDetectionResult(analyticUnitId: AnalyticUnit.AnalyticUnitI
}
console.log(`got detection result for ${analyticUnitId} with ${detectionResult.segments.length} segments`);
const sortedSegments: {from, to}[] = _.sortBy(detectionResult.segments, 'from');
const sortedSegments: {from, to, message?}[] = _.sortBy(detectionResult.segments, 'from');
const segments = sortedSegments.map(
segment => new Segment.Segment(analyticUnitId, segment.from, segment.to, false, false)
segment => new Segment.Segment(analyticUnitId, segment.from, segment.to, false, false, undefined, segment.message)
);
return {

8
server/src/models/segment_model.ts

@ -17,7 +17,7 @@ export class Segment {
public labeled: boolean = false,
public deleted: boolean = false,
public id?: SegmentId,
public params?: any
public message?: string
) {
if(analyticUnitId === undefined) {
throw new Error('AnalyticUnitId is undefined');
@ -43,7 +43,8 @@ export class Segment {
from: this.from,
to: this.to,
labeled: this.labeled,
deleted: this.deleted
deleted: this.deleted,
message: this.message
};
}
@ -54,7 +55,8 @@ export class Segment {
return new Segment(
obj.analyticUnitId,
+obj.from, +obj.to,
obj.labeled, obj.deleted, obj._id
obj.labeled, obj.deleted,
obj._id, obj.message
);
}

14
server/src/services/alert_service.ts

@ -33,7 +33,8 @@ export class Alert {
analyticUnitId: this.analyticUnit.id,
grafanaUrl,
from: segment.from,
to: segment.to
to: segment.to,
message: segment.message
};
return alert;
@ -46,7 +47,8 @@ export class Alert {
``,
`From: ${new Date(meta.from)}`,
`To: ${new Date(meta.to)}`,
`ID: ${meta.analyticUnitId}`
`ID: ${meta.analyticUnitId}`,
`Message: ${meta.message}`
].join('\n');
}
}
@ -111,12 +113,8 @@ class ThresholdAlert extends Alert {
`ID: ${meta.analyticUnitId}`
].join('\n');
if(meta.params !== undefined) {
const metrics = `
Metrics:
${this.analyticUnit.metric.targets[0].expr}: ${meta.params.value}
`;
message += metrics;
if(meta.message !== undefined) {
message += meta.message;
}
return message;
}

2
server/src/services/notification_service.ts

@ -25,7 +25,7 @@ export declare type AnalyticMeta = {
grafanaUrl: string,
from: number,
to: number
params?: any,
message?: any,
regionImage?: any
}

Loading…
Cancel
Save