diff --git a/lib/logstorage/filter.go b/lib/logstorage/filter.go index 7bf63a9f8..c074b5a75 100644 --- a/lib/logstorage/filter.go +++ b/lib/logstorage/filter.go @@ -72,78 +72,6 @@ func (fs *streamFilter) apply(bs *blockSearch, bm *bitmap) { } } -// exactPrefixFilter matches the exact prefix. -// -// Example LogsQL: `fieldName:exact("foo bar"*) -type exactPrefixFilter struct { - fieldName string - prefix string - - tokensOnce sync.Once - tokens []string -} - -func (ef *exactPrefixFilter) String() string { - return fmt.Sprintf("%sexact(%s*)", quoteFieldNameIfNeeded(ef.fieldName), quoteTokenIfNeeded(ef.prefix)) -} - -func (ef *exactPrefixFilter) getTokens() []string { - ef.tokensOnce.Do(ef.initTokens) - return ef.tokens -} - -func (ef *exactPrefixFilter) initTokens() { - ef.tokens = getTokensSkipLast(ef.prefix) -} - -func (ef *exactPrefixFilter) apply(bs *blockSearch, bm *bitmap) { - fieldName := ef.fieldName - prefix := ef.prefix - - v := bs.csh.getConstColumnValue(fieldName) - if v != "" { - if !matchExactPrefix(v, prefix) { - bm.resetBits() - } - return - } - - // Verify whether filter matches other columns - ch := bs.csh.getColumnHeader(fieldName) - if ch == nil { - // Fast path - there are no matching columns. - if !matchExactPrefix("", prefix) { - bm.resetBits() - } - return - } - - tokens := ef.getTokens() - - switch ch.valueType { - case valueTypeString: - matchStringByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeDict: - matchValuesDictByExactPrefix(bs, ch, bm, prefix) - case valueTypeUint8: - matchUint8ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeUint16: - matchUint16ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeUint32: - matchUint32ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeUint64: - matchUint64ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeFloat64: - matchFloat64ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeIPv4: - matchIPv4ByExactPrefix(bs, ch, bm, prefix, tokens) - case valueTypeTimestampISO8601: - matchTimestampISO8601ByExactPrefix(bs, ch, bm, prefix, tokens) - default: - logger.Panicf("FATAL: %s: unknown valueType=%d", bs.partPath(), ch.valueType) - } -} - // exactFilter matches the exact value. // // Example LogsQL: `fieldName:exact("foo bar")` @@ -155,22 +83,22 @@ type exactFilter struct { tokens []string } -func (ef *exactFilter) String() string { - return fmt.Sprintf("%sexact(%s)", quoteFieldNameIfNeeded(ef.fieldName), quoteTokenIfNeeded(ef.value)) +func (fe *exactFilter) String() string { + return fmt.Sprintf("%sexact(%s)", quoteFieldNameIfNeeded(fe.fieldName), quoteTokenIfNeeded(fe.value)) } -func (ef *exactFilter) getTokens() []string { - ef.tokensOnce.Do(ef.initTokens) - return ef.tokens +func (fe *exactFilter) getTokens() []string { + fe.tokensOnce.Do(fe.initTokens) + return fe.tokens } -func (ef *exactFilter) initTokens() { - ef.tokens = tokenizeStrings(nil, []string{ef.value}) +func (fe *exactFilter) initTokens() { + fe.tokens = tokenizeStrings(nil, []string{fe.value}) } -func (ef *exactFilter) apply(bs *blockSearch, bm *bitmap) { - fieldName := ef.fieldName - value := ef.value +func (fe *exactFilter) apply(bs *blockSearch, bm *bitmap) { + fieldName := fe.fieldName + value := fe.value v := bs.csh.getConstColumnValue(fieldName) if v != "" { @@ -191,7 +119,7 @@ func (ef *exactFilter) apply(bs *blockSearch, bm *bitmap) { return } - tokens := ef.getTokens() + tokens := fe.getTokens() switch ch.valueType { case valueTypeString: @@ -1226,23 +1154,6 @@ func matchTimestampISO8601ByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap bbPool.Put(bb) } -func matchTimestampISO8601ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if prefix == "" { - return - } - if prefix < "0" || prefix > "9" || !matchBloomFilterAllTokens(bs, ch, tokens) { - bm.resetBits() - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toTimestampISO8601StringExt(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - func matchTimestampISO8601ByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, value string, tokens []string) { n, ok := tryParseTimestampISO8601(value) if !ok || n < ch.minValue || n > ch.maxValue { @@ -1351,23 +1262,6 @@ func matchIPv4ByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix str bbPool.Put(bb) } -func matchIPv4ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if prefix == "" { - return - } - if prefix < "0" || prefix > "9" || len(tokens) > 3 || !matchBloomFilterAllTokens(bs, ch, tokens) { - bm.resetBits() - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toIPv4StringExt(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - func matchIPv4ByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, value string, tokens []string) { n, ok := tryParseIPv4(value) if !ok || uint64(n) < ch.minValue || uint64(n) > ch.maxValue { @@ -1486,24 +1380,6 @@ func matchFloat64ByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix bbPool.Put(bb) } -func matchFloat64ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if prefix == "" { - // An empty prefix matches all the values - return - } - if len(tokens) > 2 || !matchBloomFilterAllTokens(bs, ch, tokens) { - bm.resetBits() - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toFloat64StringExt(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - func matchFloat64ByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, value string, tokens []string) { f, ok := tryParseFloat64(value) if !ok || f < math.Float64frombits(ch.minValue) || f > math.Float64frombits(ch.maxValue) { @@ -1634,17 +1510,6 @@ func matchValuesDictByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, pref bbPool.Put(bb) } -func matchValuesDictByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string) { - bb := bbPool.Get() - for i, v := range ch.valuesDict.values { - if matchExactPrefix(v, prefix) { - bb.B = append(bb.B, byte(i)) - } - } - matchEncodedValuesDict(bs, ch, bm, bb.B) - bbPool.Put(bb) -} - func matchValuesDictByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, value string) { bb := bbPool.Get() for i, v := range ch.valuesDict.values { @@ -1746,16 +1611,6 @@ func matchStringByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix s }) } -func matchStringByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if !matchBloomFilterAllTokens(bs, ch, tokens) { - bm.resetBits() - return - } - visitValues(bs, ch, bm, func(v string) bool { - return matchExactPrefix(v, prefix) - }) -} - func matchStringByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, value string, tokens []string) { if !matchBloomFilterAllTokens(bs, ch, tokens) { bm.resetBits() @@ -2097,77 +1952,6 @@ func matchUint64ByPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix s bbPool.Put(bb) } -func matchUint8ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toUint8String(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - -func matchUint16ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toUint16String(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - -func matchUint32ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toUint32String(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - -func matchUint64ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { - if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { - return - } - - bb := bbPool.Get() - visitValues(bs, ch, bm, func(v string) bool { - s := toUint64String(bs, bb, v) - return matchExactPrefix(s, prefix) - }) - bbPool.Put(bb) -} - -func matchMinMaxExactPrefix(ch *columnHeader, bm *bitmap, prefix string, tokens []string) bool { - if prefix == "" { - // An empty prefix matches all the values - return false - } - if len(tokens) > 0 { - // Non-empty tokens means that the prefix contains at least two tokens. - // Multiple tokens cannot match any uint value. - bm.resetBits() - return false - } - n, ok := tryParseUint64(prefix) - if !ok || n > ch.maxValue { - bm.resetBits() - return false - } - return true -} - func matchUint8ByExactValue(bs *blockSearch, ch *columnHeader, bm *bitmap, phrase string, tokens []string) { n, ok := tryParseUint64(phrase) if !ok || n < ch.minValue || n > ch.maxValue { @@ -2393,10 +2177,6 @@ func matchAnyCasePhrase(s, phraseLowercase string) bool { return ok } -func matchExactPrefix(s, prefix string) bool { - return strings.HasPrefix(s, prefix) -} - func matchPhrase(s, phrase string) bool { if len(phrase) == 0 { // Special case - empty phrase matches only empty string. diff --git a/lib/logstorage/filter_and.go b/lib/logstorage/filter_and.go index 6cc2f82cd..79b172319 100644 --- a/lib/logstorage/filter_and.go +++ b/lib/logstorage/filter_and.go @@ -77,7 +77,7 @@ func (fa *filterAnd) initMsgTokens() { if isMsgFieldName(t.fieldName) { a = append(a, t.getTokens()...) } - case *exactPrefixFilter: + case *filterExactPrefix: if isMsgFieldName(t.fieldName) { a = append(a, t.getTokens()...) } diff --git a/lib/logstorage/filter_exact_prefix.go b/lib/logstorage/filter_exact_prefix.go new file mode 100644 index 000000000..8ee4b23c1 --- /dev/null +++ b/lib/logstorage/filter_exact_prefix.go @@ -0,0 +1,229 @@ +package logstorage + +import ( + "fmt" + "strings" + "sync" + + "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" +) + +// filterExactPrefix matches the exact prefix. +// +// Example LogsQL: `fieldName:exact("foo bar"*) +type filterExactPrefix struct { + fieldName string + prefix string + + tokensOnce sync.Once + tokens []string +} + +func (fep *filterExactPrefix) String() string { + return fmt.Sprintf("%sexact(%s*)", quoteFieldNameIfNeeded(fep.fieldName), quoteTokenIfNeeded(fep.prefix)) +} + +func (fep *filterExactPrefix) getTokens() []string { + fep.tokensOnce.Do(fep.initTokens) + return fep.tokens +} + +func (fep *filterExactPrefix) initTokens() { + fep.tokens = getTokensSkipLast(fep.prefix) +} + +func (fep *filterExactPrefix) apply(bs *blockSearch, bm *bitmap) { + fieldName := fep.fieldName + prefix := fep.prefix + + v := bs.csh.getConstColumnValue(fieldName) + if v != "" { + if !matchExactPrefix(v, prefix) { + bm.resetBits() + } + return + } + + // Verify whether filter matches other columns + ch := bs.csh.getColumnHeader(fieldName) + if ch == nil { + // Fast path - there are no matching columns. + if !matchExactPrefix("", prefix) { + bm.resetBits() + } + return + } + + tokens := fep.getTokens() + + switch ch.valueType { + case valueTypeString: + matchStringByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeDict: + matchValuesDictByExactPrefix(bs, ch, bm, prefix) + case valueTypeUint8: + matchUint8ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeUint16: + matchUint16ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeUint32: + matchUint32ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeUint64: + matchUint64ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeFloat64: + matchFloat64ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeIPv4: + matchIPv4ByExactPrefix(bs, ch, bm, prefix, tokens) + case valueTypeTimestampISO8601: + matchTimestampISO8601ByExactPrefix(bs, ch, bm, prefix, tokens) + default: + logger.Panicf("FATAL: %s: unknown valueType=%d", bs.partPath(), ch.valueType) + } +} + +func matchTimestampISO8601ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if prefix == "" { + return + } + if prefix < "0" || prefix > "9" || !matchBloomFilterAllTokens(bs, ch, tokens) { + bm.resetBits() + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toTimestampISO8601StringExt(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchIPv4ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if prefix == "" { + return + } + if prefix < "0" || prefix > "9" || len(tokens) > 3 || !matchBloomFilterAllTokens(bs, ch, tokens) { + bm.resetBits() + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toIPv4StringExt(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchFloat64ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if prefix == "" { + // An empty prefix matches all the values + return + } + if len(tokens) > 2 || !matchBloomFilterAllTokens(bs, ch, tokens) { + bm.resetBits() + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toFloat64StringExt(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchValuesDictByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string) { + bb := bbPool.Get() + for i, v := range ch.valuesDict.values { + if matchExactPrefix(v, prefix) { + bb.B = append(bb.B, byte(i)) + } + } + matchEncodedValuesDict(bs, ch, bm, bb.B) + bbPool.Put(bb) +} + +func matchStringByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if !matchBloomFilterAllTokens(bs, ch, tokens) { + bm.resetBits() + return + } + visitValues(bs, ch, bm, func(v string) bool { + return matchExactPrefix(v, prefix) + }) +} + +func matchUint8ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toUint8String(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchUint16ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toUint16String(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchUint32ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toUint32String(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchUint64ByExactPrefix(bs *blockSearch, ch *columnHeader, bm *bitmap, prefix string, tokens []string) { + if !matchMinMaxExactPrefix(ch, bm, prefix, tokens) { + return + } + + bb := bbPool.Get() + visitValues(bs, ch, bm, func(v string) bool { + s := toUint64String(bs, bb, v) + return matchExactPrefix(s, prefix) + }) + bbPool.Put(bb) +} + +func matchMinMaxExactPrefix(ch *columnHeader, bm *bitmap, prefix string, tokens []string) bool { + if prefix == "" { + // An empty prefix matches all the values + return false + } + if len(tokens) > 0 { + // Non-empty tokens means that the prefix contains at least two tokens. + // Multiple tokens cannot match any uint value. + bm.resetBits() + return false + } + n, ok := tryParseUint64(prefix) + if !ok || n > ch.maxValue { + bm.resetBits() + return false + } + return true +} + +func matchExactPrefix(s, prefix string) bool { + return strings.HasPrefix(s, prefix) +} diff --git a/lib/logstorage/filter_exact_prefix_test.go b/lib/logstorage/filter_exact_prefix_test.go new file mode 100644 index 000000000..215c9003f --- /dev/null +++ b/lib/logstorage/filter_exact_prefix_test.go @@ -0,0 +1,564 @@ +package logstorage + +import ( + "testing" +) + +func TestExactPrefixFilter(t *testing.T) { + t.Run("single-row", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "abc def", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "abc def", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "abc d", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0}) + + fep = &filterExactPrefix{ + fieldName: "non-existing-column", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "xabc", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "non-existing column", + prefix: "abc", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("const-column", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "abc def", + "abc def", + "abc def", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "abc def", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "ab", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2}) + + fep = &filterExactPrefix{ + fieldName: "non-existing-column", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "foobar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "non-existing column", + prefix: "x", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("dict", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "", + "foobar", + "abc", + "afdf foobar baz", + "fddf foobarbaz", + "foobarbaz", + "foobar", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "foobar", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{1, 5, 6}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "baz", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "non-existing column", + prefix: "foobar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("strings", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "a foo", + "a foobar", + "aa abc a", + "ca afdf a,foobar baz", + "aa fddf foobarbaz", + "a afoobarbaz", + "a foobar baz", + "a kjlkjf dfff", + "a ТЕСТЙЦУК НГКШ ", + "a !!,23.(!1)", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "aa ", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{2, 4}) + + fep = &filterExactPrefix{ + fieldName: "non-existing-column", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "aa b", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "fobar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "non-existing-column", + prefix: "aa", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("uint8", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "123", + "12", + "32", + "0", + "0", + "12", + "1", + "2", + "3", + "4", + "5", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "12", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 5}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "999", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "7", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("uint16", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "123", + "12", + "32", + "0", + "0", + "12", + "1", + "2", + "3", + "467", + "5", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "12", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 5}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "999", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "7", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("uint32", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "123", + "12", + "32", + "0", + "0", + "12", + "1", + "2", + "3", + "65536", + "5", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "12", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 5}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "99999", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "7", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("uint64", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "123", + "12", + "32", + "0", + "0", + "12", + "1", + "2", + "3", + "123456789012", + "5", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "12", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 5}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "1234567890123", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "7", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("float64", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "1234", + "0", + "3454", + "-65536", + "1234.5678901", + "1", + "2", + "3", + "4", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "123", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 4}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "1234.567", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{4}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "-65536", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{3}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "6511", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("ipv4", func(t *testing.T) { + columns := []column{ + { + name: "foo", + values: []string{ + "1.2.3.4", + "0.0.0.0", + "127.0.0.1", + "254.255.255.255", + "127.0.0.2", + "127.0.0.1", + "127.0.4.2", + "127.0.0.1", + "12.0.127.6", + "55.55.55.55", + "66.66.66.66", + "7.7.7.7", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "foo", + prefix: "127.0.", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{2, 4, 5, 7}) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) + + // mismatch + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + + fep = &filterExactPrefix{ + fieldName: "foo", + prefix: "255", + } + testFilterMatchForColumns(t, columns, fep, "foo", nil) + }) + + t.Run("timestamp-iso8601", func(t *testing.T) { + columns := []column{ + { + name: "_msg", + values: []string{ + "2006-01-02T15:04:05.001Z", + "2006-01-02T15:04:05.002Z", + "2006-01-02T15:04:05.003Z", + "2006-01-02T15:04:06.004Z", + "2006-01-02T15:04:06.005Z", + "2006-01-02T15:04:07.006Z", + "2006-01-02T15:04:10.007Z", + "2006-01-02T15:04:12.008Z", + "2006-01-02T15:04:15.009Z", + }, + }, + } + + // match + fep := &filterExactPrefix{ + fieldName: "_msg", + prefix: "2006-01-02T15:04:05", + } + testFilterMatchForColumns(t, columns, fep, "_msg", []int{0, 1, 2}) + + fep = &filterExactPrefix{ + fieldName: "_msg", + prefix: "", + } + testFilterMatchForColumns(t, columns, fep, "_msg", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) + + // mimatch + fep = &filterExactPrefix{ + fieldName: "_msg", + prefix: "bar", + } + testFilterMatchForColumns(t, columns, fep, "_msg", nil) + + fep = &filterExactPrefix{ + fieldName: "_msg", + prefix: "0", + } + testFilterMatchForColumns(t, columns, fep, "_msg", nil) + }) +} diff --git a/lib/logstorage/filter_test.go b/lib/logstorage/filter_test.go index 86accca1a..d1f3e2272 100644 --- a/lib/logstorage/filter_test.go +++ b/lib/logstorage/filter_test.go @@ -491,109 +491,6 @@ func TestStreamFilter(t *testing.T) { testFilterMatchForColumns(t, columns, f, "foo", nil) } -func TestExactPrefixFilter(t *testing.T) { - t.Run("single-row", func(t *testing.T) { - columns := []column{ - { - name: "foo", - values: []string{ - "abc def", - }, - }, - } - - // match - ef := &exactPrefixFilter{ - fieldName: "foo", - prefix: "abc def", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) - - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "abc d", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) - - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) - - ef = &exactPrefixFilter{ - fieldName: "non-existing-column", - prefix: "", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) - - // mismatch - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "xabc", - } - testFilterMatchForColumns(t, columns, ef, "foo", nil) - - ef = &exactPrefixFilter{ - fieldName: "non-existing column", - prefix: "abc", - } - testFilterMatchForColumns(t, columns, ef, "foo", nil) - }) - - t.Run("const-column", func(t *testing.T) { - columns := []column{ - { - name: "foo", - values: []string{ - "abc def", - "abc def", - "abc def", - }, - }, - } - - // match - ef := &exactPrefixFilter{ - fieldName: "foo", - prefix: "abc def", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) - - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "ab", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) - - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) - - ef = &exactPrefixFilter{ - fieldName: "non-existing-column", - prefix: "", - } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) - - // mismatch - ef = &exactPrefixFilter{ - fieldName: "foo", - prefix: "foobar", - } - testFilterMatchForColumns(t, columns, ef, "foo", nil) - - ef = &exactPrefixFilter{ - fieldName: "non-existing column", - prefix: "x", - } - testFilterMatchForColumns(t, columns, ef, "foo", nil) - }) - -} - func TestExactFilter(t *testing.T) { t.Run("single-row", func(t *testing.T) { columns := []column{ @@ -606,30 +503,30 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "abc def", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "abc", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing column", value: "abc", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("const-column", func(t *testing.T) { @@ -645,36 +542,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "abc def", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "foobar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing column", value: "x", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("dict", func(t *testing.T) { @@ -694,30 +591,30 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "foobar", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{1, 6}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 6}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "baz", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing column", value: "foobar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("strings", func(t *testing.T) { @@ -740,36 +637,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "aa abc a", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{2}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{2}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "aa a", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "fooaaazz a", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("uint8", func(t *testing.T) { @@ -793,36 +690,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "12", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{1, 5}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 5}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "33", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("uint16", func(t *testing.T) { @@ -846,36 +743,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "12", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{1, 5}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 5}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "33", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("uint32", func(t *testing.T) { @@ -899,36 +796,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "12", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{1, 5}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 5}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "33", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("uint64", func(t *testing.T) { @@ -952,36 +849,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "12", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{1, 5}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{1, 5}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "33", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("float64", func(t *testing.T) { @@ -1003,60 +900,60 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "1234", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "1234.5678901", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{4}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{4}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "-65536", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{3}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{3}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "65536", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "123", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "12345678901234567890", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("ipv4", func(t *testing.T) { @@ -1081,42 +978,42 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "foo", value: "127.0.0.1", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{2, 4, 5, 7}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{2, 4, 5, 7}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) + testFilterMatchForColumns(t, columns, fe, "foo", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) // mismatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "127.0", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "foo", value: "255.255.255.255", } - testFilterMatchForColumns(t, columns, ef, "foo", nil) + testFilterMatchForColumns(t, columns, fe, "foo", nil) }) t.Run("timestamp-iso8601", func(t *testing.T) { @@ -1138,36 +1035,36 @@ func TestExactFilter(t *testing.T) { } // match - ef := &exactFilter{ + fe := &exactFilter{ fieldName: "_msg", value: "2006-01-02T15:04:05.005Z", } - testFilterMatchForColumns(t, columns, ef, "_msg", []int{4}) + testFilterMatchForColumns(t, columns, fe, "_msg", []int{4}) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "non-existing-column", value: "", } - testFilterMatchForColumns(t, columns, ef, "_msg", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) + testFilterMatchForColumns(t, columns, fe, "_msg", []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) // mimatch - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "_msg", value: "bar", } - testFilterMatchForColumns(t, columns, ef, "_msg", nil) + testFilterMatchForColumns(t, columns, fe, "_msg", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "_msg", value: "", } - testFilterMatchForColumns(t, columns, ef, "_msg", nil) + testFilterMatchForColumns(t, columns, fe, "_msg", nil) - ef = &exactFilter{ + fe = &exactFilter{ fieldName: "_msg", value: "2006-03-02T15:04:05.005Z", } - testFilterMatchForColumns(t, columns, ef, "_msg", nil) + testFilterMatchForColumns(t, columns, fe, "_msg", nil) }) } diff --git a/lib/logstorage/parser.go b/lib/logstorage/parser.go index 4f20136c8..df9c633ea 100644 --- a/lib/logstorage/parser.go +++ b/lib/logstorage/parser.go @@ -635,7 +635,7 @@ func parseFilterSequence(lex *lexer, fieldName string) (filter, error) { func parseExactFilter(lex *lexer, fieldName string) (filter, error) { return parseFuncArgMaybePrefix(lex, "exact", fieldName, func(phrase string, isPrefixFilter bool) (filter, error) { if isPrefixFilter { - f := &exactPrefixFilter{ + f := &filterExactPrefix{ fieldName: fieldName, prefix: phrase, }