diff --git a/Examples/AdvancedQueryOperations.md b/Examples/AdvancedQueryOperations.md
index 1ced1dac..7f2fd88c 100644
--- a/Examples/AdvancedQueryOperations.md
+++ b/Examples/AdvancedQueryOperations.md
@@ -7,6 +7,7 @@ Aggregation and other more complex RediSearch queries
1. [Data Load](#vss_dataload)
2. [Index Creation](#vss_index)
3. [Search](#vss_search)
+ 4. [Hybrid query Search](#vss_hybrid_query_search)
4. [Advanced Search Queries](#adv_search)
1. [Data Set](#advs_dataset)
2. [Data Load](#advs_dataload)
@@ -41,10 +42,26 @@ using NRedisStack.Search.Aggregation;
### Data Load
```c#
-db.HashSet("vec:1", "vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray());
-db.HashSet("vec:2", "vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray());
-db.HashSet("vec:3", "vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray());
-db.HashSet("vec:5", "vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray());
+db.HashSet("vec:1", new HashEntry[]
+{
+ new("vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+});
+db.HashSet("vec:2", new HashEntry[]
+{
+ new("vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+});
+db.HashSet("vec:3", new HashEntry[]
+{
+ new("vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "B")
+});
+db.HashSet("vec:4", new HashEntry[]
+{
+ new("vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+});
```
### Index Creation
#### Command
@@ -53,6 +70,7 @@ ISearchCommands ft = db.FT();
try {ft.DropIndex("vss_idx");} catch {};
Console.WriteLine(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"),
new Schema()
+ .AddTagField("tag")
.AddVectorField("vector", VectorField.VectorAlgo.FLAT,
new Dictionary()
{
@@ -70,7 +88,7 @@ True
### Search
#### Command
```c#
-float[] vec = new[] { 2f, 2f, 3f, 3f};
+float[] vec = new[] { 2f, 3f, 3f, 3f};
var res = ft.Search("vss_idx",
new Query("*=>[KNN 2 @vector $query_vec]")
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
@@ -90,6 +108,30 @@ id: vec:2, score: 2
id: vec:3, score: 2
```
+### Hybrid query Search
+#### Search only documents with tag A
+```c#
+float[] vec = new[] { 2f, 3f, 3f, 3f};
+var res = ft.Search("vss_idx",
+ new Query("@tag:{A}=>[KNN 2 @vector $query_vec]")
+ .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
+ .SetSortBy("__vector_score")
+ .Dialect(2));
+foreach (var doc in res.Documents) {
+ foreach (var item in doc.GetProperties()) {
+ if (item.Key == "__vector_score") {
+ Console.WriteLine($"id: {doc.Id}, score: {item.Value}");
+ }
+ }
+}
+```
+#### Result
+```bash
+id: vec:2, score: 3
+id: vec:4, score: 7
+```
+vec:3 is not returned because it has tag B
+
## Advanced Search Queries
### Data Set
```json
diff --git a/tests/NRedisStack.Tests/Examples/ExamplesTests.cs b/tests/NRedisStack.Tests/Examples/ExampleTests.cs
similarity index 96%
rename from tests/NRedisStack.Tests/Examples/ExamplesTests.cs
rename to tests/NRedisStack.Tests/Examples/ExampleTests.cs
index 5dc02eed..b549f0ad 100644
--- a/tests/NRedisStack.Tests/Examples/ExamplesTests.cs
+++ b/tests/NRedisStack.Tests/Examples/ExampleTests.cs
@@ -18,12 +18,12 @@
namespace NRedisStack.Tests;
-public class ExaplesTests : AbstractNRedisStackTest, IDisposable
+public class ExampleTests : AbstractNRedisStackTest, IDisposable
{
private readonly ITestOutputHelper testOutputHelper;
Mock _mock = new Mock();
private readonly string key = "EXAMPLES_TESTS";
- public ExaplesTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture)
+ public ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture)
{
this.testOutputHelper = testOutputHelper;
}
@@ -41,7 +41,7 @@ public void HSETandSearch()
// Get a reference to the database and for search commands:
// var db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ft = db.FT();
@@ -186,7 +186,7 @@ public async Task PipelineWithAsync()
// Get a reference to the database
// var db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
// Setup pipeline connection
@@ -286,7 +286,7 @@ public void TestJsonConvert()
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// IDatabase db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
ISearchCommands ft = db.FT();
IJsonCommands json = db.JSON();
@@ -578,7 +578,7 @@ public void BasicJsonExamplesTest()
{
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// IDatabase db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
IJsonCommands json = db.JSON();
@@ -833,7 +833,7 @@ public void AdvancedJsonExamplesTest()
{
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// IDatabase db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
IJsonCommands json = db.JSON();
@@ -967,7 +967,7 @@ public void BasicQueryOperationsTest()
{
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// IDatabase db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
IJsonCommands json = db.JSON();
ISearchCommands ft = db.FT();
@@ -1127,22 +1127,39 @@ public void AdvancedQueryOperationsTest()
{
// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// IDatabase db = redis.GetDatabase();
- var db = redisFixture.Redis.GetDatabase();
+ var db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
IJsonCommands json = db.JSON();
ISearchCommands ft = db.FT();
// Vector Similarity Search (VSS)
// Data load:
- db.HashSet("vec:1", "vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray());
- db.HashSet("vec:2", "vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray());
- db.HashSet("vec:3", "vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray());
- db.HashSet("vec:5", "vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray());
+ db.HashSet("vec:1", new HashEntry[]
+ {
+ new("vector", (new float[] { 1f, 1f, 1f, 1f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+ });
+ db.HashSet("vec:2", new HashEntry[]
+ {
+ new("vector", (new float[] { 2f, 2f, 2f, 2f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+ });
+ db.HashSet("vec:3", new HashEntry[]
+ {
+ new("vector", (new float[] { 3f, 3f, 3f, 3f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "B")
+ });
+ db.HashSet("vec:4", new HashEntry[]
+ {
+ new("vector", (new float[] { 4f, 4f, 4f, 4f }).SelectMany(BitConverter.GetBytes).ToArray()),
+ new("tag", "A")
+ });
// Index creation:
try { ft.DropIndex("vss_idx"); } catch { };
Assert.True(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"),
new Schema()
+ .AddTagField("tag")
.AddVectorField("vector", VectorField.VectorAlgo.FLAT,
new Dictionary()
{
@@ -1156,7 +1173,7 @@ public void AdvancedQueryOperationsTest()
Thread.Sleep(2000);
// Search:
- float[] vec = new[] { 2f, 2f, 3f, 3f };
+ float[] vec = new[] { 2f, 3f, 3f, 3f };
var res = ft.Search("vss_idx",
new Query("*=>[KNN 2 @vector $query_vec]")
.AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
@@ -1176,12 +1193,37 @@ public void AdvancedQueryOperationsTest()
HashSet expectedResSet = new HashSet()
{
- "id: vec:2, score: 2",
- "id: vec:3, score: 2",
+ "id: vec:3, score: 1",
+ "id: vec:2, score: 3",
};
Assert.Equal(expectedResSet, resSet);
+ // hybrid query - search only documents with tag A:
+ res = ft.Search("vss_idx",
+ new Query("@tag:{A}=>[KNN 2 @vector $query_vec]")
+ .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray())
+ .SetSortBy("__vector_score")
+ .Dialect(2));
+
+ resSet.Clear();
+ foreach (var doc in res.Documents)
+ {
+ foreach (var item in doc.GetProperties())
+ {
+ if (item.Key == "__vector_score")
+ {
+ resSet.Add($"id: {doc.Id}, score: {item.Value}");
+ }
+ }
+ }
+
+ expectedResSet = new HashSet()
+ {
+ "id: vec:2, score: 3",
+ "id: vec:4, score: 7",
+ };
+
//Advanced Search Queries:
// data load:
json.Set("warehouse:1", "$", new
@@ -1348,4 +1390,4 @@ private static void SortAndCompare(List expectedList, List res)
Assert.Equal(expectedList[i], res[i].ToString());
}
}
-}
\ No newline at end of file
+}