Merge branch 'master' into union-run-run

This commit is contained in:
Kuba Podgórski 2020-06-26 22:32:07 +02:00 committed by GitHub
commit d99971a6c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 210 additions and 373 deletions

View file

@ -361,7 +361,7 @@ func TestAPI_ImportValue(t *testing.T) {
if err != nil {
t.Fatalf("creating index: %v", err)
}
fld, err := m1.API.CreateField(ctx, index, field, pilosa.OptFieldTypeDecimal(1))
_, err = m1.API.CreateField(ctx, index, field, pilosa.OptFieldTypeDecimal(1))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -386,66 +386,14 @@ func TestAPI_ImportValue(t *testing.T) {
t.Fatal(err)
}
pql := fmt.Sprintf("Row(%s>6)", field)
query := fmt.Sprintf("Row(%s>6)", field)
// Query node0.
if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: pql}); err != nil {
if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: query}); err != nil {
t.Fatal(err)
} else if ids := res.Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(ids, colIDs[6:]) {
t.Fatalf("unexpected column keys: %+v", ids)
}
sum, count, err := fld.FloatSum(nil, field)
if err != nil {
t.Fatalf("getting floatsum: %v", err)
} else if sum != 0.1+1.1+2.1+3.1+4.1+5.1+6.1+7.1+8.1+9.1 {
t.Fatalf("unexpected sum: %f", sum)
} else if count != 10 {
t.Fatalf("unexpected count: %d", count)
}
min, count, err := fld.FloatMin(nil, field)
if err != nil {
t.Fatalf("getting floatmin: %v", err)
} else if min != 0.1 {
t.Fatalf("unexpected min: %f", min)
} else if count != 1 {
t.Fatalf("unexpected count: %d", count)
}
max, count, err := fld.FloatMax(nil, field)
if err != nil {
t.Fatalf("getting floatmax: %v", err)
} else if max != 9.1 {
t.Fatalf("unexpected max: %f", max)
} else if count != 1 {
t.Fatalf("unexpected count: %d", count)
}
val, exists, err := fld.FloatValue(1)
if err != nil {
t.Fatalf("unepxected err getting floatvalue")
} else if !exists {
t.Fatalf("column 1 should exist")
} else if val != 1.1 {
t.Fatalf("unexpected floatvalue %f", val)
}
changed, err := fld.SetFloatValue(11, 11.1)
if err != nil {
t.Fatalf("setting float value: %v", err)
} else if !changed {
t.Fatalf("expected change")
}
val, exists, err = fld.FloatValue(11)
if err != nil {
t.Fatalf("getting float val: %v", err)
} else if !exists {
t.Fatalf("should exist")
} else if val != 11.1 {
t.Fatalf("unexpected val: %f", 11.1)
}
})
t.Run("ValDecimalFieldNegativeScale", func(t *testing.T) {

View file

@ -121,7 +121,8 @@ func (c *lruCache) Top() []bitmapPair {
Count: n,
})
}
sort.Sort(bitmapPairs(a))
pairs := bitmapPairs(a)
sort.Sort(&pairs)
return a
}
@ -137,9 +138,10 @@ var _ cache = &lruCache{}
// rankCache represents a cache with sorted entries.
type rankCache struct {
mu sync.Mutex
entries map[uint64]uint64
rankings []bitmapPair // cached, ordered list
mu sync.Mutex
entries map[uint64]uint64
rankings bitmapPairs // cached, ordered list
rankingsRead bool
updateN int
updateTime time.Time
@ -214,12 +216,15 @@ func (c *rankCache) Len() int {
func (c *rankCache) IDs() []uint64 {
c.mu.Lock()
defer c.mu.Unlock()
a := make([]uint64, 0, len(c.entries))
for id := range c.entries {
a = append(a, id)
if len(c.entries) == 0 {
return nil
}
sort.Sort(uint64Slice(a))
return a
ids := make([]uint64, 0, len(c.entries))
for id := range c.entries {
ids = append(ids, id)
}
sort.Sort(uint64Slice(ids))
return ids
}
// Invalidate recalculates the entries by rank.
@ -248,18 +253,26 @@ func (c *rankCache) invalidate() {
}
func (c *rankCache) recalculate() {
if c.rankingsRead {
c.rankings = nil
c.rankingsRead = false
}
// Convert cache to a sorted list.
rankings := make([]bitmapPair, 0, len(c.entries))
rankings := c.rankings[:0]
if cap(rankings) < len(c.entries) {
rankings = make([]bitmapPair, 0, len(c.entries))
}
for id, cnt := range c.entries {
rankings = append(rankings, bitmapPair{
ID: id,
Count: cnt,
})
}
sort.Sort(bitmapPairs(rankings))
c.rankings = rankings
sort.Sort(&c.rankings)
// Store the count of the item at the threshold index.
c.rankings = rankings
length := len(c.rankings)
c.stats.Gauge(MetricRankCacheLength, float64(length), 1.0)
@ -290,7 +303,13 @@ func (c *rankCache) SetStats(s stats.StatsClient) {
}
// Top returns an ordered list of pairs.
func (c *rankCache) Top() []bitmapPair { return c.rankings }
func (c *rankCache) Top() []bitmapPair {
c.mu.Lock()
defer c.mu.Unlock()
c.rankingsRead = true
return c.rankings
}
// WriteTo writes the cache to w.
func (c *rankCache) WriteTo(w io.Writer) (n int64, err error) {
@ -314,9 +333,9 @@ type bitmapPair struct {
// bitmapPairs is a sortable list of BitmapPair objects.
type bitmapPairs []bitmapPair
func (p bitmapPairs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p bitmapPairs) Len() int { return len(p) }
func (p bitmapPairs) Less(i, j int) bool { return p[i].Count > p[j].Count }
func (p *bitmapPairs) Swap(i, j int) { (*p)[i], (*p)[j] = (*p)[j], (*p)[i] }
func (p *bitmapPairs) Len() int { return len(*p) }
func (p *bitmapPairs) Less(i, j int) bool { return (*p)[i].Count > (*p)[j].Count }
// Pair holds an id/count pair.
type Pair struct {

View file

@ -2427,18 +2427,11 @@ func (e *executor) executeRowShard(ctx context.Context, index string, c *pql.Cal
if err != nil {
return nil, errors.New("Row() argument required: field")
}
f := e.Holder.Field(index, fieldName)
f := idx.Field(fieldName)
if f == nil {
return nil, ErrFieldNotFound
}
rowID, rowOK, rowErr := c.UintArg(fieldName)
if rowErr != nil {
return nil, fmt.Errorf("Row() error with arg for row: %v", rowErr)
} else if !rowOK {
return nil, fmt.Errorf("Row() must specify %v", rowLabel)
}
// Parse "from" time, if set.
var fromTime time.Time
if v, ok := c.Args["from"]; ok {
@ -2455,8 +2448,33 @@ func (e *executor) executeRowShard(ctx context.Context, index string, c *pql.Cal
}
}
timeNotSet := fromTime.IsZero() && toTime.IsZero()
// This is workaround to support pql.ASSIGN ('=') as condition ('==') for int and decimal fields
if c.Name == "Row" && timeNotSet &&
(f.Type() == FieldTypeInt || f.Type() == FieldTypeDecimal) {
// re-write args as conditions for fieldName
for k, v := range c.Args {
if _, ok := v.(*pql.Condition); k == fieldName && !ok {
c.Args[k] = &pql.Condition{
Op: pql.EQ,
Value: v,
}
return e.executeRowBSIGroupShard(ctx, index, c, shard)
}
}
}
rowID, rowOK, rowErr := c.UintArg(fieldName)
if rowErr != nil {
return nil, fmt.Errorf("Row() error with arg for row: %v", rowErr)
} else if !rowOK {
return nil, fmt.Errorf("Row() must specify %v", rowLabel)
}
// Simply return row if times are not set.
if c.Name == "Row" && fromTime.IsZero() && toTime.IsZero() {
if c.Name == "Row" && timeNotSet {
frag := e.Holder.fragment(index, fieldName, viewStandard, shard)
if frag == nil {
return NewRow(), nil

View file

@ -3027,6 +3027,121 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
test.CheckGroupBy(t, expected, results)
}
})
t.Run("Row on ints with ASSIGN condition", func(t *testing.T) {
_, err := c[0].API.CreateIndex(context.Background(), "intidx", pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c[0].API.CreateField(context.Background(), "intidx", "gint", pilosa.OptFieldTypeInt(-1000, 1000))
if err != nil {
t.Fatalf("creating field: %v", err)
}
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "intidx", Query: `
Set(1000, gint=1)
Set(2000, gint=2)
Set(3000, gint=3)
`}); err != nil {
t.Fatalf("querying remote: %v", err)
}
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{
Index: "intidx",
Query: `Row(gint=2)Row(gint==1)`,
}); err != nil {
t.Fatalf("Row querying: %v", err)
} else {
row0, row1 := res.Results[0].(*pilosa.Row), res.Results[1].(*pilosa.Row)
if len(row0.Columns()) != 1 || len(row1.Columns()) != 1 {
t.Fatalf(`Expected: []uint64{2000} []uint64{1000}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
if row0.Columns()[0] != 2000 || row1.Columns()[0] != 1000 {
t.Fatalf(`Expected: []uint64{2000} []uint64{1000}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
}
})
t.Run("Row on decimals with ASSIGN condition", func(t *testing.T) {
_, err := c[0].API.CreateIndex(context.Background(), "decidx", pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c[0].API.CreateField(context.Background(), "decidx", "fdec", pilosa.OptFieldTypeDecimal(0))
if err != nil {
t.Fatalf("creating field: %v", err)
}
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "decidx", Query: `
Set(11, fdec=1.1)
Set(22, fdec=2.2)
Set(33, fdec=3.3)
`}); err != nil {
t.Fatalf("querying remote: %v", err)
}
if res, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{
Index: "decidx",
Query: `Row(fdec=2.2)Row(fdec==1.1)`,
}); err != nil {
t.Fatalf("Row querying: %v", err)
} else {
row0, row1 := res.Results[0].(*pilosa.Row), res.Results[1].(*pilosa.Row)
if len(row0.Columns()) != 1 || len(row1.Columns()) != 1 {
t.Fatalf(`Expected: []uint64{22} []uint64{11}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
if row0.Columns()[0] != 22 || row1.Columns()[0] != 11 {
t.Fatalf(`Expected: []uint64{22} []uint64{11}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
}
})
t.Run("Row on foreign key with ASSIGN condition", func(t *testing.T) {
_, err := c[0].API.CreateIndex(context.Background(), "parent", pilosa.IndexOptions{Keys: true})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c[0].API.CreateField(context.Background(), "parent", "general", pilosa.OptFieldTypeSet(pilosa.DefaultCacheType, pilosa.DefaultCacheSize))
if err != nil {
t.Fatalf("creating field: %v", err)
}
_, err = c[0].API.CreateIndex(context.Background(), "child", pilosa.IndexOptions{Keys: false})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c[0].API.CreateField(context.Background(), "child", "parentid",
pilosa.OptFieldForeignIndex("parent"),
pilosa.OptFieldTypeInt(-9223372036854775808, 9223372036854775807),
)
if err != nil {
t.Fatalf("creating field: %v", err)
}
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "child", Query: `
Set(1, parentid="one")
Set(2, parentid="two")
Set(3, parentid="three")
`}); err != nil {
t.Fatalf("querying remote: %v", err)
}
if res, err := c[1].API.Query(context.Background(), &pilosa.QueryRequest{
Index: "child",
Query: `Row(parentid="two")Row(parentid=="one")`,
}); err != nil {
t.Fatalf("Row querying: %v", err)
} else {
row0, row1 := res.Results[0].(*pilosa.Row), res.Results[1].(*pilosa.Row)
if len(row0.Columns()) != 1 || len(row1.Columns()) != 1 {
t.Fatalf(`Expected: []uint64{1} []uint64{0}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
if row0.Columns()[0] != 2 || row1.Columns()[0] != 1 {
t.Fatalf(`Expected: []uint64{1} []uint64{0}, Got: %+v %+v`, row0.Columns(), row1.Columns())
}
}
})
}
// Ensure executor returns an error if too many writes are in a single request.

155
field.go
View file

@ -1376,37 +1376,6 @@ func (f *Field) StringValue(columnID uint64) (value string, exists bool, err err
return value, exists, err
}
// FloatValue reads an integer field value for a column, and converts
// it to a float based on the configured scale.
func (f *Field) FloatValue(columnID uint64) (value float64, exists bool, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return 0, false, ErrBSIGroupNotFound
}
val, exists, err := f.Value(columnID)
if exists {
value = float64(val) / math.Pow10(int(bsig.Scale))
}
return value, exists, err
}
// DecimalValue reads a decimal field value for a column, and converts
// it to a pql.Decimal based on the configured scale.
func (f *Field) DecimalValue(columnID uint64) (value pql.Decimal, exists bool, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return value, false, ErrBSIGroupNotFound
}
val, exists, err := f.Value(columnID)
if exists {
value.Value = val
value.Scale = bsig.Scale
}
return value, exists, err
}
// Value reads a field value for a column.
func (f *Field) Value(columnID uint64) (value int64, exists bool, err error) {
bsig := f.bsiGroup(f.name)
@ -1429,18 +1398,6 @@ func (f *Field) Value(columnID uint64) (value int64, exists bool, err error) {
return int64(v) + bsig.Base, true, nil
}
// SetFloatValue takes a floating point value, and converts it to an
// integer based on the field's configured scale, before setting that
// integer via SetValue.
func (f *Field) SetFloatValue(columnID uint64, value float64) (changed bool, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return false, ErrBSIGroupNotFound
}
val := int64(float64(value) * math.Pow10(int(bsig.Scale)))
return f.SetValue(columnID, val)
}
// SetValue sets a field value for a column.
func (f *Field) SetValue(columnID uint64, value int64) (changed bool, err error) {
// Fetch bsiGroup & validate min/max.
@ -1506,98 +1463,6 @@ func (f *Field) ClearValue(columnID uint64) (changed bool, err error) {
return false, nil
}
// FloatSum performs a Sum query and converts the result to a float
// based on the field's configured scale.
func (f *Field) FloatSum(filter *Row, name string) (sum float64, count int64, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
sumI, count, err := f.Sum(filter, name)
if err == nil {
sum = float64(sumI) / math.Pow10(int(bsig.Scale))
}
return sum, count, err
}
// Sum returns the sum and count for a field.
// An optional filtering row can be provided.
func (f *Field) Sum(filter *Row, name string) (sum, count int64, err error) {
bsig := f.bsiGroup(name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
view := f.view(viewBSIGroupPrefix + name)
if view == nil {
return 0, 0, nil
}
vsum, vcount, err := view.sum(filter, bsig.BitDepth)
if err != nil {
return 0, 0, err
}
return int64(vsum) + (int64(vcount) * bsig.Base), int64(vcount), nil
}
// FloatMin performs a Min query and converts the result to a float
// based on the field's configured scale.
// TODO: this and Min are probably worthless
func (f *Field) FloatMin(filter *Row, name string) (min float64, count int64, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
minI, count, err := f.Min(filter, name)
if err == nil {
min = float64(minI) / math.Pow10(int(bsig.Scale))
}
return min, count, err
}
// Min returns the min for a field.
// An optional filtering row can be provided.
func (f *Field) Min(filter *Row, name string) (min, count int64, err error) {
bsig := f.bsiGroup(name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
view := f.view(viewBSIGroupPrefix + name)
if view == nil {
return 0, 0, nil
}
vmin, vcount, err := view.min(filter, bsig.BitDepth)
if err != nil {
return 0, 0, err
}
return int64(vmin) + bsig.Base, int64(vcount), nil
}
// FloatMax performs a max query and converts the result to a float
// based on the field's configured scale.
//
// TODO, this isn't really used, because it's kind of useless. It will
// only get the max among shards on this node, but all query execution
// already happens at the shard level and bypasses this entirely
// calling fragment.max instead.
func (f *Field) FloatMax(filter *Row, name string) (max float64, count int64, err error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
maxI, count, err := f.Max(filter, name)
if err == nil {
max = float64(maxI) / math.Pow10(int(bsig.Scale))
}
return max, count, err
}
func (f *Field) MaxForShard(shard uint64, filter *Row) (ValCount, error) {
bsig := f.bsiGroup(f.name)
if bsig == nil {
@ -1667,26 +1532,6 @@ func (f *Field) MinForShard(shard uint64, filter *Row) (ValCount, error) {
return valCount, nil
}
// Max returns the max for a field.
// An optional filtering row can be provided.
func (f *Field) Max(filter *Row, name string) (max, count int64, err error) {
bsig := f.bsiGroup(name)
if bsig == nil {
return 0, 0, ErrBSIGroupNotFound
}
view := f.view(viewBSIGroupPrefix + name)
if view == nil {
return 0, 0, nil
}
vmax, vcount, err := view.max(filter, bsig.BitDepth)
if err != nil {
return 0, 0, err
}
return int64(vmax) + bsig.Base, int64(vcount), nil
}
// Range performs a conditional operation on Field.
func (f *Field) Range(name string, op pql.Token, predicate int64) (*Row, error) {
// Retrieve and validate bsiGroup.

View file

@ -1647,7 +1647,8 @@ func (f *fragment) topBitmapPairs(rowIDs []uint64) []bitmapPair {
})
}
}
sort.Sort(bitmapPairs(pairs))
sortPairs := bitmapPairs(pairs)
sort.Sort(&sortPairs)
return pairs
}

View file

@ -777,7 +777,7 @@ func TestClient_ImportKeys(t *testing.T) {
// Load bitmap into cache to ensure cache gets updated.
index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{Keys: true})
field, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
_, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
if err != nil {
t.Fatal(err)
}
@ -792,15 +792,6 @@ func TestClient_ImportKeys(t *testing.T) {
t.Fatal(err)
}
// Verify Sum.
sum, cnt, err := field.Sum(nil, fldName)
if err != nil {
t.Fatal(err)
}
if sum != 50 || cnt != 3 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=50, cnt=3", sum, cnt)
}
// Verify range.
queryRequest := &pilosa.QueryRequest{
Query: fmt.Sprintf(`Row(%s>10)`, fldName),
@ -823,15 +814,6 @@ func TestClient_ImportKeys(t *testing.T) {
t.Fatal(err)
}
// Verify Sum.
sum, cnt, err = field.Sum(nil, fldName)
if err != nil {
t.Fatal(err)
}
if sum != 30 || cnt != 2 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=30, cnt=2", sum, cnt)
}
// Verify Range.
queryRequest = &pilosa.QueryRequest{
Query: fmt.Sprintf(`Row(%s>10)`, fldName),
@ -928,7 +910,7 @@ func TestClient_ImportValue(t *testing.T) {
// Load bitmap into cache to ensure cache gets updated.
index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{})
field, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
_, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
if err != nil {
t.Fatal(err)
}
@ -944,43 +926,21 @@ func TestClient_ImportValue(t *testing.T) {
}
// Verify Sum.
sum, cnt, err := field.Sum(nil, fldName)
if err != nil {
if resp, err := c.Query(context.Background(), "i", &pilosa.QueryRequest{Query: `Sum(field=f)`}); err != nil {
t.Fatal(err)
}
if sum != 50 || cnt != 3 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=50, cnt=3", sum, cnt)
}
// Verify Min.
min, cnt, err := field.Min(nil, fldName)
if err != nil {
t.Fatal(err)
}
if min != -10 || cnt != 1 {
t.Fatalf("unexpected values: got min=%v, count=%v; expected min=-10, cnt=1", min, cnt)
}
// Verify Min with Filter.
filter, err := field.Range(fldName, pql.GT, 40)
if err != nil {
t.Fatal(err)
}
min, cnt, err = field.Min(filter, fldName)
if err != nil {
t.Fatal(err)
}
if min != 0 || cnt != 0 {
t.Fatalf("unexpected values: got min=%v, count=%v; expected min=0, cnt=0", min, cnt)
} else if vc, ok := resp.Results[0].(pilosa.ValCount); !ok {
t.Fatalf("expected ValCount; got %T", resp.Results[0])
} else if vc.Val != 50 || vc.Count != 3 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=50, cnt=3", vc.Val, vc.Count)
}
// Verify Max.
max, cnt, err := field.Max(nil, fldName)
if err != nil {
if resp, err := c.Query(context.Background(), "i", &pilosa.QueryRequest{Query: `Max(field=f)`}); err != nil {
t.Fatal(err)
}
if max != 40 || cnt != 1 {
t.Fatalf("unexpected values: got max=%v, count=%v; expected max=40, cnt=1", max, cnt)
} else if vc, ok := resp.Results[0].(pilosa.ValCount); !ok {
t.Fatalf("expected ValCount; got %T", resp.Results[0])
} else if vc.Val != 40 || vc.Count != 1 {
t.Fatalf("unexpected values: got max=%v, count=%v; expected max=40, cnt=1", vc.Val, vc.Count)
}
// Send import request.
@ -992,34 +952,21 @@ func TestClient_ImportValue(t *testing.T) {
}
// Verify Sum.
sum, cnt, err = field.Sum(nil, fldName)
if err != nil {
if resp, err := c.Query(context.Background(), "i", &pilosa.QueryRequest{Query: `Sum(field=f)`}); err != nil {
t.Fatal(err)
}
if sum != 20 || cnt != 1 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=20, cnt=1", sum, cnt)
}
// Verify Min with Filter.
filter, err = field.Range(fldName, pql.GT, 40)
if err != nil {
t.Fatal(err)
}
min, cnt, err = field.Min(filter, fldName)
if err != nil {
t.Fatal(err)
}
if min != 0 || cnt != 0 {
t.Fatalf("unexpected values: got min=%v, count=%v; expected min=0, cnt=0", min, cnt)
} else if vc, ok := resp.Results[0].(pilosa.ValCount); !ok {
t.Fatalf("expected ValCount; got %T", resp.Results[0])
} else if vc.Val != 20 || vc.Count != 1 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=20, cnt=1", vc.Val, vc.Count)
}
// Verify Max.
max, cnt, err = field.Max(nil, fldName)
if err != nil {
if resp, err := c.Query(context.Background(), "i", &pilosa.QueryRequest{Query: `Max(field=f)`}); err != nil {
t.Fatal(err)
}
if max != 20 || cnt != 1 {
t.Fatalf("unexpected values: got max=%v, count=%v; expected max=20, cnt=1", max, cnt)
} else if vc, ok := resp.Results[0].(pilosa.ValCount); !ok {
t.Fatalf("expected ValCount; got %T", resp.Results[0])
} else if vc.Val != 20 || vc.Count != 1 {
t.Fatalf("unexpected values: got max=%v, count=%v; expected max=20, cnt=1", vc.Val, vc.Count)
}
}
@ -1071,7 +1018,7 @@ func TestClient_ImportExistence(t *testing.T) {
fldName := "fint"
index := hldr.MustCreateIndexIfNotExists(idxName, pilosa.IndexOptions{TrackExistence: true})
field, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
_, err := index.CreateFieldIfNotExists(fldName, pilosa.OptFieldTypeInt(-100, 100))
if err != nil {
t.Fatal(err)
}
@ -1087,12 +1034,12 @@ func TestClient_ImportExistence(t *testing.T) {
}
// Verify Sum.
sum, cnt, err := field.Sum(nil, fldName)
if err != nil {
if resp, err := c.Query(context.Background(), idxName, &pilosa.QueryRequest{Query: fmt.Sprintf(`Sum(field=%s)`, fldName)}); err != nil {
t.Fatal(err)
}
if sum != 50 || cnt != 3 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=50, cnt=3", sum, cnt)
} else if vc, ok := resp.Results[0].(pilosa.ValCount); !ok {
t.Fatalf("expected ValCount; got %T", resp.Results[0])
} else if vc.Val != 50 || vc.Count != 3 {
t.Fatalf("unexpected values: got sum=%v, count=%v; expected sum=50, cnt=3", vc.Val, vc.Count)
}
// Verify existence.

56
view.go
View file

@ -469,62 +469,6 @@ func (v *view) clearValue(columnID uint64, bitDepth uint, value int64) (changed
return frag.clearValue(columnID, bitDepth, value)
}
// sum returns the sum & count of a field.
func (v *view) sum(filter *Row, bitDepth uint) (sum int64, count uint64, err error) {
for _, f := range v.allFragments() {
fsum, fcount, err := f.sum(filter, bitDepth)
if err != nil {
return sum, count, err
}
sum += fsum
count += fcount
}
return sum, count, nil
}
// min returns the min and count of a field.
func (v *view) min(filter *Row, bitDepth uint) (min int64, count uint64, err error) {
var minHasValue bool
for _, f := range v.allFragments() {
fmin, fcount, err := f.min(filter, bitDepth)
if err != nil {
return min, count, err
}
// Don't consider a min based on zero columns.
if fcount == 0 {
continue
}
if !minHasValue {
min = fmin
minHasValue = true
count += fcount
continue
}
if fmin < min {
min = fmin
count += fcount
}
}
return min, count, nil
}
// max returns the max and count of a field.
func (v *view) max(filter *Row, bitDepth uint) (max int64, count uint64, err error) {
for _, f := range v.allFragments() {
fmax, fcount, err := f.max(filter, bitDepth)
if err != nil {
return max, count, err
}
if fcount > 0 && fmax > max {
max = fmax
count += fcount
}
}
return max, count, nil
}
// rangeOp returns rows with a field value encoding matching the predicate.
func (v *view) rangeOp(op pql.Token, bitDepth uint, predicate int64) (*Row, error) {
r := NewRow()