2022-05-06 17:43:51 +08:00
|
|
|
package planparserv2
|
|
|
|
|
|
|
|
import (
|
2022-05-20 18:47:57 +08:00
|
|
|
"sync"
|
2022-05-06 17:43:51 +08:00
|
|
|
"testing"
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
"github.com/milvus-io/milvus/pkg/common"
|
|
|
|
|
2022-10-16 20:49:27 +08:00
|
|
|
"github.com/milvus-io/milvus-proto/go-api/schemapb"
|
2023-05-16 16:19:22 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/planpb"
|
2023-04-06 19:14:32 +08:00
|
|
|
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
2023-05-16 16:19:22 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
2022-05-06 17:43:51 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
func newTestSchema() *schemapb.CollectionSchema {
|
|
|
|
fields := []*schemapb.FieldSchema{
|
|
|
|
{FieldID: 0, Name: "FieldID", IsPrimaryKey: false, Description: "field no.1", DataType: schemapb.DataType_Int64},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, value := range schemapb.DataType_value {
|
|
|
|
dataType := schemapb.DataType(value)
|
|
|
|
newField := &schemapb.FieldSchema{
|
|
|
|
FieldID: int64(100 + value), Name: name + "Field", IsPrimaryKey: false, Description: "", DataType: dataType,
|
|
|
|
}
|
|
|
|
fields = append(fields, newField)
|
|
|
|
}
|
2023-05-18 09:33:24 +08:00
|
|
|
fields = append(fields, &schemapb.FieldSchema{
|
|
|
|
FieldID: 199, Name: common.MetaFieldName, IsPrimaryKey: false, Description: "dynamic field", DataType: schemapb.DataType_JSON,
|
|
|
|
IsDynamic: true,
|
|
|
|
})
|
2022-05-06 17:43:51 +08:00
|
|
|
|
|
|
|
return &schemapb.CollectionSchema{
|
2023-05-18 09:33:24 +08:00
|
|
|
Name: "test",
|
|
|
|
Description: "schema for test used",
|
|
|
|
AutoID: true,
|
|
|
|
Fields: fields,
|
|
|
|
EnableDynamicField: true,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertValidExpr(t *testing.T, helper *typeutil.SchemaHelper, exprStr string) {
|
|
|
|
_, err := ParseExpr(helper, exprStr)
|
|
|
|
assert.NoError(t, err, exprStr)
|
|
|
|
|
|
|
|
// expr, err := ParseExpr(helper, exprStr)
|
|
|
|
// assert.NoError(t, err, exprStr)
|
|
|
|
// fmt.Printf("expr: %s\n", exprStr)
|
|
|
|
// ShowExpr(expr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertInvalidExpr(t *testing.T, helper *typeutil.SchemaHelper, exprStr string) {
|
|
|
|
_, err := ParseExpr(helper, exprStr)
|
|
|
|
assert.Error(t, err, exprStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Term(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`BoolField in [true, false]`,
|
|
|
|
`Int8Field in [1, 2]`,
|
|
|
|
`Int16Field in [3, 4]`,
|
|
|
|
`Int32Field in [5, 6]`,
|
|
|
|
`Int64Field in [7, 8]`,
|
|
|
|
`FloatField in [9.0, 10.0]`,
|
|
|
|
`DoubleField in [11.0, 12.0]`,
|
|
|
|
`StringField in ["str13", "str14"]`,
|
|
|
|
`VarCharField in ["str15", "str16"]`,
|
|
|
|
`FloatField in [1373, 115]`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`Int64Field in [17]`,
|
2022-05-06 17:43:51 +08:00
|
|
|
`Int64Field in []`,
|
|
|
|
`Int64Field not in []`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"] in [1, 10]`,
|
|
|
|
`JSONField["A"] in []`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"] in [1, 10]`,
|
|
|
|
`$meta["A"] in []`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`A in [1, 10]`,
|
|
|
|
`A in []`,
|
|
|
|
`A in ["abc", "def"]`,
|
|
|
|
`A in ["1", "2", "abc", "def"]`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Compare(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`Int8Field < Int16Field`,
|
|
|
|
`Int16Field <= Int32Field`,
|
|
|
|
`Int32Field > Int64Field`,
|
|
|
|
`Int64Field >= FloatField`,
|
|
|
|
`FloatField == DoubleField`,
|
|
|
|
`StringField != VarCharField`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"] > Int16Field`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"] > Int16Field`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_UnaryRange(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`Int8Field < 0`,
|
|
|
|
`Int16Field <= 1`,
|
|
|
|
`Int32Field > 2`,
|
|
|
|
`Int64Field >= 3`,
|
|
|
|
`FloatField == 4.0`,
|
|
|
|
`FloatField == 2`,
|
|
|
|
`DoubleField != 5.0`,
|
|
|
|
`StringField > "str6"`,
|
|
|
|
`VarCharField <= "str7"`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"] > 10`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"] > 10`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Like(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`VarCharField like "prefix%"`,
|
2022-05-07 16:31:52 +08:00
|
|
|
`VarCharField like "equal"`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"] like "name*"`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"] like "name*"`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
2022-05-07 16:31:52 +08:00
|
|
|
|
|
|
|
// TODO: enable these after regex-match is supported.
|
|
|
|
unsupported := []string{
|
|
|
|
`VarCharField like "not_%_supported"`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"] like "not_%_supported"`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"] like "not_%_supported"`,
|
2022-05-07 16:31:52 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range unsupported {
|
|
|
|
assertInvalidExpr(t, helper, exprStr)
|
|
|
|
}
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_BinaryRange(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`1 < Int8Field < 2`,
|
|
|
|
`3 <= Int16Field < 4`,
|
|
|
|
`5 <= Int32Field <= 6`,
|
|
|
|
`7 < Int64Field <= 8`,
|
|
|
|
`9.0 < FloatField < 10.0`,
|
|
|
|
`11.0 < DoubleField < 12.0`,
|
|
|
|
`"str13" < StringField < "str14"`,
|
|
|
|
`"str15" < VarCharField < "str16"`,
|
|
|
|
`17 < DoubleField < 18`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`10 < A < 25`,
|
2022-05-06 17:43:51 +08:00
|
|
|
|
|
|
|
`2 > Int8Field > 1`,
|
|
|
|
`4 >= Int16Field >= 3`,
|
|
|
|
`6 >= Int32Field >= 5`,
|
|
|
|
`8 >= Int64Field > 7`,
|
|
|
|
`10.0 > FloatField > 9.0`,
|
|
|
|
`12.0 > DoubleField > 11.0`,
|
|
|
|
`"str14" > StringField > "str13"`,
|
|
|
|
`"str16" > VarCharField > "str15"`,
|
|
|
|
`18 > DoubleField > 17`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`100 > B > 14`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_BinaryArith(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`Int64Field % 10 == 9`,
|
|
|
|
`Int64Field % 10 != 9`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`A % 10 != 2`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: enable these after execution backend is ready.
|
|
|
|
unsupported := []string{
|
|
|
|
`Int8Field + 1 < 2`,
|
|
|
|
`Int16Field - 3 <= 4`,
|
|
|
|
`Int32Field * 5 > 6`,
|
|
|
|
`Int64Field / 7 >= 8`,
|
|
|
|
`FloatField + 11 < 12`,
|
|
|
|
`DoubleField - 13 < 14`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`A - 15 < 16`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range unsupported {
|
|
|
|
assertInvalidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Value(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`1`,
|
|
|
|
`2.0`,
|
|
|
|
`true`,
|
|
|
|
`false`,
|
|
|
|
`"str"`,
|
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
expr := handleExpr(helper, exprStr)
|
|
|
|
assert.NotNil(t, getExpr(expr).expr, exprStr)
|
|
|
|
// fmt.Printf("expr: %s\n", exprStr)
|
|
|
|
// ShowExpr(getExpr(expr).expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Identifier(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`BoolField`,
|
|
|
|
`Int8Field`,
|
|
|
|
`Int16Field`,
|
|
|
|
`Int32Field`,
|
|
|
|
`Int64Field`,
|
|
|
|
`FloatField`,
|
|
|
|
`DoubleField`,
|
|
|
|
`StringField`,
|
|
|
|
`VarCharField`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`JSONField["A"]`,
|
2023-05-18 09:33:24 +08:00
|
|
|
`$meta["A"]`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
expr := handleExpr(helper, exprStr)
|
|
|
|
assert.NotNil(t, getExpr(expr).expr, exprStr)
|
|
|
|
|
|
|
|
// fmt.Printf("expr: %s\n", exprStr)
|
|
|
|
// ShowExpr(getExpr(expr).expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Constant(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
// ------------------- arithmetic operations ----------------
|
|
|
|
`1.0 + 2.0`,
|
|
|
|
`1.0 + 2`,
|
|
|
|
`1 + 2.0`,
|
|
|
|
`1 + 2`,
|
|
|
|
`1.0 - 2.0`,
|
|
|
|
`1.0 - 2`,
|
|
|
|
`1 - 2.0`,
|
|
|
|
`1 - 2`,
|
|
|
|
`1.0 * 2.0`,
|
|
|
|
`1.0 * 2`,
|
|
|
|
`1 * 2.0`,
|
|
|
|
`1 * 2`,
|
|
|
|
`1.0 / 2.0`,
|
|
|
|
`1.0 / 2`,
|
|
|
|
`1 / 2.0`,
|
|
|
|
`1 / 2`,
|
|
|
|
`1 % 2`,
|
|
|
|
// ------------------- logical operations ----------------
|
|
|
|
`true and false`,
|
|
|
|
`true or false`,
|
|
|
|
`!true`,
|
|
|
|
`!false`,
|
|
|
|
// ------------------- relational operations ----------------
|
|
|
|
`"1" < "2"`,
|
|
|
|
`1.0 < 2.0`,
|
|
|
|
`1.0 < 2`,
|
|
|
|
`1 < 2.0`,
|
|
|
|
`1 < 2`,
|
|
|
|
`"1" <= "2"`,
|
|
|
|
`1.0 <= 2.0`,
|
|
|
|
`1.0 <= 2`,
|
|
|
|
`1 <= 2.0`,
|
|
|
|
`1 <= 2`,
|
|
|
|
`"1" > "2"`,
|
|
|
|
`1.0 > 2.0`,
|
|
|
|
`1.0 > 2`,
|
|
|
|
`1 > 2.0`,
|
|
|
|
`1 > 2`,
|
|
|
|
`"1" >= "2"`,
|
|
|
|
`1.0 >= 2.0`,
|
|
|
|
`1.0 >= 2`,
|
|
|
|
`1 >= 2.0`,
|
|
|
|
`1 >= 2`,
|
|
|
|
`"1" == "2"`,
|
|
|
|
`1.0 == 2.0`,
|
|
|
|
`1.0 == 2`,
|
|
|
|
`1 == 2.0`,
|
|
|
|
`1 == 2`,
|
|
|
|
`true == false`,
|
|
|
|
`"1" != "2"`,
|
|
|
|
`1.0 != 2.0`,
|
|
|
|
`1.0 != 2`,
|
|
|
|
`1 != 2.0`,
|
|
|
|
`1 != 2`,
|
|
|
|
`true != false`,
|
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
expr := handleExpr(helper, exprStr)
|
|
|
|
assert.NotNil(t, getExpr(expr).expr, exprStr)
|
|
|
|
|
|
|
|
// fmt.Printf("expr: %s\n", exprStr)
|
|
|
|
// ShowExpr(getExpr(expr).expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Combinations(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`not (Int8Field + 1 == 2)`,
|
|
|
|
`(Int16Field - 3 == 4) and (Int32Field * 5 != 6)`,
|
|
|
|
`(Int64Field / 7 != 8) or (Int64Field % 10 == 9)`,
|
2022-05-19 17:15:57 +08:00
|
|
|
`Int64Field > 0 && VarCharField > "0"`,
|
|
|
|
`Int64Field < 0 && VarCharField < "0"`,
|
2023-05-10 10:19:19 +08:00
|
|
|
`A > 50 or B < 40`,
|
2022-05-06 17:43:51 +08:00
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
assertValidExpr(t, helper, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateRetrievePlan(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
_, err := CreateRetrievePlan(schema, "Int64Field > 0")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateSearchPlan(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
2023-05-18 09:33:24 +08:00
|
|
|
_, err := CreateSearchPlan(schema, `$meta["A"] != 10`, "FloatVectorField", &planpb.QueryInfo{
|
2022-05-06 17:43:51 +08:00
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExpr_Invalid(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
helper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
exprStrs := []string{
|
|
|
|
`invalid expression`,
|
|
|
|
`"constant"`,
|
|
|
|
// -------------- identifier not in schema --------------
|
|
|
|
`not_in_schema`,
|
|
|
|
// ------------------------ Add/Sub ---------------------
|
|
|
|
`not_in_schema + 1`,
|
|
|
|
`1 - not_in_schema`,
|
|
|
|
`true + false`,
|
|
|
|
`"str" + "text"`,
|
|
|
|
`true + "str"`,
|
|
|
|
`true - false`,
|
|
|
|
`"str" - "text"`,
|
|
|
|
`true - "str"`,
|
|
|
|
`StringField + VarCharField`,
|
|
|
|
`StringField - 2`,
|
|
|
|
`2 + StringField`,
|
|
|
|
// ------------------------ Mul/Div/Mod ---------------------
|
|
|
|
`not_in_schema * 1`,
|
|
|
|
`1 / not_in_schema`,
|
|
|
|
`1 % not_in_schema`,
|
|
|
|
`true * false`,
|
|
|
|
`true / false`,
|
|
|
|
`true % false`,
|
|
|
|
`"str" * "text"`,
|
|
|
|
`"str" / "text"`,
|
|
|
|
`"str" % "text"`,
|
|
|
|
`2 / 0`,
|
|
|
|
`2 % 0`,
|
|
|
|
`StringField % VarCharField`,
|
|
|
|
`StringField * 2`,
|
|
|
|
`2 / StringField`,
|
|
|
|
// ----------------------- ==/!= -------------------------
|
2023-05-10 10:19:19 +08:00
|
|
|
//`not_in_schema != 1`, // maybe in json
|
|
|
|
//`1 == not_in_schema`, // maybe in json
|
2022-05-06 17:43:51 +08:00
|
|
|
`true == "str"`,
|
|
|
|
`"str" != false`,
|
2022-06-01 10:00:07 +08:00
|
|
|
`VarCharField != FloatField`,
|
|
|
|
`FloatField == VarCharField`,
|
2022-05-06 17:43:51 +08:00
|
|
|
// ---------------------- relational --------------------
|
2023-05-10 10:19:19 +08:00
|
|
|
//`not_in_schema < 1`, // maybe in json
|
|
|
|
//`1 <= not_in_schema`, // maybe in json
|
2022-05-06 17:43:51 +08:00
|
|
|
`true <= "str"`,
|
|
|
|
`"str" >= false`,
|
2022-06-01 10:00:07 +08:00
|
|
|
`VarCharField < FloatField`,
|
|
|
|
`FloatField > VarCharField`,
|
2022-05-06 17:43:51 +08:00
|
|
|
// ------------------------ like ------------------------
|
|
|
|
`(VarCharField % 2) like "prefix%"`,
|
|
|
|
`FloatField like "prefix%"`,
|
2023-05-10 10:19:19 +08:00
|
|
|
//`value like "prefix%"`, // maybe in json
|
2022-05-06 17:43:51 +08:00
|
|
|
// ------------------------ term ------------------------
|
2023-05-10 10:19:19 +08:00
|
|
|
//`not_in_schema in [1, 2, 3]`, // maybe in json
|
2022-05-06 17:43:51 +08:00
|
|
|
`1 in [1, 2, 3]`,
|
|
|
|
`(Int8Field + 8) in [1, 2, 3]`,
|
|
|
|
`Int8Field in [(true + 1)]`,
|
|
|
|
`Int8Field in [Int16Field]`,
|
|
|
|
`BoolField in [4.0]`,
|
|
|
|
`VarCharField in [4.0]`,
|
|
|
|
`Int32Field in [4.0]`,
|
|
|
|
`FloatField in [5, 6.0, true]`,
|
|
|
|
// ----------------------- range -------------------------
|
2023-05-10 10:19:19 +08:00
|
|
|
//`1 < not_in_schema < 2`, // maybe in json
|
2022-05-06 17:43:51 +08:00
|
|
|
`1 < 3 < 2`,
|
|
|
|
`1 < (Int8Field + Int16Field) < 2`,
|
|
|
|
`(invalid_lower) < Int32Field < 2`,
|
|
|
|
`1 < Int32Field < (invalid_upper)`,
|
|
|
|
`(Int8Field) < Int32Field < 2`,
|
|
|
|
`1 < Int32Field < (Int16Field)`,
|
|
|
|
`1 < StringField < 2`,
|
|
|
|
`1 < BoolField < 2`,
|
|
|
|
`1.0 < Int32Field < 2.0`,
|
|
|
|
`true < FloatField < false`,
|
|
|
|
// `2 <= Int32Field <= 1`,
|
|
|
|
`2 = Int32Field = 1`,
|
|
|
|
`true = BoolField = false`,
|
|
|
|
// ----------------------- unary ------------------------
|
|
|
|
`-true`,
|
|
|
|
`!"str"`,
|
|
|
|
`!(not_in_schema)`,
|
|
|
|
`-Int32Field`,
|
|
|
|
`!(Int32Field)`,
|
|
|
|
// ----------------------- or/and ------------------------
|
|
|
|
`not_in_schema or true`,
|
|
|
|
`false or not_in_schema`,
|
|
|
|
`"str" or false`,
|
|
|
|
`BoolField or false`,
|
|
|
|
`Int32Field or Int64Field`,
|
|
|
|
`not_in_schema and true`,
|
|
|
|
`false and not_in_schema`,
|
|
|
|
`"str" and false`,
|
|
|
|
`BoolField and false`,
|
|
|
|
`Int32Field and Int64Field`,
|
|
|
|
// -------------------- unsupported ----------------------
|
|
|
|
`1 ^ 2`,
|
|
|
|
`1 & 2`,
|
|
|
|
`1 ** 2`,
|
|
|
|
`1 << 2`,
|
|
|
|
`1 | 2`,
|
|
|
|
}
|
|
|
|
for _, exprStr := range exprStrs {
|
|
|
|
_, err := ParseExpr(helper, exprStr)
|
|
|
|
assert.Error(t, err, exprStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateRetrievePlan_Invalid(t *testing.T) {
|
|
|
|
t.Run("invalid schema", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
schema.Fields = append(schema.Fields, schema.Fields[0])
|
|
|
|
_, err := CreateRetrievePlan(schema, "")
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("invalid expr", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
_, err := CreateRetrievePlan(schema, "invalid expression")
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateSearchPlan_Invalid(t *testing.T) {
|
|
|
|
t.Run("invalid schema", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
schema.Fields = append(schema.Fields, schema.Fields[0])
|
|
|
|
_, err := CreateSearchPlan(schema, "", "", nil)
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("invalid expr", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
_, err := CreateSearchPlan(schema, "invalid expression", "", nil)
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("invalid vector field", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
_, err := CreateSearchPlan(schema, "Int64Field > 0", "not_exist", nil)
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("not vector type", func(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
_, err := CreateSearchPlan(schema, "Int64Field > 0", "VarCharField", nil)
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
}
|
2022-05-20 18:47:57 +08:00
|
|
|
|
|
|
|
func Test_handleExpr(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
schemaHelper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-10 10:19:19 +08:00
|
|
|
ret1 := handleExpr(schemaHelper, "1 < Int32Field < (Int16Field)")
|
2022-05-20 18:47:57 +08:00
|
|
|
err1, ok := ret1.(error)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Error(t, err1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// test if handleExpr is thread-safe.
|
|
|
|
func Test_handleExpr_17126(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
schemaHelper, err := typeutil.CreateSchemaHelper(schema)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
normal := "Int64Field > 0"
|
2023-05-10 10:19:19 +08:00
|
|
|
abnormal := "1 < Int32Field < (Int16Field)"
|
2022-05-20 18:47:57 +08:00
|
|
|
|
|
|
|
n := 4 // default parallel in regression.
|
|
|
|
m := 16
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < n*m; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
i := i
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
if i%2 == 0 {
|
|
|
|
ret := handleExpr(schemaHelper, normal)
|
|
|
|
_, ok := ret.(error)
|
|
|
|
assert.False(t, ok)
|
|
|
|
} else {
|
|
|
|
ret := handleExpr(schemaHelper, abnormal)
|
|
|
|
err, ok := ret.(error)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2023-05-10 10:19:19 +08:00
|
|
|
|
|
|
|
func Test_JSONExpr(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
expr := ""
|
|
|
|
// search
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] > 90`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err := CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `JSONField["A"] > 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-10 10:19:19 +08:00
|
|
|
expr = `A < 10`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `JSONField["A"] <= 5`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] <= 5`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `$meta["A"] >= 95`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] == 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] != 95`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] > 90 && $meta["B"] < 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] > 95 || $meta["B"] < 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `A > 95 || $meta["B"] < 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `not ($meta["A"] == 95)`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] in [90, 91, 95, 97]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] not in [90, 91, 95, 97]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["C"]["0"] in [90, 91, 95, 97]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["C"]["0"] not in [90, 91, 95, 97]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-16 16:19:22 +08:00
|
|
|
expr = `C["0"] not in [90, 91, 95, 97]`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `C[0] in [90, 91, 95, 97]`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-10 10:19:19 +08:00
|
|
|
expr = `C["0"] > 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `C["0"] < 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `C["0"] == 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `10 < C["0"] < 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `100 > C["0"] > 90`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `0 <= $meta["A"] < 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `0 <= A < 5`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] + 5 == 10`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta["A"] > 10 + 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `100 - 5 < $meta["A"]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `100 == $meta["A"] + 6`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `exists $meta["A"]`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `exists $meta["A"]["B"]["C"] `
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
2023-05-16 16:19:22 +08:00
|
|
|
assert.NoError(t, err)
|
2023-05-10 10:19:19 +08:00
|
|
|
|
2023-05-16 16:19:22 +08:00
|
|
|
expr = `A["B"][0] > 100`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
expr = `A["B"][0] > 100`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2023-05-14 22:51:21 +08:00
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta[0] > 100`
|
2023-05-14 22:51:21 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-16 16:19:22 +08:00
|
|
|
expr = `A["\"\"B\"\""] > 10`
|
2023-05-14 22:51:21 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-05-16 16:19:22 +08:00
|
|
|
expr = `A["[\"B\"]"] == "abc\"bbb\"cc"`
|
2023-05-14 22:51:21 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2023-05-10 10:19:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test_InvalidExprOnJSONField(t *testing.T) {
|
|
|
|
schema := newTestSchema()
|
|
|
|
expr := ""
|
|
|
|
var err error
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `exists $meta`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-10 10:19:19 +08:00
|
|
|
expr = `exists JSONField`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta > 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `$meta > 0`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `JSONField == 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta < 100`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `0 < $meta < 100`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `20 > $meta > 0`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta + 5 > 0`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `$meta > 2 + 5`
|
2023-05-10 10:19:19 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
2023-05-16 16:19:22 +08:00
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2023-05-18 09:33:24 +08:00
|
|
|
expr = `exists $meta["A"] > 10 `
|
2023-05-16 16:19:22 +08:00
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `exists Int64Field `
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `A[[""B""]] > 10`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `A["[""B""]"] > 10`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `A[[""B""]] > 10`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `A[B] > 10`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
2023-05-10 10:19:19 +08:00
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_InvalidExprWithoutJSONField(t *testing.T) {
|
|
|
|
fields := []*schemapb.FieldSchema{
|
|
|
|
{FieldID: 100, Name: "id", IsPrimaryKey: true, Description: "id", DataType: schemapb.DataType_Int64},
|
|
|
|
{FieldID: 101, Name: "vector", IsPrimaryKey: false, Description: "vector", DataType: schemapb.DataType_FloatVector},
|
|
|
|
}
|
|
|
|
|
|
|
|
schema := &schemapb.CollectionSchema{
|
|
|
|
Name: "test",
|
|
|
|
Description: "schema for test used",
|
|
|
|
AutoID: true,
|
|
|
|
Fields: fields,
|
|
|
|
}
|
|
|
|
|
|
|
|
expr := ""
|
|
|
|
var err error
|
|
|
|
expr = `A == 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `JSON["A"] > 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `A < 100`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `0 < JSON["A"] < 100`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `0 < A < 100`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `100 > JSON["A"] > 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
|
|
expr = `100 > A > 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_InvalidExprWithMultipleJSONField(t *testing.T) {
|
|
|
|
fields := []*schemapb.FieldSchema{
|
|
|
|
{FieldID: 100, Name: "id", IsPrimaryKey: true, Description: "id", DataType: schemapb.DataType_Int64},
|
|
|
|
{FieldID: 101, Name: "vector", IsPrimaryKey: false, Description: "vector", DataType: schemapb.DataType_FloatVector},
|
|
|
|
{FieldID: 102, Name: "json1", IsPrimaryKey: false, Description: "json field 1", DataType: schemapb.DataType_JSON},
|
|
|
|
{FieldID: 103, Name: "json2", IsPrimaryKey: false, Description: "json field 2", DataType: schemapb.DataType_JSON},
|
|
|
|
}
|
|
|
|
|
|
|
|
schema := &schemapb.CollectionSchema{
|
|
|
|
Name: "test",
|
|
|
|
Description: "schema for test used",
|
|
|
|
AutoID: true,
|
|
|
|
Fields: fields,
|
|
|
|
}
|
|
|
|
|
|
|
|
expr := ""
|
|
|
|
var err error
|
|
|
|
expr = `A == 0`
|
|
|
|
_, err = CreateSearchPlan(schema, expr, "FloatVectorField", &planpb.QueryInfo{
|
|
|
|
Topk: 0,
|
|
|
|
MetricType: "",
|
|
|
|
SearchParams: "",
|
|
|
|
RoundDecimal: 0,
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|