reducer.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package conditions
  2. import (
  3. "math"
  4. "sort"
  5. "github.com/grafana/grafana/pkg/components/null"
  6. "github.com/grafana/grafana/pkg/tsdb"
  7. )
  8. type QueryReducer interface {
  9. Reduce(timeSeries *tsdb.TimeSeries) null.Float
  10. }
  11. type SimpleReducer struct {
  12. Type string
  13. }
  14. func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) null.Float {
  15. if len(series.Points) == 0 {
  16. return null.FloatFromPtr(nil)
  17. }
  18. value := float64(0)
  19. allNull := true
  20. switch s.Type {
  21. case "avg":
  22. validPointsCount := 0
  23. for _, point := range series.Points {
  24. if point[0].Valid {
  25. value += point[0].Float64
  26. validPointsCount += 1
  27. allNull = false
  28. }
  29. }
  30. if validPointsCount > 0 {
  31. value = value / float64(validPointsCount)
  32. }
  33. case "sum":
  34. for _, point := range series.Points {
  35. if point[0].Valid {
  36. value += point[0].Float64
  37. allNull = false
  38. }
  39. }
  40. case "min":
  41. value = math.MaxFloat64
  42. for _, point := range series.Points {
  43. if point[0].Valid {
  44. allNull = false
  45. if value > point[0].Float64 {
  46. value = point[0].Float64
  47. }
  48. }
  49. }
  50. case "max":
  51. value = -math.MaxFloat64
  52. for _, point := range series.Points {
  53. if point[0].Valid {
  54. allNull = false
  55. if value < point[0].Float64 {
  56. value = point[0].Float64
  57. }
  58. }
  59. }
  60. case "count":
  61. value = float64(len(series.Points))
  62. allNull = false
  63. case "last":
  64. points := series.Points
  65. for i := len(points) - 1; i >= 0; i-- {
  66. if points[i][0].Valid {
  67. value = points[i][0].Float64
  68. allNull = false
  69. break
  70. }
  71. }
  72. case "median":
  73. var values []float64
  74. for _, v := range series.Points {
  75. if v[0].Valid {
  76. allNull = false
  77. values = append(values, v[0].Float64)
  78. }
  79. }
  80. if len(values) >= 1 {
  81. sort.Float64s(values)
  82. length := len(values)
  83. if length%2 == 1 {
  84. value = values[(length-1)/2]
  85. } else {
  86. value = (values[(length/2)-1] + values[length/2]) / 2
  87. }
  88. }
  89. case "diff":
  90. allNull, value = calculateDiff(series, allNull, value, diff)
  91. case "percent_diff":
  92. allNull, value = calculateDiff(series, allNull, value, percentDiff)
  93. case "count_non_null":
  94. for _, v := range series.Points {
  95. if v[0].Valid {
  96. value++
  97. }
  98. }
  99. if value > 0 {
  100. allNull = false
  101. }
  102. }
  103. if allNull {
  104. return null.FloatFromPtr(nil)
  105. }
  106. return null.FloatFrom(value)
  107. }
  108. func NewSimpleReducer(typ string) *SimpleReducer {
  109. return &SimpleReducer{Type: typ}
  110. }
  111. func calculateDiff(series *tsdb.TimeSeries, allNull bool, value float64, fn func(float64, float64) float64) (bool, float64) {
  112. var (
  113. points = series.Points
  114. first float64
  115. i int
  116. )
  117. // get the newest point
  118. for i = len(points) - 1; i >= 0; i-- {
  119. if points[i][0].Valid {
  120. allNull = false
  121. first = points[i][0].Float64
  122. break
  123. }
  124. }
  125. if i >= 1 {
  126. // get the oldest point
  127. points = points[0:i]
  128. for i := 0; i < len(points); i++ {
  129. if points[i][0].Valid {
  130. allNull = false
  131. val := fn(first, points[i][0].Float64)
  132. value = math.Abs(val)
  133. break
  134. }
  135. }
  136. }
  137. return allNull, value
  138. }
  139. var diff = func(newest, oldest float64) float64 {
  140. return newest - oldest
  141. }
  142. var percentDiff = func(newest, oldest float64) float64 {
  143. return (newest - oldest) / oldest * 100
  144. }