mirror of
https://github.com/prometheus/prometheus
synced 2025-02-04 14:13:32 +00:00
Optimize label values with matchers by taking shortcuts (#13426)
Don't calculate postings beforehand: we may not need them. If all matchers are for the requested label, we can just filter its values. Also, if there are no values at all, no need to run any kind of logic. Also add more labelValuesWithMatchers benchmarks Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
This commit is contained in:
parent
c095ba24f2
commit
ed172a6667
@ -410,7 +410,7 @@ func TestOOOHeadChunkReader_LabelValues(t *testing.T) {
|
||||
queryMinT: math.MinInt64,
|
||||
queryMaxT: math.MaxInt64,
|
||||
expValues1: []string{"bar1"},
|
||||
expValues2: []string{},
|
||||
expValues2: nil,
|
||||
expValues3: []string{"bar1", "bar2"},
|
||||
expValues4: []string{"bar1", "bar2"},
|
||||
},
|
||||
@ -419,7 +419,7 @@ func TestOOOHeadChunkReader_LabelValues(t *testing.T) {
|
||||
queryMinT: 90,
|
||||
queryMaxT: 90,
|
||||
expValues1: []string{"bar1"},
|
||||
expValues2: []string{},
|
||||
expValues2: nil,
|
||||
expValues3: []string{"bar1", "bar2"},
|
||||
expValues4: []string{"bar1", "bar2"},
|
||||
},
|
||||
|
@ -440,11 +440,6 @@ func inversePostingsForMatcher(ctx context.Context, ix IndexReader, m *labels.Ma
|
||||
}
|
||||
|
||||
func labelValuesWithMatchers(ctx context.Context, r IndexReader, name string, matchers ...*labels.Matcher) ([]string, error) {
|
||||
p, err := PostingsForMatchers(ctx, r, matchers...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching postings for matchers: %w", err)
|
||||
}
|
||||
|
||||
allValues, err := r.LabelValues(ctx, name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching values of label %s: %w", name, err)
|
||||
@ -453,8 +448,10 @@ func labelValuesWithMatchers(ctx context.Context, r IndexReader, name string, ma
|
||||
// If we have a matcher for the label name, we can filter out values that don't match
|
||||
// before we fetch postings. This is especially useful for labels with many values.
|
||||
// e.g. __name__ with a selector like {__name__="xyz"}
|
||||
hasMatchersForOtherLabels := false
|
||||
for _, m := range matchers {
|
||||
if m.Name != name {
|
||||
hasMatchersForOtherLabels = true
|
||||
continue
|
||||
}
|
||||
|
||||
@ -469,6 +466,20 @@ func labelValuesWithMatchers(ctx context.Context, r IndexReader, name string, ma
|
||||
allValues = filteredValues
|
||||
}
|
||||
|
||||
if len(allValues) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// If we don't have any matchers for other labels, then we're done.
|
||||
if !hasMatchersForOtherLabels {
|
||||
return allValues, nil
|
||||
}
|
||||
|
||||
p, err := PostingsForMatchers(ctx, r, matchers...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching postings for matchers: %w", err)
|
||||
}
|
||||
|
||||
valuesPostings := make([]index.Postings, len(allValues))
|
||||
for i, value := range allValues {
|
||||
valuesPostings[i], err = r.Postings(ctx, name, value)
|
||||
|
@ -182,13 +182,16 @@ func benchmarkPostingsForMatchers(b *testing.B, ir IndexReader) {
|
||||
|
||||
func benchmarkLabelValuesWithMatchers(b *testing.B, ir IndexReader) {
|
||||
i1 := labels.MustNewMatcher(labels.MatchEqual, "i", "1")
|
||||
i1Plus := labels.MustNewMatcher(labels.MatchRegexp, "i", "1.+")
|
||||
i1PostingsBenchSuffix := labels.MustNewMatcher(labels.MatchEqual, "i", "1"+postingsBenchSuffix)
|
||||
iSuffix := labels.MustNewMatcher(labels.MatchRegexp, "i", ".+ddd")
|
||||
iStar := labels.MustNewMatcher(labels.MatchRegexp, "i", "^.*$")
|
||||
jNotFoo := labels.MustNewMatcher(labels.MatchNotEqual, "j", "foo")
|
||||
jXXXYYY := labels.MustNewMatcher(labels.MatchRegexp, "j", "XXX|YYY")
|
||||
jXplus := labels.MustNewMatcher(labels.MatchRegexp, "j", "X.+")
|
||||
n1 := labels.MustNewMatcher(labels.MatchEqual, "n", "1"+postingsBenchSuffix)
|
||||
nX := labels.MustNewMatcher(labels.MatchNotEqual, "n", "X"+postingsBenchSuffix)
|
||||
nPlus := labels.MustNewMatcher(labels.MatchRegexp, "i", "^.+$")
|
||||
nPlus := labels.MustNewMatcher(labels.MatchRegexp, "n", "^.+$")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
@ -197,6 +200,7 @@ func benchmarkLabelValuesWithMatchers(b *testing.B, ir IndexReader) {
|
||||
labelName string
|
||||
matchers []*labels.Matcher
|
||||
}{
|
||||
// i is never "1", this isn't matching anything.
|
||||
{`i with i="1"`, "i", []*labels.Matcher{i1}},
|
||||
// i has 100k values.
|
||||
{`i with n="1"`, "i", []*labels.Matcher{n1}},
|
||||
@ -206,9 +210,16 @@ func benchmarkLabelValuesWithMatchers(b *testing.B, ir IndexReader) {
|
||||
{`i with n="1",j=~"XXX|YYY"`, "i", []*labels.Matcher{n1, jXXXYYY}},
|
||||
{`i with n="X",j!="foo"`, "i", []*labels.Matcher{nX, jNotFoo}},
|
||||
{`i with n="1",i=~"^.*$",j!="foo"`, "i", []*labels.Matcher{n1, iStar, jNotFoo}},
|
||||
// matchers on i itself
|
||||
{`i with i="1aaa...ddd"`, "i", []*labels.Matcher{i1PostingsBenchSuffix}},
|
||||
{`i with i=~"1.+"`, "i", []*labels.Matcher{i1Plus}},
|
||||
{`i with i=~"1.+",i=~".+ddd"`, "i", []*labels.Matcher{i1Plus, iSuffix}},
|
||||
// n has 10 values.
|
||||
{`n with j!="foo"`, "n", []*labels.Matcher{jNotFoo}},
|
||||
{`n with i="1"`, "n", []*labels.Matcher{i1}},
|
||||
{`n with i=~"1.+"`, "n", []*labels.Matcher{i1Plus}},
|
||||
// there's no label "none"
|
||||
{`none with i=~"1"`, "none", []*labels.Matcher{i1Plus}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
Loading…
Reference in New Issue
Block a user