Skip to content

Commit 2dcac07

Browse files
authored
Add Hybrid Query Example (#138)
* Add Hybrid query example + Tests * Update and rename ExamplesTests.cs to ExampleTests.cs
1 parent ee1a576 commit 2dcac07

File tree

2 files changed

+106
-22
lines changed

2 files changed

+106
-22
lines changed

Examples/AdvancedQueryOperations.md

+47-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Aggregation and other more complex RediSearch queries
77
1. [Data Load](#vss_dataload)
88
2. [Index Creation](#vss_index)
99
3. [Search](#vss_search)
10+
4. [Hybrid query Search](#vss_hybrid_query_search)
1011
4. [Advanced Search Queries](#adv_search)
1112
1. [Data Set](#advs_dataset)
1213
2. [Data Load](#advs_dataload)
@@ -41,10 +42,26 @@ using NRedisStack.Search.Aggregation;
4142

4243
### Data Load <a name="vss_dataload"></a>
4344
```c#
44-
db.HashSet("vec:1", "vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray());
45-
db.HashSet("vec:2", "vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray());
46-
db.HashSet("vec:3", "vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray());
47-
db.HashSet("vec:5", "vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray());
45+
db.HashSet("vec:1", new HashEntry[]
46+
{
47+
new("vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray()),
48+
new("tag", "A")
49+
});
50+
db.HashSet("vec:2", new HashEntry[]
51+
{
52+
new("vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray()),
53+
new("tag", "A")
54+
});
55+
db.HashSet("vec:3", new HashEntry[]
56+
{
57+
new("vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray()),
58+
new("tag", "B")
59+
});
60+
db.HashSet("vec:4", new HashEntry[]
61+
{
62+
new("vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray()),
63+
new("tag", "A")
64+
});
4865
```
4966
### Index Creation <a name="vss_index">
5067
#### Command
@@ -53,6 +70,7 @@ ISearchCommands ft = db.FT();
5370
try {ft.DropIndex("vss_idx");} catch {};
5471
Console.WriteLine(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"),
5572
new Schema()
73+
.AddTagField("tag")
5674
.AddVectorField("vector", VectorField.VectorAlgo.FLAT,
5775
new Dictionary<string, object>()
5876
{
@@ -70,7 +88,7 @@ True
7088
### Search <a name="vss_search">
7189
#### Command
7290
```c#
73-
float[] vec = new[] { 2f, 2f, 3f, 3f};
91+
float[] vec = new[] { 2f, 3f, 3f, 3f};
7492
var res = ft.Search("vss_idx",
7593
new Query("*=>[KNN 2 @vector $query_vec]")
7694
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
@@ -90,6 +108,30 @@ id: vec:2, score: 2
90108
id: vec:3, score: 2
91109
```
92110

111+
### Hybrid query Search <a name="vss_hybrid_query_search">
112+
#### Search only documents with tag A
113+
```c#
114+
float[] vec = new[] { 2f, 3f, 3f, 3f};
115+
var res = ft.Search("vss_idx",
116+
new Query("@tag:{A}=>[KNN 2 @vector $query_vec]")
117+
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
118+
.SetSortBy("__vector_score")
119+
.Dialect(2));
120+
foreach (var doc in res.Documents) {
121+
foreach (var item in doc.GetProperties()) {
122+
if (item.Key == "__vector_score") {
123+
Console.WriteLine($"id: {doc.Id}, score: {item.Value}");
124+
}
125+
}
126+
}
127+
```
128+
#### Result
129+
```bash
130+
id: vec:2, score: 3
131+
id: vec:4, score: 7
132+
```
133+
vec:3 is not returned because it has tag B
134+
93135
## Advanced Search Queries <a name="adv_search">
94136
### Data Set <a name="advs_dataset">
95137
```json

tests/NRedisStack.Tests/Examples/ExamplesTests.cs tests/NRedisStack.Tests/Examples/ExampleTests.cs

+59-17
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
namespace NRedisStack.Tests;
2020

21-
public class ExaplesTests : AbstractNRedisStackTest, IDisposable
21+
public class ExampleTests : AbstractNRedisStackTest, IDisposable
2222
{
2323
private readonly ITestOutputHelper testOutputHelper;
2424
Mock<IDatabase> _mock = new Mock<IDatabase>();
2525
private readonly string key = "EXAMPLES_TESTS";
26-
public ExaplesTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture)
26+
public ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture)
2727
{
2828
this.testOutputHelper = testOutputHelper;
2929
}
@@ -41,7 +41,7 @@ public void HSETandSearch()
4141

4242
// Get a reference to the database and for search commands:
4343
// var db = redis.GetDatabase();
44-
var db = redisFixture.Redis.GetDatabase();
44+
var db = redisFixture.Redis.GetDatabase();
4545
db.Execute("FLUSHALL");
4646
var ft = db.FT();
4747

@@ -186,7 +186,7 @@ public async Task PipelineWithAsync()
186186

187187
// Get a reference to the database
188188
// var db = redis.GetDatabase();
189-
var db = redisFixture.Redis.GetDatabase();
189+
var db = redisFixture.Redis.GetDatabase();
190190
db.Execute("FLUSHALL");
191191
// Setup pipeline connection
192192

@@ -286,7 +286,7 @@ public void TestJsonConvert()
286286
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
287287
// IDatabase db = redis.GetDatabase();
288288

289-
var db = redisFixture.Redis.GetDatabase();
289+
var db = redisFixture.Redis.GetDatabase();
290290
db.Execute("FLUSHALL");
291291
ISearchCommands ft = db.FT();
292292
IJsonCommands json = db.JSON();
@@ -578,7 +578,7 @@ public void BasicJsonExamplesTest()
578578
{
579579
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
580580
// IDatabase db = redis.GetDatabase();
581-
var db = redisFixture.Redis.GetDatabase();
581+
var db = redisFixture.Redis.GetDatabase();
582582
db.Execute("FLUSHALL");
583583
IJsonCommands json = db.JSON();
584584

@@ -833,7 +833,7 @@ public void AdvancedJsonExamplesTest()
833833
{
834834
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
835835
// IDatabase db = redis.GetDatabase();
836-
var db = redisFixture.Redis.GetDatabase();
836+
var db = redisFixture.Redis.GetDatabase();
837837
db.Execute("FLUSHALL");
838838
IJsonCommands json = db.JSON();
839839

@@ -967,7 +967,7 @@ public void BasicQueryOperationsTest()
967967
{
968968
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
969969
// IDatabase db = redis.GetDatabase();
970-
var db = redisFixture.Redis.GetDatabase();
970+
var db = redisFixture.Redis.GetDatabase();
971971
db.Execute("FLUSHALL");
972972
IJsonCommands json = db.JSON();
973973
ISearchCommands ft = db.FT();
@@ -1127,22 +1127,39 @@ public void AdvancedQueryOperationsTest()
11271127
{
11281128
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
11291129
// IDatabase db = redis.GetDatabase();
1130-
var db = redisFixture.Redis.GetDatabase();
1130+
var db = redisFixture.Redis.GetDatabase();
11311131
db.Execute("FLUSHALL");
11321132
IJsonCommands json = db.JSON();
11331133
ISearchCommands ft = db.FT();
11341134

11351135
// Vector Similarity Search (VSS)
11361136
// Data load:
1137-
db.HashSet("vec:1", "vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray());
1138-
db.HashSet("vec:2", "vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray());
1139-
db.HashSet("vec:3", "vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray());
1140-
db.HashSet("vec:5", "vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray());
1137+
db.HashSet("vec:1", new HashEntry[]
1138+
{
1139+
new("vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray()),
1140+
new("tag", "A")
1141+
});
1142+
db.HashSet("vec:2", new HashEntry[]
1143+
{
1144+
new("vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray()),
1145+
new("tag", "A")
1146+
});
1147+
db.HashSet("vec:3", new HashEntry[]
1148+
{
1149+
new("vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray()),
1150+
new("tag", "B")
1151+
});
1152+
db.HashSet("vec:4", new HashEntry[]
1153+
{
1154+
new("vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray()),
1155+
new("tag", "A")
1156+
});
11411157

11421158
// Index creation:
11431159
try { ft.DropIndex("vss_idx"); } catch { };
11441160
Assert.True(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"),
11451161
new Schema()
1162+
.AddTagField("tag")
11461163
.AddVectorField("vector", VectorField.VectorAlgo.FLAT,
11471164
new Dictionary<string, object>()
11481165
{
@@ -1156,7 +1173,7 @@ public void AdvancedQueryOperationsTest()
11561173
Thread.Sleep(2000);
11571174

11581175
// Search:
1159-
float[] vec = new[] { 2f, 2f, 3f, 3f };
1176+
float[] vec = new[] { 2f, 3f, 3f, 3f };
11601177
var res = ft.Search("vss_idx",
11611178
new Query("*=>[KNN 2 @vector $query_vec]")
11621179
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
@@ -1176,12 +1193,37 @@ public void AdvancedQueryOperationsTest()
11761193

11771194
HashSet<string> expectedResSet = new HashSet<string>()
11781195
{
1179-
"id: vec:2, score: 2",
1180-
"id: vec:3, score: 2",
1196+
"id: vec:3, score: 1",
1197+
"id: vec:2, score: 3",
11811198
};
11821199

11831200
Assert.Equal(expectedResSet, resSet);
11841201

1202+
// hybrid query - search only documents with tag A:
1203+
res = ft.Search("vss_idx",
1204+
new Query("@tag:{A}=>[KNN 2 @vector $query_vec]")
1205+
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
1206+
.SetSortBy("__vector_score")
1207+
.Dialect(2));
1208+
1209+
resSet.Clear();
1210+
foreach (var doc in res.Documents)
1211+
{
1212+
foreach (var item in doc.GetProperties())
1213+
{
1214+
if (item.Key == "__vector_score")
1215+
{
1216+
resSet.Add($"id: {doc.Id}, score: {item.Value}");
1217+
}
1218+
}
1219+
}
1220+
1221+
expectedResSet = new HashSet<string>()
1222+
{
1223+
"id: vec:2, score: 3",
1224+
"id: vec:4, score: 7",
1225+
};
1226+
11851227
//Advanced Search Queries:
11861228
// data load:
11871229
json.Set("warehouse:1", "$", new
@@ -1348,4 +1390,4 @@ private static void SortAndCompare(List<string> expectedList, List<string> res)
13481390
Assert.Equal(expectedList[i], res[i].ToString());
13491391
}
13501392
}
1351-
}
1393+
}

0 commit comments

Comments
 (0)