diff --git a/executor.go b/executor.go index bc9b3014e..d563bf5f9 100644 --- a/executor.go +++ b/executor.go @@ -1303,15 +1303,22 @@ func (e *executor) executePercentile(ctx context.Context, qcx *Qcx, index string defer span.Finish() // get nth - var nth float64 - if nthArg, ok := c.Args["nth"].(pql.Decimal); ok { - nth = nthArg.Float64() - if nth < 0 || nth > 1.0 { - return ValCount{}, errors.Errorf("Percentile(): invalid nth value(%f), should be >= 0 and <= 1.0", nth) - } - } else { + var nthFloat float64 + nthArg, ok := c.Args["nth"] + if !ok { return ValCount{}, errors.New("Percentile(): nth required") } + switch nthArg := nthArg.(type) { + case pql.Decimal: + nthFloat = nthArg.Float64() + case int64: + nthFloat = float64(nthArg) + default: + return ValCount{}, errors.Errorf("Percentile(): invalid nth='%v' of type (%[1]T), should be a number between 0 and 100 inclusive", c.Args["nth"]) + } + if nthFloat < 0 || nthFloat > 100.0 { + return ValCount{}, errors.Errorf("Percentile(): invalid nth value (%f), should be a number between 0 and 100 inclusive", nthFloat) + } // get field if fieldArg := c.Args["field"]; fieldArg == "" { @@ -1337,7 +1344,7 @@ func (e *executor) executePercentile(ctx context.Context, qcx *Qcx, index string if err != nil { return ValCount{}, errors.Wrap(err, "executing Min call for Percentile") } - if nth == 0.0 { + if nthFloat == 0.0 { return ValCount{Val: minVal.Val, Count: minVal.Count}, nil } @@ -1365,7 +1372,7 @@ func (e *executor) executePercentile(ctx context.Context, qcx *Qcx, index string rangeCall = intersectCall.Children[0] } - k := (1 - nth) / nth + k := (100 - nthFloat) / nthFloat min, max := minVal.Val, maxVal.Val // estimate nth val, eg median when nth=0.5 diff --git a/executor_test.go b/executor_test.go index e3cb9282b..9a53ff35a 100644 --- a/executor_test.go +++ b/executor_test.go @@ -7055,7 +7055,7 @@ func variousQueriesOnPercentiles(t *testing.T, c *test.Cluster) { if nth == 0.0 { return min } - k := (1 - nth) / nth + k := (100 - nth) / nth possibleNthVal := int64(0) // bin search @@ -7129,9 +7129,9 @@ func variousQueriesOnPercentiles(t *testing.T, c *test.Cluster) { } // generate test cases per each nth argument - nths := []float64{0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99} + nthsFloat := []float64{0, 10, 25, 50, 75, 90, 99} var tests []testCase - for _, nth := range nths { + for _, nth := range nthsFloat { query := fmt.Sprintf(`Percentile(field="net_worth", filter=Row(val="foo"), nth=%f)`, nth) expectedPercentile := getExpectedPercentile(nums, nth) tests = append(tests, testCase{ @@ -7139,6 +7139,15 @@ func variousQueriesOnPercentiles(t *testing.T, c *test.Cluster) { csvVerifier: fmt.Sprintf("%d,1\n", expectedPercentile), }) } + nthsInt := []int64{0, 10, 100} + for _, nth := range nthsInt { + query := fmt.Sprintf(`Percentile(field="net_worth", filter=Row(val="foo"), nth=%d)`, nth) + expectedPercentile := getExpectedPercentile(nums, float64(nth)) + tests = append(tests, testCase{ + query: query, + csvVerifier: fmt.Sprintf("%d,1\n", expectedPercentile), + }) + } for i, tst := range tests { t.Run(fmt.Sprintf("%d-%s", i, tst.query), func(t *testing.T) {