This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git


The following commit(s) were added to refs/heads/main by this push:
     new 214265832 Fix tagFamilyFilters.range method about encode and logic 
problem (#976)
214265832 is described below

commit 21426583251c95711ec2b165f7f069f0cab6f29d
Author: eye-gu <[email protected]>
AuthorDate: Sun Feb 22 21:24:04 2026 +0800

    Fix tagFamilyFilters.range method about encode and logic problem (#976)
    
    * Fix tagFamilyFilters.range method about encode and logic problem
    
    * Add boundary case tests for Range method in tag filters
    
    ---------
    
    Co-authored-by: Gao Hongtao <[email protected]>
---
 banyand/stream/tag_filter.go      |  15 ++--
 banyand/stream/tag_filter_test.go | 169 +++++++++++++++++++++++++++++++++++---
 2 files changed, 167 insertions(+), 17 deletions(-)

diff --git a/banyand/stream/tag_filter.go b/banyand/stream/tag_filter.go
index d83729548..4498777a6 100644
--- a/banyand/stream/tag_filter.go
+++ b/banyand/stream/tag_filter.go
@@ -21,7 +21,10 @@ import (
        "bytes"
        "fmt"
 
+       "github.com/blugelabs/bluge/numeric"
+
        pkgbytes "github.com/apache/skywalking-banyandb/pkg/bytes"
+       "github.com/apache/skywalking-banyandb/pkg/convert"
        "github.com/apache/skywalking-banyandb/pkg/encoding"
        "github.com/apache/skywalking-banyandb/pkg/filter"
        "github.com/apache/skywalking-banyandb/pkg/fs"
@@ -233,10 +236,9 @@ func (tfs *tagFamilyFilters) Range(tagName string, 
rangeOpts index.RangeOpts) (b
                                if !ok {
                                        return false, fmt.Errorf("lower is not 
a float value: %v", rangeOpts.Lower)
                                }
-                               value := make([]byte, 0)
-                               value = encoding.Int64ToBytes(value, 
int64(lower.Value))
+                               value := 
convert.Int64ToBytes(numeric.Float64ToInt64(lower.Value))
                                if bytes.Compare(tf.max, value) == -1 || 
!rangeOpts.IncludesLower && bytes.Equal(tf.max, value) {
-                                       return false, nil
+                                       return true, nil
                                }
                        }
                        if rangeOpts.Upper != nil {
@@ -244,15 +246,14 @@ func (tfs *tagFamilyFilters) Range(tagName string, 
rangeOpts index.RangeOpts) (b
                                if !ok {
                                        return false, fmt.Errorf("upper is not 
a float value: %v", rangeOpts.Upper)
                                }
-                               value := make([]byte, 0)
-                               value = encoding.Int64ToBytes(value, 
int64(upper.Value))
+                               value := 
convert.Int64ToBytes(numeric.Float64ToInt64(upper.Value))
                                if bytes.Compare(tf.min, value) == 1 || 
!rangeOpts.IncludesUpper && bytes.Equal(tf.min, value) {
-                                       return false, nil
+                                       return true, nil
                                }
                        }
                }
        }
-       return true, nil
+       return false, nil
 }
 
 // Having checks if any of the provided tag values might exist in the bloom 
filter.
diff --git a/banyand/stream/tag_filter_test.go 
b/banyand/stream/tag_filter_test.go
index ad5fafccd..363b1c621 100644
--- a/banyand/stream/tag_filter_test.go
+++ b/banyand/stream/tag_filter_test.go
@@ -25,6 +25,7 @@ import (
 
        "github.com/stretchr/testify/assert"
 
+       "github.com/apache/skywalking-banyandb/pkg/convert"
        "github.com/apache/skywalking-banyandb/pkg/encoding"
        "github.com/apache/skywalking-banyandb/pkg/filter"
        "github.com/apache/skywalking-banyandb/pkg/fs"
@@ -491,10 +492,8 @@ func generateMetaAndFilterWithScenarios(scenarios []struct 
{
                }
 
                if scenario.hasMinMax && scenario.valueType == 
pbv1.ValueTypeInt64 {
-                       tm.min = make([]byte, 8)
-                       tm.max = make([]byte, 8)
-                       binary.BigEndian.PutUint64(tm.min, 100)
-                       binary.BigEndian.PutUint64(tm.max, 200)
+                       tm.min = convert.Int64ToBytes(100)
+                       tm.max = convert.Int64ToBytes(200)
                }
 
                if scenario.hasFilter {
@@ -600,6 +599,8 @@ func TestTagFamilyFiltersNPEAndUnmarshalBehavior(t 
*testing.T) {
        tff := tfs.tagFamilyFilters[0]
        assert.NotNil(t, tff)
 
+       ops := index.NewIntRangeOpts(150, 180, true, true)
+
        tests := []struct {
                rangeOpts     *index.RangeOpts
                name          string
@@ -662,12 +663,7 @@ func TestTagFamilyFiltersNPEAndUnmarshalBehavior(t 
*testing.T) {
                        eqExpected:    true,
                        eqDescription: "Eq should return true (conservative) 
when filter is nil",
                        testRange:     true,
-                       rangeOpts: &index.RangeOpts{
-                               Lower:         &index.FloatTermValue{Value: 
150.0},
-                               Upper:         &index.FloatTermValue{Value: 
180.0},
-                               IncludesLower: true,
-                               IncludesUpper: true,
-                       },
+                       rangeOpts:     &ops,
                        rangeExpected: false, // should not skip (value is 
within range)
                        rangeErr:      false,
                },
@@ -722,3 +718,156 @@ func TestTagFamilyFiltersNPEAndUnmarshalBehavior(t 
*testing.T) {
                })
        }
 }
+
+func TestTagFamilyFiltersRangeBoundaryCases(t *testing.T) {
+       scenarios := []struct {
+               name       string
+               valueType  pbv1.ValueType
+               hasFilter  bool
+               hasMinMax  bool
+               encodeType encoding.EncodeType
+       }{
+               {
+                       name:       "numeric-tag",
+                       valueType:  pbv1.ValueTypeInt64,
+                       hasFilter:  false,
+                       hasMinMax:  true,
+                       encodeType: encoding.EncodeTypePlain,
+               },
+       }
+
+       metaBuf, filterBuf, tagValueBuf := 
generateMetaAndFilterWithScenarios(scenarios)
+
+       tagFamilies := map[string]*dataBlock{
+               "default": {
+                       offset: 0,
+                       size:   uint64(len(metaBuf)),
+               },
+       }
+       metaReaders := map[string]fs.Reader{
+               "default": &mockReader{data: metaBuf},
+       }
+       filterReaders := map[string]fs.Reader{
+               "default": &mockReader{data: filterBuf},
+       }
+       tagValueReaders := map[string]fs.Reader{
+               "default": &mockReader{data: tagValueBuf},
+       }
+
+       tfs := generateTagFamilyFilters()
+       defer releaseTagFamilyFilters(tfs)
+       tfs.unmarshal(tagFamilies, metaReaders, filterReaders, tagValueReaders)
+
+       tests := []struct {
+               name          string
+               description   string
+               lower         int64
+               upper         int64
+               includesLower bool
+               includesUpper bool
+               expectedSkip  bool
+       }{
+               {
+                       name:          "query above block max - inclusive",
+                       lower:         300,
+                       upper:         400,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  true,
+                       description:   "query [300, 400] vs block [100, 200] 
should skip",
+               },
+               {
+                       name:          "query above block max - adjacent",
+                       lower:         200,
+                       upper:         300,
+                       includesLower: false,
+                       includesUpper: true,
+                       expectedSkip:  true,
+                       description:   "query (200, 300] vs block [100, 200] 
should skip since lower is exclusive",
+               },
+               {
+                       name:          "query below block min - inclusive",
+                       lower:         10,
+                       upper:         50,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  true,
+                       description:   "query [10, 50] vs block [100, 200] 
should skip",
+               },
+               {
+                       name:          "query below block min - adjacent",
+                       lower:         50,
+                       upper:         100,
+                       includesLower: true,
+                       includesUpper: false,
+                       expectedSkip:  true,
+                       description:   "query [50, 100) vs block [100, 200] 
should skip since upper is exclusive",
+               },
+               {
+                       name:          "query overlaps block lower",
+                       lower:         50,
+                       upper:         150,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [50, 150] vs block [100, 200] 
should not skip",
+               },
+               {
+                       name:          "query overlaps block upper",
+                       lower:         150,
+                       upper:         250,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [150, 250] vs block [100, 200] 
should not skip",
+               },
+               {
+                       name:          "query contains block",
+                       lower:         50,
+                       upper:         250,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [50, 250] vs block [100, 200] 
should not skip",
+               },
+               {
+                       name:          "query within block",
+                       lower:         120,
+                       upper:         180,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [120, 180] vs block [100, 200] 
should not skip",
+               },
+               {
+                       name:          "inclusive lower equals block max",
+                       lower:         200,
+                       upper:         300,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [200, 300] vs block [100, 200] 
should not skip since lower is inclusive",
+               },
+               {
+                       name:          "inclusive upper equals block min",
+                       lower:         50,
+                       upper:         100,
+                       includesLower: true,
+                       includesUpper: true,
+                       expectedSkip:  false,
+                       description:   "query [50, 100] vs block [100, 200] 
should not skip since upper is inclusive",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       tester := assert.New(t)
+
+                       rangeOpts := index.NewIntRangeOpts(tt.lower, tt.upper, 
tt.includesLower, tt.includesUpper)
+                       shouldSkip, err := tfs.Range("numeric-tag", rangeOpts)
+
+                       tester.NoError(err)
+                       tester.Equal(tt.expectedSkip, shouldSkip, 
tt.description)
+               })
+       }
+}

Reply via email to