use of com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO in project pinot by linkedin.
the class AnomalyResource method viewRawAnomaliesInRange.
//View raw anomalies for collection
@GET
@Path("/raw-anomalies/view")
@Produces(MediaType.APPLICATION_JSON)
public String viewRawAnomaliesInRange(@QueryParam("functionId") String functionId, @QueryParam("dataset") String dataset, @QueryParam("startTimeIso") String startTimeIso, @QueryParam("endTimeIso") String endTimeIso, @QueryParam("metric") String metric) throws JsonProcessingException {
if (StringUtils.isBlank(functionId) && StringUtils.isBlank(dataset)) {
throw new IllegalArgumentException("must provide dataset or functionId");
}
DateTime endTime = DateTime.now();
if (StringUtils.isNotEmpty(endTimeIso)) {
endTime = ISODateTimeFormat.dateTimeParser().parseDateTime(endTimeIso);
}
DateTime startTime = endTime.minusDays(7);
if (StringUtils.isNotEmpty(startTimeIso)) {
startTime = ISODateTimeFormat.dateTimeParser().parseDateTime(startTimeIso);
}
List<RawAnomalyResultDTO> rawAnomalyResults = new ArrayList<>();
if (StringUtils.isNotBlank(functionId)) {
rawAnomalyResults = rawAnomalyResultDAO.findAllByTimeAndFunctionId(startTime.getMillis(), endTime.getMillis(), Long.valueOf(functionId));
} else if (StringUtils.isNotBlank(dataset)) {
List<AnomalyFunctionDTO> anomalyFunctions = anomalyFunctionDAO.findAllByCollection(dataset);
List<Long> functionIds = new ArrayList<>();
for (AnomalyFunctionDTO anomalyFunction : anomalyFunctions) {
if (StringUtils.isNotBlank(metric) && !anomalyFunction.getTopicMetric().equals(metric)) {
continue;
}
functionIds.add(anomalyFunction.getId());
}
for (Long id : functionIds) {
rawAnomalyResults.addAll(rawAnomalyResultDAO.findAllByTimeAndFunctionId(startTime.getMillis(), endTime.getMillis(), id));
}
}
String response = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(rawAnomalyResults);
return response;
}
use of com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO in project pinot by linkedin.
the class AnomalyResource method getAnomalyMergedResultTimeSeries.
/**
* Returns the time series for the given anomaly.
*
* If viewWindowStartTime and/or viewWindowEndTime is not given, then a window is padded automatically. The padded
* windows is half of the anomaly window size. For instance, if the anomaly lasts for 4 hours, then the pad window
* size is 2 hours. The max padding size is 1 day.
*
* @param anomalyResultId the id of the given anomaly
* @param viewWindowStartTime start time of the time series, inclusive
* @param viewWindowEndTime end time of the time series, inclusive
* @return the time series of the given anomaly
* @throws Exception when it fails to retrieve collection, i.e., dataset, information
*/
@GET
@Path("/anomaly-merged-result/timeseries/{anomaly_merged_result_id}")
public AnomalyTimelinesView getAnomalyMergedResultTimeSeries(@NotNull @PathParam("anomaly_merged_result_id") long anomalyResultId, @NotNull @QueryParam("aggTimeGranularity") String aggTimeGranularity, @QueryParam("start") long viewWindowStartTime, @QueryParam("end") long viewWindowEndTime) throws Exception {
boolean loadRawAnomalies = false;
MergedAnomalyResultDTO anomalyResult = anomalyMergedResultDAO.findById(anomalyResultId, loadRawAnomalies);
DimensionMap dimensions = anomalyResult.getDimensions();
AnomalyFunctionDTO anomalyFunctionSpec = anomalyResult.getFunction();
BaseAnomalyFunction anomalyFunction = anomalyFunctionFactory.fromSpec(anomalyFunctionSpec);
// By default, the padding window size is half of the anomaly window.
if (viewWindowStartTime == 0 || viewWindowEndTime == 0) {
long anomalyWindowStartTime = anomalyResult.getStartTime();
long anomalyWindowEndTime = anomalyResult.getEndTime();
long bucketMillis = TimeUnit.MILLISECONDS.convert(anomalyFunctionSpec.getBucketSize(), anomalyFunctionSpec.getBucketUnit());
long bucketCount = (anomalyWindowEndTime - anomalyWindowStartTime) / bucketMillis;
long paddingMillis = Math.max(1, (bucketCount / 2)) * bucketMillis;
if (paddingMillis > TimeUnit.DAYS.toMillis(1)) {
paddingMillis = TimeUnit.DAYS.toMillis(1);
}
if (viewWindowStartTime == 0) {
viewWindowStartTime = anomalyWindowStartTime - paddingMillis;
}
if (viewWindowEndTime == 0) {
viewWindowEndTime = anomalyWindowEndTime + paddingMillis;
}
}
TimeGranularity timeGranularity = Utils.getAggregationTimeGranularity(aggTimeGranularity, anomalyFunctionSpec.getCollection());
long bucketMillis = timeGranularity.toMillis();
// ThirdEye backend is end time exclusive, so one more bucket is appended to make end time inclusive for frontend.
viewWindowEndTime += bucketMillis;
long maxDataTime = collectionMaxDataTimeCache.get(anomalyResult.getCollection());
if (viewWindowEndTime > maxDataTime) {
viewWindowEndTime = (anomalyResult.getEndTime() > maxDataTime) ? anomalyResult.getEndTime() : maxDataTime;
}
AnomalyDetectionInputContext adInputContext = TimeBasedAnomalyMerger.fetchDataByDimension(viewWindowStartTime, viewWindowEndTime, dimensions, anomalyFunction, anomalyMergedResultDAO, overrideConfigDAO, false);
MetricTimeSeries metricTimeSeries = adInputContext.getDimensionKeyMetricTimeSeriesMap().get(dimensions);
if (metricTimeSeries == null) {
// the timeseries for the given anomaly
return new AnomalyTimelinesView();
}
// Transform time series with scaling factor
List<ScalingFactor> scalingFactors = adInputContext.getScalingFactors();
if (CollectionUtils.isNotEmpty(scalingFactors)) {
Properties properties = anomalyFunction.getProperties();
MetricTransfer.rescaleMetric(metricTimeSeries, viewWindowStartTime, scalingFactors, anomalyFunctionSpec.getTopicMetric(), properties);
}
List<MergedAnomalyResultDTO> knownAnomalies = adInputContext.getKnownMergedAnomalies().get(dimensions);
// Known anomalies are ignored (the null parameter) because 1. we can reduce users' waiting time and 2. presentation
// data does not need to be as accurate as the one used for detecting anomalies
AnomalyTimelinesView anomalyTimelinesView = anomalyFunction.getTimeSeriesView(metricTimeSeries, bucketMillis, anomalyFunctionSpec.getTopicMetric(), viewWindowStartTime, viewWindowEndTime, knownAnomalies);
// Generate summary for frontend
List<TimeBucket> timeBuckets = anomalyTimelinesView.getTimeBuckets();
if (timeBuckets.size() > 0) {
TimeBucket firstBucket = timeBuckets.get(0);
anomalyTimelinesView.addSummary("currentStart", Long.toString(firstBucket.getCurrentStart()));
anomalyTimelinesView.addSummary("baselineStart", Long.toString(firstBucket.getBaselineStart()));
TimeBucket lastBucket = timeBuckets.get(timeBuckets.size() - 1);
anomalyTimelinesView.addSummary("currentEnd", Long.toString(lastBucket.getCurrentStart()));
anomalyTimelinesView.addSummary("baselineEnd", Long.toString(lastBucket.getBaselineEnd()));
}
return anomalyTimelinesView;
}
use of com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO in project pinot by linkedin.
the class AnomalyResource method viewAnomalyFunctions.
/************* CRUD for anomaly functions of collection **********************************************/
// View all anomaly functions
@GET
@Path("/anomaly-function/view")
public List<AnomalyFunctionDTO> viewAnomalyFunctions(@NotNull @QueryParam("dataset") String dataset, @QueryParam("metric") String metric) {
if (StringUtils.isBlank(dataset)) {
throw new IllegalArgumentException("dataset is a required query param");
}
List<AnomalyFunctionDTO> anomalyFunctionSpecs = anomalyFunctionDAO.findAllByCollection(dataset);
List<AnomalyFunctionDTO> anomalyFunctions = anomalyFunctionSpecs;
if (StringUtils.isNotEmpty(metric)) {
anomalyFunctions = new ArrayList<>();
for (AnomalyFunctionDTO anomalyFunctionSpec : anomalyFunctionSpecs) {
if (metric.equals(anomalyFunctionSpec.getTopicMetric())) {
anomalyFunctions.add(anomalyFunctionSpec);
}
}
}
return anomalyFunctions;
}
use of com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO in project pinot by linkedin.
the class EmailResource method removeFunctionFromEmail.
@POST
@Path("{emailId}/delete/{functionId}")
public void removeFunctionFromEmail(@PathParam("emailId") Long emailId, @PathParam("functionId") Long functionId) {
AnomalyFunctionDTO function = functionDAO.findById(functionId);
EmailConfigurationDTO emailConfiguration = emailDAO.findById(emailId);
if (function != null && emailConfiguration != null) {
if (emailConfiguration.getFunctions().contains(function)) {
emailConfiguration.getFunctions().remove(function);
emailDAO.update(emailConfiguration);
}
}
}
use of com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO in project pinot by linkedin.
the class EmailResource method addFunctionInEmail.
@POST
@Path("{emailId}/add/{functionId}")
public void addFunctionInEmail(@PathParam("emailId") Long emailId, @PathParam("functionId") Long functionId) {
AnomalyFunctionDTO function = functionDAO.findById(functionId);
EmailConfigurationDTO emailConfiguration = emailDAO.findById(emailId);
List<EmailConfigurationDTO> emailConfigurationsWithFunction = emailDAO.findByFunctionId(functionId);
for (EmailConfigurationDTO emailConfigurationDTO : emailConfigurationsWithFunction) {
emailConfigurationDTO.getFunctions().remove(function);
emailDAO.update(emailConfigurationDTO);
}
if (function != null && emailConfiguration != null) {
if (!emailConfiguration.getFunctions().contains(function)) {
emailConfiguration.getFunctions().add(function);
emailDAO.update(emailConfiguration);
}
} else {
throw new IllegalArgumentException("function or email not found for email : " + emailId + " function : " + functionId);
}
}
Aggregations