Skip to content

Commit

Permalink
Vector Search and Semantic Caching (#417)
Browse files Browse the repository at this point in the history
  • Loading branch information
slorello89 committed Dec 5, 2023
1 parent c87f2da commit cf41ed7
Show file tree
Hide file tree
Showing 107 changed files with 5,008 additions and 464 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.onnx filter=lfs diff=lfs merge=lfs -text
src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources/vocab.txt filter=lfs diff=lfs merge=lfs -text
2 changes: 2 additions & 0 deletions .github/workflows/dotnet-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
lfs: true
- name: execute
run: docker-compose -f ./docker/docker-compose.yaml run dotnet
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,5 @@ FodyWeavers.xsd
# JetBrains Rider
.idea/
*.sln.iml

test/Redis.OM.Unit.Tests/appsettings.json.local
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,110 @@ customers.Where(x => x.LastName == "Bond" && x.FirstName == "James");
customers.Where(x=>x.NickNames.Contains("Jim"));
```

### Vectors

Redis OM .NET also supports storing and querying Vectors stored in Redis.

A `Vector<T>` is a representation of an object that can be transformed into a vector by a Vectorizer.

A `VectorizerAttribute` is the abstract class you use to decorate your Vector fields, it is responsible for defining the logic to convert the object's that `Vector<T>` is a container for into actual vector embeddings needed. In the package `Redis.OM.Vectorizers` we provide vectorizers for HuggingFace, OpenAI, and AzureOpenAI to allow you to easily integrate them into your workflows.

#### Define a Vector in your Model.

To define a vector in your model, simply decorate a `Vector<T>` field with an `Indexed` attribute which defines the algorithm and algorithmic parameters and a `Vectorizer` attribute which defines the shape of the vectors, (in this case we'll use OpenAI):

```cs
[Document(StorageType = StorageType.Json)]
public class OpenAICompletionResponse
{
[RedisIdField]
public string Id { get; set; }

[Indexed(DistanceMetric = DistanceMetric.COSINE, Algorithm = VectorAlgorithm.HNSW, M = 16)]
[OpenAIVectorizer]
public Vector<string> Prompt { get; set; }

public string Response { get; set; }

[Indexed]
public string Language { get; set; }

[Indexed]
public DateTime TimeStamp { get; set; }
}
```

#### Insert Vectors into Redis

With the vector defined in our model, all we need to do is create Vectors of the generic type, and insert them with our model. Using our `RedisCollection`, you can do this by simply using `Insert`:

```cs
var collection = _provider.RedisCollection<OpenAICompletionResponse>();
var completionResult = new OpenAICompletionResponse
{
Language = "en_us",
Prompt = Vector.Of("What is the Capital of France?"),
Response = "Paris",
TimeStamp = DateTime.Now - TimeSpan.FromHours(3)
};
collection.Insert(completionResult);
```

The Vectorizer will manage the embedding generation for you without you having to intervene.

#### Query Vectors in Redis

To query vector fields in Redis, all you need to do is use the `VectorRange` method on a vector within our normal LINQ queries, and/or use the `NearestNeighbors` with whatever other filters you want to use, here's some examples:

```cs
var prompt = "What really is the Capital of France?";

// simple vector range, find first within .15
var result = collection.First(x => x.Prompt.VectorRange(prompt, .15));

// simple nearest neighbors query, finds first nearest neighbor
result = collection.NearestNeighbors(x => x.Prompt, 1, prompt).First();

// hybrid query, pre-filters result set for english responses, then runs a nearest neighbors search.
result = collection.Where(x=>x.Language == "en_us").NearestNeighbors(x => x.Prompt, 1, prompt).First();

// hybrid query, pre-filters responses newer than 4 hours, and finds first result within .15
var ts = DateTimeOffset.Now - TimeSpan.FromHours(4);
result = collection.First(x=>x.TimeStamp > ts && x.Prompt.VectorRange(prompt, .15));
```

#### What Happens to the Embeddings?

With Redis OM, the embeddings can be completely transparent to you, they are generated and bound to the `Vector<T>` when you query/insert your vectors. If however you needed your embedding after the insertion/Query, they are available at `Vector<T>.Embedding`, and be queried either as the raw bytes, as an array of doubles or as an array of floats (depending on your vectorizer).

#### Configuration

The Vectorizers provided by the `Redis.OM.Vectorizers` package have some configuration parameters that it will pull in either from your `appsettings.json` file, or your environment variables (with your appsettings taking precedence).

| Configuration Parameter | Description |
|-------------------------------- |-----------------------------------------------|
| REDIS_OM_HF_TOKEN | HuggingFace Authorization token. |
| REDIS_OM_OAI_TOKEN | OpenAI Authorization token |
| REDIS_OM_OAI_API_URL | OpenAI URL |
| REDIS_OM_AZURE_OAI_TOKEN | Azure OpenAI api key |
| REDIS_OM_AZURE_OAI_RESOURCE_NAME | Azure resource name |
| REDIS_OM_AZURE_OAI_DEPLOYMENT_NAME | Azure deployment |

### Semantic Caching

Redis OM also provides the ability to use Semantic Caching, as well as providers for OpenAI, HuggingFace, and Azure OpenAI to perform semantic caching. To use a Semantic Cache, simply pull one out of the RedisConnectionProvider and use `Store` to insert items, and `GetSimilar` to retrieve items. For example:

```cs
var cache = _provider.OpenAISemanticCache(token, threshold: .15);
cache.Store("What is the capital of France?", "Paris");
var res = cache.GetSimilar("What really is the capital of France?").First();
```

### ML.NET Based Vectorizers

We also provide the packages `Redis.OM.Vectorizers.ResNet18` and `Redis.OM.Vectorizers.AllMiniLML6V2` which have embedded models / ML Pipelines in them to
allow you to easily Vectorize Images and Sentences respectively without the need to depend on an external API.

### 🖩 Aggregations

We can also run aggregations on the customer object, again using expressions in LINQ:
Expand Down
112 changes: 58 additions & 54 deletions Redis.OM.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.OM.POC", "src\Redis.O
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.OM.Unit.Tests", "test\Redis.OM.Unit.Tests\Redis.OM.Unit.Tests.csproj", "{570BF479-BCF4-4D1B-A702-2234CA0A3E7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.OM.Test.ConsoleApp", "test\Redis.OM.Test.ConsoleApp\Redis.OM.Test.ConsoleApp.csproj", "{FC7E5ED3-51AC-45E6-A178-6287C9227975}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Vectorizers", "src\Redis.OM.Vectorizers\Redis.OM.Vectorizers.csproj", "{4B9F4623-3126-48B7-B690-F28F702A4717}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Analyzer", "src\Redis.OM.Analyzer\Redis.OM.Analyzer.csproj", "{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vectorizers", "Vectorizers", "{452DC80B-8195-44E8-A376-C246619492A8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.AspNetCore", "src\Redis.OM.AspNetCore\Redis.OM.AspNetCore.csproj", "{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Vectorizers.AllMiniLML6V2", "src\Redis.OM.Vectorizers.AllMiniLML6V2\Redis.OM.Vectorizers.AllMiniLML6V2.csproj", "{081DEE32-9B26-44C6-B377-456E862D3813}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Test.AspDotnetCore", "test\Redis.OM.Test.AspDotnetCore\Redis.OM.Test.AspDotnetCore.csproj", "{3F609AB2-1492-4EBE-9FF2-B47829307E9E}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Vectorizer.Tests", "test\Redis.OM.Vectorizer.Tests\Redis.OM.Vectorizer.Tests.csproj", "{7C3E1D79-408C-45E9-931C-12195DFA268D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.Vectorizers.Resnet18", "src\Redis.OM.Vectorizers.Resnet18\Redis.OM.Vectorizers.Resnet18.csproj", "{FE22706B-9A28-4045-9581-2058F32C4193}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -64,63 +66,65 @@ Global
{570BF479-BCF4-4D1B-A702-2234CA0A3E7D}.Release|x64.Build.0 = Release|Any CPU
{570BF479-BCF4-4D1B-A702-2234CA0A3E7D}.Release|x86.ActiveCfg = Release|Any CPU
{570BF479-BCF4-4D1B-A702-2234CA0A3E7D}.Release|x86.Build.0 = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|x64.Build.0 = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Debug|x86.Build.0 = Debug|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|Any CPU.Build.0 = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|x64.ActiveCfg = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|x64.Build.0 = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|x86.ActiveCfg = Release|Any CPU
{FC7E5ED3-51AC-45E6-A178-6287C9227975}.Release|x86.Build.0 = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|x64.ActiveCfg = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|x64.Build.0 = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|x86.ActiveCfg = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Debug|x86.Build.0 = Debug|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|Any CPU.Build.0 = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|x64.ActiveCfg = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|x64.Build.0 = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|x86.ActiveCfg = Release|Any CPU
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1}.Release|x86.Build.0 = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|x64.ActiveCfg = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|x64.Build.0 = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|x86.ActiveCfg = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Debug|x86.Build.0 = Debug|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|Any CPU.Build.0 = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|x64.ActiveCfg = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|x64.Build.0 = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|x86.ActiveCfg = Release|Any CPU
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF}.Release|x86.Build.0 = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|x64.ActiveCfg = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|x64.Build.0 = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|x86.ActiveCfg = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Debug|x86.Build.0 = Debug|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|Any CPU.Build.0 = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|x64.ActiveCfg = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|x64.Build.0 = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|x86.ActiveCfg = Release|Any CPU
{3F609AB2-1492-4EBE-9FF2-B47829307E9E}.Release|x86.Build.0 = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|x64.ActiveCfg = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|x64.Build.0 = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|x86.ActiveCfg = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Debug|x86.Build.0 = Debug|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|Any CPU.Build.0 = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|x64.ActiveCfg = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|x64.Build.0 = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|x86.ActiveCfg = Release|Any CPU
{4B9F4623-3126-48B7-B690-F28F702A4717}.Release|x86.Build.0 = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|Any CPU.Build.0 = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|x64.ActiveCfg = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|x64.Build.0 = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|x86.ActiveCfg = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Debug|x86.Build.0 = Debug|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|Any CPU.ActiveCfg = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|Any CPU.Build.0 = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|x64.ActiveCfg = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|x64.Build.0 = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|x86.ActiveCfg = Release|Any CPU
{081DEE32-9B26-44C6-B377-456E862D3813}.Release|x86.Build.0 = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|x64.ActiveCfg = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|x64.Build.0 = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|x86.ActiveCfg = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Debug|x86.Build.0 = Debug|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|Any CPU.Build.0 = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|x64.ActiveCfg = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|x64.Build.0 = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|x86.ActiveCfg = Release|Any CPU
{7C3E1D79-408C-45E9-931C-12195DFA268D}.Release|x86.Build.0 = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|x64.ActiveCfg = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|x64.Build.0 = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|x86.ActiveCfg = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Debug|x86.Build.0 = Debug|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|Any CPU.Build.0 = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|x64.ActiveCfg = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|x64.Build.0 = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|x86.ActiveCfg = Release|Any CPU
{FE22706B-9A28-4045-9581-2058F32C4193}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7994382C-28EF-4F55-9B6D-810D35247816} = {8D9ECCFF-E022-4B68-BB43-228CEA248DEC}
{E3A31119-E4F1-4793-B5C2-ED2D51502B01} = {8D9ECCFF-E022-4B68-BB43-228CEA248DEC}
{44FAD9BB-C6DF-402C-BCE7-64E7C674F8D1} = {8D9ECCFF-E022-4B68-BB43-228CEA248DEC}
{230ED77D-D625-43BC-94D6-6BDBACEA3EAF} = {8D9ECCFF-E022-4B68-BB43-228CEA248DEC}
{452DC80B-8195-44E8-A376-C246619492A8} = {8D9ECCFF-E022-4B68-BB43-228CEA248DEC}
{4B9F4623-3126-48B7-B690-F28F702A4717} = {452DC80B-8195-44E8-A376-C246619492A8}
{081DEE32-9B26-44C6-B377-456E862D3813} = {452DC80B-8195-44E8-A376-C246619492A8}
{FE22706B-9A28-4045-9581-2058F32C4193} = {452DC80B-8195-44E8-A376-C246619492A8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E5752441-184B-4F17-BAD0-93823AC68607}
Expand Down
5 changes: 2 additions & 3 deletions dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0

FROM mcr.microsoft.com/dotnet/sdk:7.0

WORKDIR /app
ADD . /app

RUN ls /app
RUN dotnet restore /app/Redis.OM.sln

ENTRYPOINT ["dotnet","test"]
ENTRYPOINT ["dotnet", "test", "--framework", "net7.0" ]
4 changes: 2 additions & 2 deletions src/Redis.OM.POC/RedisCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ public static long XAck(this IRedisConnection connection, string streamId, strin
public static async Task<string?> XAddAsync(this IRedisConnection connection, string streamId, object message, string messageId = "*", int maxLen = -1, string minId = "", bool trimApprox = true, bool makeStream = true)
{
var kvps = message.BuildHashSet();
var args = new List<string> { streamId };
var args = new List<object> { streamId };
if (!makeStream)
{
args.Add("NOMKSTREAM");
Expand Down Expand Up @@ -611,7 +611,7 @@ public static long XAck(this IRedisConnection connection, string streamId, strin
public static string? XAdd(this IRedisConnection connection, string streamId, object message, string messageId = "*", int maxLen = -1, string minId = "", bool trimApprox = true, bool makeStream = true)
{
var kvps = message.BuildHashSet();
var args = new List<string> { streamId };
var args = new List<object> { streamId };
if (!makeStream)
{
args.Add("NOMKSTREAM");
Expand Down
Loading

0 comments on commit cf41ed7

Please sign in to comment.