mirror of https://github.com/grafana/loki
Label selector optimizations (#8763)
This PR introduces the following label selector optimizations: - any selector that is `=~<literal>` is converted to an `Equals/NotEquals` matcher - Use the greedy->non-greedy regex improvements that exist in line and label filters - Never run `.*` label matchers. Prometheus regex matchers anchor the match to the beginning and end of the line. That means matchers of the form `=~<literal_value>` are just testing equality. Benchmarks -- this is just a quick bench to demonstrate equality matchers are faster than their equivalent regex matchers: ``` BenchmarkMatcherTypes/regex-8 27694834 53.74 ns/op 0 B/op 0 allocs/op BenchmarkMatcherTypes/equals-8 627045850 2.153 ns/op 0 B/op 0 allocs/op ```pull/8857/head
parent
cb8a7440d4
commit
5a08a6bcb9
@ -0,0 +1,35 @@ |
||||
package util |
||||
|
||||
import "github.com/grafana/regexp/syntax" |
||||
|
||||
func IsCaseInsensitive(reg *syntax.Regexp) bool { |
||||
return (reg.Flags & syntax.FoldCase) != 0 |
||||
} |
||||
|
||||
// AllNonGreedy turns greedy quantifiers such as `.*` and `.+` into non-greedy ones. This is the same effect as writing
|
||||
// `.*?` and `.+?`. This is only safe because we use `Match`. If we were to find the exact position and length of the match
|
||||
// we would not be allowed to make this optimization. `Match` can return quicker because it is not looking for the longest match.
|
||||
// Prepending the expression with `(?U)` or passing `NonGreedy` to the expression compiler is not enough since it will
|
||||
// just negate `.*` and `.*?`.
|
||||
func AllNonGreedy(regs ...*syntax.Regexp) { |
||||
ClearCapture(regs...) |
||||
for _, re := range regs { |
||||
switch re.Op { |
||||
case syntax.OpCapture, syntax.OpConcat, syntax.OpAlternate: |
||||
AllNonGreedy(re.Sub...) |
||||
case syntax.OpStar, syntax.OpPlus: |
||||
re.Flags = re.Flags | syntax.NonGreedy |
||||
default: |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// ClearCapture removes capture operation as they are not used for filtering.
|
||||
func ClearCapture(regs ...*syntax.Regexp) { |
||||
for _, r := range regs { |
||||
if r.Op == syntax.OpCapture { |
||||
*r = *r.Sub[0] |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue