promql: Remove interpolation of vector values.

The current behaviour produces values that are not
from rules or scrapes. So if for example I have
a boolean 0/1 it can be returned as 0.2344589. This
prevents a number of advanced use cases, introduces
race conditions and can produce misleading graphs.
This commit is contained in:
Brian Brazil 2015-08-18 17:06:22 +01:00
parent 25a8bd50a5
commit fb585e4591
1 changed files with 8 additions and 54 deletions

View File

@ -723,7 +723,7 @@ func (ev *evaluator) vectorSelector(node *VectorSelector) Vector {
vec := Vector{} vec := Vector{}
for fp, it := range node.iterators { for fp, it := range node.iterators {
sampleCandidates := it.ValueAtTime(ev.Timestamp.Add(-node.Offset)) sampleCandidates := it.ValueAtTime(ev.Timestamp.Add(-node.Offset))
samplePair := chooseClosestSample(sampleCandidates, ev.Timestamp.Add(-node.Offset)) samplePair := chooseClosestBefore(sampleCandidates, ev.Timestamp.Add(-node.Offset))
if samplePair != nil { if samplePair != nil {
vec = append(vec, &Sample{ vec = append(vec, &Sample{
Metric: node.metrics[fp], Metric: node.metrics[fp],
@ -1173,67 +1173,21 @@ func shouldDropMetricName(op itemType) bool {
// series is considered stale. // series is considered stale.
var StalenessDelta = 5 * time.Minute var StalenessDelta = 5 * time.Minute
// chooseClosestSample chooses the closest sample of a list of samples // chooseClosestBefore chooses the closest sample of a list of samples
// surrounding a given target time. If samples are found both before and after // before or at a given target time.
// the target time, the sample value is interpolated between these. Otherwise, func chooseClosestBefore(samples []model.SamplePair, timestamp model.Time) *model.SamplePair {
// the single closest sample is returned verbatim.
func chooseClosestSample(samples []model.SamplePair, timestamp model.Time) *model.SamplePair {
var closestBefore *model.SamplePair
var closestAfter *model.SamplePair
for _, candidate := range samples { for _, candidate := range samples {
delta := candidate.Timestamp.Sub(timestamp) delta := candidate.Timestamp.Sub(timestamp)
// Samples before target time. // Samples before or at target time.
if delta < 0 { if delta <= 0 {
// Ignore samples outside of staleness policy window. // Ignore samples outside of staleness policy window.
if -delta > StalenessDelta { if -delta > StalenessDelta {
continue continue
} }
// Ignore samples that are farther away than what we've seen before. return &candidate
if closestBefore != nil && candidate.Timestamp.Before(closestBefore.Timestamp) {
continue
}
sample := candidate
closestBefore = &sample
}
// Samples after target time.
if delta >= 0 {
// Ignore samples outside of staleness policy window.
if delta > StalenessDelta {
continue
}
// Ignore samples that are farther away than samples we've seen before.
if closestAfter != nil && candidate.Timestamp.After(closestAfter.Timestamp) {
continue
}
sample := candidate
closestAfter = &sample
} }
} }
return nil
switch {
case closestBefore != nil && closestAfter != nil:
return interpolateSamples(closestBefore, closestAfter, timestamp)
case closestBefore != nil:
return closestBefore
default:
return closestAfter
}
}
// interpolateSamples interpolates a value at a target time between two
// provided sample pairs.
func interpolateSamples(first, second *model.SamplePair, timestamp model.Time) *model.SamplePair {
dv := second.Value - first.Value
dt := second.Timestamp.Sub(first.Timestamp)
dDt := dv / model.SampleValue(dt)
offset := model.SampleValue(timestamp.Sub(first.Timestamp))
return &model.SamplePair{
Value: first.Value + (offset * dDt),
Timestamp: timestamp,
}
} }
// A queryGate controls the maximum number of concurrently running and waiting queries. // A queryGate controls the maximum number of concurrently running and waiting queries.