Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ec11e7d

Browse files
authoredJul 22, 2024··
Merge branch 'master' into os-add-coverage-ci
2 parents 1308152 + 3613df6 commit ec11e7d

File tree

2 files changed

+290
-0
lines changed

2 files changed

+290
-0
lines changed
 

‎search_commands.go

+9
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ type FieldSchema struct {
7575
WithSuffixtrie bool
7676
VectorArgs *FTVectorArgs
7777
GeoShapeFieldType string
78+
IndexEmpty bool
79+
IndexMissing bool
7880
}
7981

8082
type FTVectorArgs struct {
@@ -1002,6 +1004,13 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
10021004
if schema.WithSuffixtrie {
10031005
args = append(args, "WITHSUFFIXTRIE")
10041006
}
1007+
if schema.IndexEmpty {
1008+
args = append(args, "INDEXEMPTY")
1009+
}
1010+
if schema.IndexMissing {
1011+
args = append(args, "INDEXMISSING")
1012+
1013+
}
10051014
}
10061015
cmd := NewStatusCmd(ctx, args...)
10071016
_ = c(ctx, cmd)

‎search_test.go

+281
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,110 @@ var _ = Describe("RediSearch commands", Label("search"), func() {
10171017
Expect(res.Attributes[0].WithSuffixtrie).To(BeTrue())
10181018
})
10191019

1020+
It("should test dialect 4", Label("search", "ftcreate", "ftsearch", "NonRedisEnterprise"), func() {
1021+
val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{
1022+
Prefix: []interface{}{"resource:"},
1023+
}, &redis.FieldSchema{
1024+
FieldName: "uuid",
1025+
FieldType: redis.SearchFieldTypeTag,
1026+
}, &redis.FieldSchema{
1027+
FieldName: "tags",
1028+
FieldType: redis.SearchFieldTypeTag,
1029+
}, &redis.FieldSchema{
1030+
FieldName: "description",
1031+
FieldType: redis.SearchFieldTypeText,
1032+
}, &redis.FieldSchema{
1033+
FieldName: "rating",
1034+
FieldType: redis.SearchFieldTypeNumeric,
1035+
}).Result()
1036+
Expect(err).NotTo(HaveOccurred())
1037+
Expect(val).To(BeEquivalentTo("OK"))
1038+
1039+
client.HSet(ctx, "resource:1", map[string]interface{}{
1040+
"uuid": "123e4567-e89b-12d3-a456-426614174000",
1041+
"tags": "finance|crypto|$btc|blockchain",
1042+
"description": "Analysis of blockchain technologies & Bitcoin's potential.",
1043+
"rating": 5,
1044+
})
1045+
client.HSet(ctx, "resource:2", map[string]interface{}{
1046+
"uuid": "987e6543-e21c-12d3-a456-426614174999",
1047+
"tags": "health|well-being|fitness|new-year's-resolutions",
1048+
"description": "Health trends for the new year, including fitness regimes.",
1049+
"rating": 4,
1050+
})
1051+
1052+
res, err := client.FTSearchWithArgs(ctx, "idx1", "@uuid:{$uuid}",
1053+
&redis.FTSearchOptions{
1054+
DialectVersion: 2,
1055+
Params: map[string]interface{}{"uuid": "123e4567-e89b-12d3-a456-426614174000"},
1056+
}).Result()
1057+
Expect(err).NotTo(HaveOccurred())
1058+
Expect(res.Total).To(BeEquivalentTo(int64(1)))
1059+
Expect(res.Docs[0].ID).To(BeEquivalentTo("resource:1"))
1060+
1061+
res, err = client.FTSearchWithArgs(ctx, "idx1", "@uuid:{$uuid}",
1062+
&redis.FTSearchOptions{
1063+
DialectVersion: 4,
1064+
Params: map[string]interface{}{"uuid": "123e4567-e89b-12d3-a456-426614174000"},
1065+
}).Result()
1066+
Expect(err).NotTo(HaveOccurred())
1067+
Expect(res.Total).To(BeEquivalentTo(int64(1)))
1068+
Expect(res.Docs[0].ID).To(BeEquivalentTo("resource:1"))
1069+
1070+
client.HSet(ctx, "test:1", map[string]interface{}{
1071+
"uuid": "3d3586fe-0416-4572-8ce",
1072+
"email": "adriano@acme.com.ie",
1073+
"num": 5,
1074+
})
1075+
1076+
// Create the index
1077+
ftCreateOptions := &redis.FTCreateOptions{
1078+
Prefix: []interface{}{"test:"},
1079+
}
1080+
schema := []*redis.FieldSchema{
1081+
{
1082+
FieldName: "uuid",
1083+
FieldType: redis.SearchFieldTypeTag,
1084+
},
1085+
{
1086+
FieldName: "email",
1087+
FieldType: redis.SearchFieldTypeTag,
1088+
},
1089+
{
1090+
FieldName: "num",
1091+
FieldType: redis.SearchFieldTypeNumeric,
1092+
},
1093+
}
1094+
1095+
val, err = client.FTCreate(ctx, "idx_hash", ftCreateOptions, schema...).Result()
1096+
Expect(err).NotTo(HaveOccurred())
1097+
Expect(val).To(Equal("OK"))
1098+
1099+
ftSearchOptions := &redis.FTSearchOptions{
1100+
DialectVersion: 4,
1101+
Params: map[string]interface{}{
1102+
"uuid": "3d3586fe-0416-4572-8ce",
1103+
"email": "adriano@acme.com.ie",
1104+
},
1105+
}
1106+
1107+
res, err = client.FTSearchWithArgs(ctx, "idx_hash", "@uuid:{$uuid}", ftSearchOptions).Result()
1108+
Expect(err).NotTo(HaveOccurred())
1109+
Expect(res.Docs[0].ID).To(BeEquivalentTo("test:1"))
1110+
Expect(res.Docs[0].Fields["uuid"]).To(BeEquivalentTo("3d3586fe-0416-4572-8ce"))
1111+
1112+
res, err = client.FTSearchWithArgs(ctx, "idx_hash", "@email:{$email}", ftSearchOptions).Result()
1113+
Expect(err).NotTo(HaveOccurred())
1114+
Expect(res.Docs[0].ID).To(BeEquivalentTo("test:1"))
1115+
Expect(res.Docs[0].Fields["email"]).To(BeEquivalentTo("adriano@acme.com.ie"))
1116+
1117+
ftSearchOptions.Params = map[string]interface{}{"num": 5}
1118+
res, err = client.FTSearchWithArgs(ctx, "idx_hash", "@num:[5]", ftSearchOptions).Result()
1119+
Expect(err).NotTo(HaveOccurred())
1120+
Expect(res.Docs[0].ID).To(BeEquivalentTo("test:1"))
1121+
Expect(res.Docs[0].Fields["num"]).To(BeEquivalentTo("5"))
1122+
})
1123+
10201124
It("should FTCreate GeoShape", Label("search", "ftcreate", "ftsearch"), func() {
10211125
val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "geom", FieldType: redis.SearchFieldTypeGeoShape, GeoShapeFieldType: "FLAT"}).Result()
10221126
Expect(err).NotTo(HaveOccurred())
@@ -1043,8 +1147,185 @@ var _ = Describe("RediSearch commands", Label("search"), func() {
10431147
Expect(err).NotTo(HaveOccurred())
10441148
Expect(res2.Total).To(BeEquivalentTo(int64(2)))
10451149
})
1150+
1151+
It("should create search index with FLOAT16 and BFLOAT16 vectors", Label("search", "ftcreate", "NonRedisEnterprise"), func() {
1152+
val, err := client.FTCreate(ctx, "index", &redis.FTCreateOptions{},
1153+
&redis.FieldSchema{FieldName: "float16", FieldType: redis.SearchFieldTypeVector, VectorArgs: &redis.FTVectorArgs{FlatOptions: &redis.FTFlatOptions{Type: "FLOAT16", Dim: 768, DistanceMetric: "COSINE"}}},
1154+
&redis.FieldSchema{FieldName: "bfloat16", FieldType: redis.SearchFieldTypeVector, VectorArgs: &redis.FTVectorArgs{FlatOptions: &redis.FTFlatOptions{Type: "BFLOAT16", Dim: 768, DistanceMetric: "COSINE"}}},
1155+
).Result()
1156+
Expect(err).NotTo(HaveOccurred())
1157+
Expect(val).To(BeEquivalentTo("OK"))
1158+
WaitForIndexing(client, "index")
1159+
})
1160+
1161+
It("should test geoshapes query intersects and disjoint", Label("NonRedisEnterprise"), func() {
1162+
_, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{}, &redis.FieldSchema{
1163+
FieldName: "g",
1164+
FieldType: redis.SearchFieldTypeGeoShape,
1165+
GeoShapeFieldType: "FLAT",
1166+
}).Result()
1167+
Expect(err).NotTo(HaveOccurred())
1168+
1169+
client.HSet(ctx, "doc_point1", "g", "POINT (10 10)")
1170+
client.HSet(ctx, "doc_point2", "g", "POINT (50 50)")
1171+
client.HSet(ctx, "doc_polygon1", "g", "POLYGON ((20 20, 25 35, 35 25, 20 20))")
1172+
client.HSet(ctx, "doc_polygon2", "g", "POLYGON ((60 60, 65 75, 70 70, 65 55, 60 60))")
1173+
1174+
intersection, err := client.FTSearchWithArgs(ctx, "idx1", "@g:[intersects $shape]",
1175+
&redis.FTSearchOptions{
1176+
DialectVersion: 3,
1177+
Params: map[string]interface{}{"shape": "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))"},
1178+
}).Result()
1179+
Expect(err).NotTo(HaveOccurred())
1180+
_assert_geosearch_result(&intersection, []string{"doc_point2", "doc_polygon1"})
1181+
1182+
disjunction, err := client.FTSearchWithArgs(ctx, "idx1", "@g:[disjoint $shape]",
1183+
&redis.FTSearchOptions{
1184+
DialectVersion: 3,
1185+
Params: map[string]interface{}{"shape": "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))"},
1186+
}).Result()
1187+
Expect(err).NotTo(HaveOccurred())
1188+
_assert_geosearch_result(&disjunction, []string{"doc_point1", "doc_polygon2"})
1189+
})
1190+
1191+
It("should test geoshapes query contains and within", func() {
1192+
_, err := client.FTCreate(ctx, "idx2", &redis.FTCreateOptions{}, &redis.FieldSchema{
1193+
FieldName: "g",
1194+
FieldType: redis.SearchFieldTypeGeoShape,
1195+
GeoShapeFieldType: "FLAT",
1196+
}).Result()
1197+
Expect(err).NotTo(HaveOccurred())
1198+
1199+
client.HSet(ctx, "doc_point1", "g", "POINT (10 10)")
1200+
client.HSet(ctx, "doc_point2", "g", "POINT (50 50)")
1201+
client.HSet(ctx, "doc_polygon1", "g", "POLYGON ((20 20, 25 35, 35 25, 20 20))")
1202+
client.HSet(ctx, "doc_polygon2", "g", "POLYGON ((60 60, 65 75, 70 70, 65 55, 60 60))")
1203+
1204+
containsA, err := client.FTSearchWithArgs(ctx, "idx2", "@g:[contains $shape]",
1205+
&redis.FTSearchOptions{
1206+
DialectVersion: 3,
1207+
Params: map[string]interface{}{"shape": "POINT(25 25)"},
1208+
}).Result()
1209+
Expect(err).NotTo(HaveOccurred())
1210+
_assert_geosearch_result(&containsA, []string{"doc_polygon1"})
1211+
1212+
containsB, err := client.FTSearchWithArgs(ctx, "idx2", "@g:[contains $shape]",
1213+
&redis.FTSearchOptions{
1214+
DialectVersion: 3,
1215+
Params: map[string]interface{}{"shape": "POLYGON((24 24, 24 26, 25 25, 24 24))"},
1216+
}).Result()
1217+
Expect(err).NotTo(HaveOccurred())
1218+
_assert_geosearch_result(&containsB, []string{"doc_polygon1"})
1219+
1220+
within, err := client.FTSearchWithArgs(ctx, "idx2", "@g:[within $shape]",
1221+
&redis.FTSearchOptions{
1222+
DialectVersion: 3,
1223+
Params: map[string]interface{}{"shape": "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))"},
1224+
}).Result()
1225+
Expect(err).NotTo(HaveOccurred())
1226+
_assert_geosearch_result(&within, []string{"doc_point2", "doc_polygon1"})
1227+
})
1228+
1229+
It("should search missing fields", Label("search", "ftcreate", "ftsearch", "NonRedisEnterprise"), func() {
1230+
val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{Prefix: []interface{}{"property:"}},
1231+
&redis.FieldSchema{FieldName: "title", FieldType: redis.SearchFieldTypeText, Sortable: true},
1232+
&redis.FieldSchema{FieldName: "features", FieldType: redis.SearchFieldTypeTag, IndexMissing: true},
1233+
&redis.FieldSchema{FieldName: "description", FieldType: redis.SearchFieldTypeText, IndexMissing: true}).Result()
1234+
Expect(err).NotTo(HaveOccurred())
1235+
Expect(val).To(BeEquivalentTo("OK"))
1236+
WaitForIndexing(client, "idx1")
1237+
1238+
client.HSet(ctx, "property:1", map[string]interface{}{
1239+
"title": "Luxury Villa in Malibu",
1240+
"features": "pool,sea view,modern",
1241+
"description": "A stunning modern villa overlooking the Pacific Ocean.",
1242+
})
1243+
1244+
client.HSet(ctx, "property:2", map[string]interface{}{
1245+
"title": "Downtown Flat",
1246+
"description": "Modern flat in central Paris with easy access to metro.",
1247+
})
1248+
1249+
client.HSet(ctx, "property:3", map[string]interface{}{
1250+
"title": "Beachfront Bungalow",
1251+
"features": "beachfront,sun deck",
1252+
})
1253+
1254+
res, err := client.FTSearchWithArgs(ctx, "idx1", "ismissing(@features)", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1255+
Expect(err).NotTo(HaveOccurred())
1256+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:2"))
1257+
1258+
res, err = client.FTSearchWithArgs(ctx, "idx1", "-ismissing(@features)", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1259+
Expect(err).NotTo(HaveOccurred())
1260+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:1"))
1261+
Expect(res.Docs[1].ID).To(BeEquivalentTo("property:3"))
1262+
1263+
res, err = client.FTSearchWithArgs(ctx, "idx1", "ismissing(@description)", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1264+
Expect(err).NotTo(HaveOccurred())
1265+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:3"))
1266+
1267+
res, err = client.FTSearchWithArgs(ctx, "idx1", "-ismissing(@description)", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1268+
Expect(err).NotTo(HaveOccurred())
1269+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:1"))
1270+
Expect(res.Docs[1].ID).To(BeEquivalentTo("property:2"))
1271+
})
1272+
1273+
It("should search empty fields", Label("search", "ftcreate", "ftsearch", "NonRedisEnterprise"), func() {
1274+
val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{Prefix: []interface{}{"property:"}},
1275+
&redis.FieldSchema{FieldName: "title", FieldType: redis.SearchFieldTypeText, Sortable: true},
1276+
&redis.FieldSchema{FieldName: "features", FieldType: redis.SearchFieldTypeTag, IndexEmpty: true},
1277+
&redis.FieldSchema{FieldName: "description", FieldType: redis.SearchFieldTypeText, IndexEmpty: true}).Result()
1278+
Expect(err).NotTo(HaveOccurred())
1279+
Expect(val).To(BeEquivalentTo("OK"))
1280+
WaitForIndexing(client, "idx1")
1281+
1282+
client.HSet(ctx, "property:1", map[string]interface{}{
1283+
"title": "Luxury Villa in Malibu",
1284+
"features": "pool,sea view,modern",
1285+
"description": "A stunning modern villa overlooking the Pacific Ocean.",
1286+
})
1287+
1288+
client.HSet(ctx, "property:2", map[string]interface{}{
1289+
"title": "Downtown Flat",
1290+
"features": "",
1291+
"description": "Modern flat in central Paris with easy access to metro.",
1292+
})
1293+
1294+
client.HSet(ctx, "property:3", map[string]interface{}{
1295+
"title": "Beachfront Bungalow",
1296+
"features": "beachfront,sun deck",
1297+
"description": "",
1298+
})
1299+
1300+
res, err := client.FTSearchWithArgs(ctx, "idx1", "@features:{\"\"}", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1301+
Expect(err).NotTo(HaveOccurred())
1302+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:2"))
1303+
1304+
res, err = client.FTSearchWithArgs(ctx, "idx1", "-@features:{\"\"}", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1305+
Expect(err).NotTo(HaveOccurred())
1306+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:1"))
1307+
Expect(res.Docs[1].ID).To(BeEquivalentTo("property:3"))
1308+
1309+
res, err = client.FTSearchWithArgs(ctx, "idx1", "@description:''", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1310+
Expect(err).NotTo(HaveOccurred())
1311+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:3"))
1312+
1313+
res, err = client.FTSearchWithArgs(ctx, "idx1", "-@description:''", &redis.FTSearchOptions{DialectVersion: 4, Return: []redis.FTSearchReturn{{FieldName: "id"}}, NoContent: true}).Result()
1314+
Expect(err).NotTo(HaveOccurred())
1315+
Expect(res.Docs[0].ID).To(BeEquivalentTo("property:1"))
1316+
Expect(res.Docs[1].ID).To(BeEquivalentTo("property:2"))
1317+
})
10461318
})
10471319

1320+
func _assert_geosearch_result(result *redis.FTSearchResult, expectedDocIDs []string) {
1321+
ids := make([]string, len(result.Docs))
1322+
for i, doc := range result.Docs {
1323+
ids[i] = doc.ID
1324+
}
1325+
Expect(ids).To(ConsistOf(expectedDocIDs))
1326+
Expect(result.Total).To(BeEquivalentTo(len(expectedDocIDs)))
1327+
}
1328+
10481329
// It("should FTProfile Search and Aggregate", Label("search", "ftprofile"), func() {
10491330
// val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "t", FieldType: redis.SearchFieldTypeText}).Result()
10501331
// Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)
Please sign in to comment.