Search in sources :

Example 36 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class FetchMetricDataAndExistingAnomaliesTool method fetchMergedAnomaliesInRangeByFunctionId.

public List<ResultNode> fetchMergedAnomaliesInRangeByFunctionId(long functionId, DateTime startTime, DateTime endTime) {
    AnomalyFunctionDTO anomalyFunction = anomalyFunctionDAO.findById(functionId);
    LOG.info("Loading merged anaomaly results of functionId {} from db...", functionId);
    List<ResultNode> resultNodes = new ArrayList<>();
    if (anomalyFunction == null) {
        // no such function
        return resultNodes;
    }
    List<MergedAnomalyResultDTO> mergedResults = mergedAnomalyResultDAO.findByStartTimeInRangeAndFunctionId(startTime.getMillis(), endTime.getMillis(), functionId);
    for (MergedAnomalyResultDTO mergedResult : mergedResults) {
        ResultNode res = new ResultNode();
        res.functionId = functionId;
        res.functionName = anomalyFunction.getFunctionName();
        res.startTime = new DateTime(mergedResult.getStartTime());
        res.endTime = new DateTime(mergedResult.getEndTime());
        res.dimensions = mergedResult.getDimensions();
        res.setFilters(anomalyFunction.getFilters());
        res.severity = mergedResult.getWeight();
        AnomalyFeedbackDTO feedback = mergedResult.getFeedback();
        res.feedbackType = (feedback == null) ? null : feedback.getFeedbackType();
        resultNodes.add(res);
    }
    return resultNodes;
}
Also used : MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) ArrayList(java.util.ArrayList) AnomalyFeedbackDTO(com.linkedin.thirdeye.datalayer.dto.AnomalyFeedbackDTO) AnomalyFunctionDTO(com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO) DateTime(org.joda.time.DateTime)

Example 37 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class GenerateAnomalyReport method buildReport.

void buildReport() {
    List<MergedAnomalyResultDTO> anomalies = new ArrayList<>();
    for (String collection : collections) {
        anomalies.addAll(anomalyResultManager.findByCollectionTime(collection, startTime.getTime(), endTime.getTime(), false));
    }
    if (anomalies.size() == 0) {
        System.out.println("No anomalies found, please check the report config... exiting");
    } else {
        Set<String> metrics = new HashSet<>();
        int alertedAnomalies = 0;
        int feedbackCollected = 0;
        int trueAlert = 0;
        int falseAlert = 0;
        int nonActionable = 0;
        List<AnomalyReportDTO> anomalyReportDTOList = new ArrayList<>();
        for (MergedAnomalyResultDTO anomaly : anomalies) {
            metrics.add(anomaly.getMetric());
            if (anomaly.getFeedback() != null) {
                feedbackCollected++;
                if (anomaly.getFeedback().getFeedbackType().equals(AnomalyFeedbackType.ANOMALY)) {
                    trueAlert++;
                } else if (anomaly.getFeedback().getFeedbackType().equals(AnomalyFeedbackType.NOT_ANOMALY)) {
                    falseAlert++;
                } else {
                    nonActionable++;
                }
            }
            String feedbackVal = getFeedback(anomaly.getFeedback() == null ? "NA" : anomaly.getFeedback().getFeedbackType().name());
            AnomalyReportDTO anomalyReportDTO = new AnomalyReportDTO(String.valueOf(anomaly.getId()), feedbackVal, String.format("%+.2f", anomaly.getWeight()), anomaly.getMetric(), new Date(anomaly.getStartTime()).toString(), String.format("%.2f", getTimeDiffInHours(anomaly.getStartTime(), anomaly.getEndTime())), getAnomalyURL(anomaly));
            // include notified alerts only in the email
            if (anomaly.isNotified()) {
                alertedAnomalies++;
                anomalyReportDTOList.add(anomalyReportDTO);
            }
        }
        Map<String, Object> templateData = new HashMap<>();
        templateData.put("startTime", startTime.toString());
        templateData.put("endTime", endTime.toString());
        templateData.put("anomalyCount", anomalies.size());
        templateData.put("metricsCount", metrics.size());
        templateData.put("notifiedCount", alertedAnomalies);
        templateData.put("feedbackCount", feedbackCollected);
        templateData.put("trueAlertCount", trueAlert);
        templateData.put("falseAlertCount", falseAlert);
        templateData.put("nonActionableCount", nonActionable);
        templateData.put("datasets", String.join(", ", collections));
        templateData.put("anomalyDetails", anomalyReportDTOList);
        buildEmailTemplateAndSendAlert(templateData);
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Date(java.util.Date) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) HashSet(java.util.HashSet)

Example 38 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AnomaliesResource method getAnomalyDetails.

/**
   * Generates Anomaly Details for each merged anomaly
   * @param mergedAnomaly
   * @param datasetConfig
   * @param timeSeriesDateFormatter
   * @param startEndDateFormatterHours
   * @param startEndDateFormatterDays
   * @param externalUrl
   * @return
   */
private AnomalyDetails getAnomalyDetails(MergedAnomalyResultDTO mergedAnomaly, DatasetConfigDTO datasetConfig, DateTimeFormatter timeSeriesDateFormatter, DateTimeFormatter startEndDateFormatterHours, DateTimeFormatter startEndDateFormatterDays, String externalUrl) throws Exception {
    String dataset = datasetConfig.getDataset();
    String metricName = mergedAnomaly.getMetric();
    AnomalyFunctionDTO anomalyFunctionSpec = anomalyFunctionDAO.findById(mergedAnomaly.getFunctionId());
    BaseAnomalyFunction anomalyFunction = anomalyFunctionFactory.fromSpec(anomalyFunctionSpec);
    String aggGranularity = constructAggGranularity(datasetConfig);
    long anomalyStartTime = mergedAnomaly.getStartTime();
    long anomalyEndTime = mergedAnomaly.getEndTime();
    TimeRange range = getTimeseriesOffsetedTimes(anomalyStartTime, anomalyEndTime, datasetConfig);
    long currentStartTime = range.getStart();
    long currentEndTime = range.getEnd();
    DimensionMap dimensions = mergedAnomaly.getDimensions();
    TimeGranularity timeGranularity = Utils.getAggregationTimeGranularity(aggGranularity, anomalyFunctionSpec.getCollection());
    long bucketMillis = timeGranularity.toMillis();
    AnomalyDetails anomalyDetails = null;
    try {
        AnomalyDetectionInputContext adInputContext = TimeBasedAnomalyMerger.fetchDataByDimension(currentStartTime, currentEndTime, dimensions, anomalyFunction, mergedAnomalyResultDAO, overrideConfigDAO, true);
        MetricTimeSeries metricTimeSeries = adInputContext.getDimensionKeyMetricTimeSeriesMap().get(dimensions);
        // Transform time series with scaling factor
        List<ScalingFactor> scalingFactors = adInputContext.getScalingFactors();
        if (CollectionUtils.isNotEmpty(scalingFactors)) {
            Properties properties = anomalyFunction.getProperties();
            MetricTransfer.rescaleMetric(metricTimeSeries, currentStartTime, 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(), currentStartTime, currentEndTime, knownAnomalies);
        anomalyDetails = constructAnomalyDetails(metricName, dataset, datasetConfig, mergedAnomaly, anomalyFunctionSpec, currentStartTime, currentEndTime, anomalyTimelinesView, timeSeriesDateFormatter, startEndDateFormatterHours, startEndDateFormatterDays, externalUrl);
    } catch (Exception e) {
        LOG.error("Exception in constructing anomaly wrapper for anomaly {}", mergedAnomaly.getId(), e);
    }
    return anomalyDetails;
}
Also used : BaseAnomalyFunction(com.linkedin.thirdeye.detector.function.BaseAnomalyFunction) AnomalyDetails(com.linkedin.thirdeye.dashboard.resources.v2.pojo.AnomalyDetails) MetricTimeSeries(com.linkedin.thirdeye.api.MetricTimeSeries) ScalingFactor(com.linkedin.thirdeye.detector.metric.transfer.ScalingFactor) AnomalyTimelinesView(com.linkedin.thirdeye.anomaly.views.AnomalyTimelinesView) Properties(java.util.Properties) TimeoutException(java.util.concurrent.TimeoutException) JSONException(org.json.JSONException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) TimeRange(com.linkedin.thirdeye.api.TimeRange) AnomalyDetectionInputContext(com.linkedin.thirdeye.anomaly.detection.AnomalyDetectionInputContext) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) TimeGranularity(com.linkedin.thirdeye.api.TimeGranularity) DimensionMap(com.linkedin.thirdeye.api.DimensionMap) AnomalyFunctionDTO(com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO)

Example 39 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class AnomaliesResource method constructAnomaliesWrapperFromMergedAnomalies.

/**
   * Constructs AnomaliesWrapper object from a list of merged anomalies
   * @param mergedAnomalies
   * @return
   * @throws ExecutionException
   */
private AnomaliesWrapper constructAnomaliesWrapperFromMergedAnomalies(List<MergedAnomalyResultDTO> mergedAnomalies, int pageNumber) throws ExecutionException {
    AnomaliesWrapper anomaliesWrapper = new AnomaliesWrapper();
    anomaliesWrapper.setTotalAnomalies(mergedAnomalies.size());
    LOG.info("Total anomalies: {}", mergedAnomalies.size());
    // TODO: get page number and page size from client
    int pageSize = DEFAULT_PAGE_SIZE;
    int maxPageNumber = (mergedAnomalies.size() - 1) / pageSize + 1;
    if (pageNumber > maxPageNumber) {
        pageNumber = maxPageNumber;
    }
    if (pageNumber < 1) {
        pageNumber = 1;
    }
    int fromIndex = (pageNumber - 1) * pageSize;
    int toIndex = pageNumber * pageSize;
    if (toIndex > mergedAnomalies.size()) {
        toIndex = mergedAnomalies.size();
    }
    // Show most recent anomalies first, i.e., the anomaly whose end time is most recent then largest id shown at top
    Collections.sort(mergedAnomalies, new MergedAnomalyEndTimeComparator().reversed());
    List<MergedAnomalyResultDTO> displayedAnomalies = mergedAnomalies.subList(fromIndex, toIndex);
    anomaliesWrapper.setNumAnomaliesOnPage(displayedAnomalies.size());
    LOG.info("Page number: {} Page size: {} Num anomalies on page: {}", pageNumber, pageSize, displayedAnomalies.size());
    // for each anomaly, create anomaly details
    List<Future<AnomalyDetails>> anomalyDetailsListFutures = new ArrayList<>();
    for (MergedAnomalyResultDTO mergedAnomaly : displayedAnomalies) {
        Callable<AnomalyDetails> callable = new Callable<AnomalyDetails>() {

            @Override
            public AnomalyDetails call() throws Exception {
                String dataset = mergedAnomaly.getCollection();
                DatasetConfigDTO datasetConfig = CACHE_REGISTRY.getDatasetConfigCache().get(dataset);
                DateTimeFormatter timeSeriesDateFormatter = DateTimeFormat.forPattern(TIME_SERIES_DATE_FORMAT).withZone(Utils.getDataTimeZone(dataset));
                DateTimeFormatter startEndDateFormatterDays = DateTimeFormat.forPattern(START_END_DATE_FORMAT_DAYS).withZone(Utils.getDataTimeZone(dataset));
                DateTimeFormatter startEndDateFormatterHours = DateTimeFormat.forPattern(START_END_DATE_FORMAT_HOURS).withZone(Utils.getDataTimeZone(dataset));
                return getAnomalyDetails(mergedAnomaly, datasetConfig, timeSeriesDateFormatter, startEndDateFormatterHours, startEndDateFormatterDays, getExternalURL(mergedAnomaly));
            }
        };
        anomalyDetailsListFutures.add(threadPool.submit(callable));
    }
    List<AnomalyDetails> anomalyDetailsList = new ArrayList<>();
    for (Future<AnomalyDetails> anomalyDetailsFuture : anomalyDetailsListFutures) {
        try {
            AnomalyDetails anomalyDetails = anomalyDetailsFuture.get(120, TimeUnit.SECONDS);
            if (anomalyDetails != null) {
                anomalyDetailsList.add(anomalyDetails);
            }
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            LOG.error("Exception in getting AnomalyDetails", e);
        }
    }
    anomaliesWrapper.setAnomalyDetailsList(anomalyDetailsList);
    return anomaliesWrapper;
}
Also used : ArrayList(java.util.ArrayList) AnomalyDetails(com.linkedin.thirdeye.dashboard.resources.v2.pojo.AnomalyDetails) Callable(java.util.concurrent.Callable) DatasetConfigDTO(com.linkedin.thirdeye.datalayer.dto.DatasetConfigDTO) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO) Future(java.util.concurrent.Future) AnomaliesWrapper(com.linkedin.thirdeye.dashboard.resources.v2.pojo.AnomaliesWrapper) ExecutionException(java.util.concurrent.ExecutionException) DateTimeFormatter(org.joda.time.format.DateTimeFormatter) TimeoutException(java.util.concurrent.TimeoutException)

Example 40 with MergedAnomalyResultDTO

use of com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO in project pinot by linkedin.

the class MergedAnomalyResultManagerImpl method findById.

public MergedAnomalyResultDTO findById(Long id, boolean loadRawAnomalies) {
    MergedAnomalyResultBean mergedAnomalyResultBean = genericPojoDao.get(id, MergedAnomalyResultBean.class);
    if (mergedAnomalyResultBean != null) {
        MergedAnomalyResultDTO mergedAnomalyResultDTO;
        mergedAnomalyResultDTO = convertMergedAnomalyBean2DTO(mergedAnomalyResultBean, loadRawAnomalies);
        return mergedAnomalyResultDTO;
    } else {
        return null;
    }
}
Also used : MergedAnomalyResultBean(com.linkedin.thirdeye.datalayer.pojo.MergedAnomalyResultBean) MergedAnomalyResultDTO(com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO)

Aggregations

MergedAnomalyResultDTO (com.linkedin.thirdeye.datalayer.dto.MergedAnomalyResultDTO)61 ArrayList (java.util.ArrayList)24 AnomalyFunctionDTO (com.linkedin.thirdeye.datalayer.dto.AnomalyFunctionDTO)17 RawAnomalyResultDTO (com.linkedin.thirdeye.datalayer.dto.RawAnomalyResultDTO)17 Path (javax.ws.rs.Path)16 DimensionMap (com.linkedin.thirdeye.api.DimensionMap)11 GET (javax.ws.rs.GET)10 AnomalyFeedbackDTO (com.linkedin.thirdeye.datalayer.dto.AnomalyFeedbackDTO)9 HashMap (java.util.HashMap)9 DateTime (org.joda.time.DateTime)9 MetricTimeSeries (com.linkedin.thirdeye.api.MetricTimeSeries)8 IOException (java.io.IOException)8 ScalingFactor (com.linkedin.thirdeye.detector.metric.transfer.ScalingFactor)7 ExecutionException (java.util.concurrent.ExecutionException)7 TimeoutException (java.util.concurrent.TimeoutException)6 TimeGranularity (com.linkedin.thirdeye.api.TimeGranularity)5 POST (javax.ws.rs.POST)5 Pair (com.linkedin.pinot.pql.parsers.utils.Pair)4 AnomalyDetectionInputContext (com.linkedin.thirdeye.anomaly.detection.AnomalyDetectionInputContext)4 AnomaliesWrapper (com.linkedin.thirdeye.dashboard.resources.v2.pojo.AnomaliesWrapper)4