github.com/go-graphite/carbonapi@v0.17.0/expr/functions/heatMap/helpers.go (about)

     1  package heatMap
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"sort"
     7  
     8  	"github.com/go-graphite/carbonapi/expr/types"
     9  )
    10  
    11  // Helper functions that are used to sort or validate metrics
    12  func validateNeighbourSeries(series []*types.MetricData) error {
    13  	if len(series) == 0 {
    14  		return nil
    15  	}
    16  	s1 := series[0]
    17  
    18  	for i := 1; i < len(series); i++ {
    19  		s2 := series[i]
    20  		if s1.StartTime != s2.StartTime {
    21  			return fmt.Errorf("StartTime differs: %d!=%d", s1.StartTime, s2.StartTime)
    22  		}
    23  		if s1.StopTime != s2.StopTime {
    24  			return fmt.Errorf("StartTime differs: %d!=%d", s1.StopTime, s2.StopTime)
    25  		}
    26  		if s1.StepTime != s2.StepTime {
    27  			return fmt.Errorf("StartTime differs: %d!=%d", s1.StepTime, s2.StepTime)
    28  		}
    29  		if len(s1.Values) != len(s2.Values) {
    30  			return fmt.Errorf("values quantity differs: %d!=%d", len(s1.Values), len(s2.Values))
    31  		}
    32  	}
    33  	return nil
    34  }
    35  
    36  // sortMetricData returns *types.MetricData list sorted by sum of the first values
    37  func sortMetricData(list []*types.MetricData) []*types.MetricData {
    38  	// take 5 first not null values
    39  	const points = 5
    40  
    41  	// mate series with its weight (sum of first values)
    42  	type metricDataWeighted struct {
    43  		data   *types.MetricData
    44  		weight float64
    45  	}
    46  
    47  	seriesQty := len(list)
    48  	if seriesQty < 2 {
    49  		return list
    50  	}
    51  
    52  	listWeighted := make([]metricDataWeighted, seriesQty)
    53  	for j := 0; j < seriesQty; j++ {
    54  		listWeighted[j].data = list[j]
    55  	}
    56  
    57  	pointsFound := 0
    58  	valuesQty := len(list[0].Values)
    59  
    60  	for i := 0; i < valuesQty && pointsFound < points; i++ {
    61  		// make sure that each series has current point not null
    62  		absent := false
    63  		for j := 0; j < seriesQty && !absent; j++ {
    64  			absent = math.IsNaN(list[j].Values[i])
    65  		}
    66  		if absent {
    67  			continue
    68  		}
    69  
    70  		// accumulate sum of first not-null values
    71  		for j := 0; j < seriesQty; j++ {
    72  			listWeighted[j].weight += list[j].Values[i]
    73  		}
    74  		pointsFound++
    75  	}
    76  
    77  	// sort series by its weight
    78  	if pointsFound > 0 {
    79  		sort.SliceStable(listWeighted, func(i, j int) bool {
    80  			return listWeighted[i].weight < listWeighted[j].weight
    81  		})
    82  		for j := 0; j < seriesQty; j++ {
    83  			list[j] = listWeighted[j].data
    84  		}
    85  	}
    86  
    87  	return list
    88  }