{"id":16330259,"url":"https://github.com/redis-developer/product-catalog-redis-om-dotnet","last_synced_at":"2025-04-09T21:32:43.773Z","repository":{"id":210913684,"uuid":"727433470","full_name":"redis-developer/product-catalog-redis-om-dotnet","owner":"redis-developer","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-06T21:07:34.000Z","size":351,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T12:11:31.326Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redis-developer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-12-04T21:14:54.000Z","updated_at":"2024-10-14T15:17:40.000Z","dependencies_parsed_at":"2023-12-06T22:24:29.232Z","dependency_job_id":"f1211868-018b-4245-9e7c-33764fe60e65","html_url":"https://github.com/redis-developer/product-catalog-redis-om-dotnet","commit_stats":null,"previous_names":["slorello89/product-catalog-redis-om-dotnet","redis-developer/product-catalog-redis-om-dotnet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fproduct-catalog-redis-om-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fproduct-catalog-redis-om-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fproduct-catalog-redis-om-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fproduct-catalog-redis-om-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redis-developer","download_url":"https://codeload.github.com/redis-developer/product-catalog-redis-om-dotnet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248114886,"owners_count":21050137,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T23:18:52.089Z","updated_at":"2025-04-09T21:32:43.317Z","avatar_url":"https://github.com/redis-developer.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redis OM .NET Vector Search Product Catalog Demo\n\nThis demo is a practical example of how to use Redis Stack and Redis Enterprise's Vector Search with Redis OM .NET. This allows you to use Redis easily as a highly performant Vector Database in your applications.\n\n## Capabilities demonstrated\n\nThe following Redis Vector Search capabilities are demonstrated by this app:\n\n* Vector Search:\n    * Using Images\n    * Using Text\n* Vector Indexing Types\n    * HNSW\n    * Flat(brute-force)\n* Easily extensible hybrid queries to pre-filter your indexes\n\n## Application\n\nThis repo contains two applications\n\n1. SeedDatabase - a simple console app to seed the database from the dataset.\n2. ProductCatalog - a Single Page Application (SPA) to display and filter products from the dataset.\n\n## Technologies Used\n\nThese applications make use of the following:\n\n* [Redis Stack](https://redis.io/docs/about/about-stack/): For Vector Search + JSON document storage\n* ASP.NET Core: To build the API backend.\n* ReactL for the frontend\n* Redis OM .NET: For index modeling, vector generation, all Document Creation, Reading, Updating, and Deleting (CRUD) in Redis.\n    * Redis OM uses Resnet 18 for Image Vectorization\n    * Redis OM uses [All-MiniLM-L6-V2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) for sentence vectorization\n\n## How to Run this Demo\n\n### Get the Dataset\n\nBefore running the app, you must acquire the \"fashion dataset\". You can use either of the following:\n\n* [Large](https://www.kaggle.com/datasets/paramaggarwal/fashion-product-images-dataset) ~ 25 GB\n* [Small](https://www.kaggle.com/datasets/paramaggarwal/fashion-product-images-small) ~ 500MB\n\nEither is permissible, however if you use the small data set, your images will look a bit grainy in the app.\n\nDownload either data set and unzip it, the root of the unzipped folder will be our `DATASET_ROOT` environment variable.\n\n### Configure Redis\n\n#### Redis Cloud (recommended)\n\n1. [Configure your Redis Cloud Instance](https://app.redislabs.com/#/) if needed\n2. Set the following environment variables to point at your Redis Cloud instance:\n    1. `REDIS_HOST`\n    2. `REDIS_PORT`\n    3. `REDIS_PASSWORD`\n\n#### Redis in Docker:\n\nIf you want to run Redis locally in docker run the following:\n\n`docker run -d -p 6379:6379 redis/redis-stack-server`\n\n### Clone this Repository\n\nClone this repository using the following:\n\n\n```sh\ngit clone https://github.com/redis-developer/ProductCatalog\n```\n\nChange directory into the newly created `ProductCatalog` directory `cd ProductCatalog`\n\n### Seed your Database\n\nTo seed your database, take the base path of the dataset (the `DATASET_ROOT` variable from before), and decide where you want to put the JSON backup of your vectors (at the root of the `ProductCatalog` repo is fine) and run the following:\n\n```sh\nOUTPUT_DIR=\u003coutput_dir\u003e DATASET_ROOT=\u003cdataset_root\u003e dotnet run --project SeedDatabase\n```\n\nReplacing `\u003coutput_dir\u003e` and `DATASET_ROOT` the the appropriate directories.\n\nSeeding the database takes some time (95% of which is simply generating the vectors).\n\n### Configure the app\n\nOpen `ProductCatalog/Properties/launchSettings.json`, and update the `DATASET_ROOT` environment variable to point at your dataset root (absolute path).\n\n### Run the App\n\nTo Run the app just run:\n\n```sh\ndotnet run --project ProductCatalog\n```\n\nThe app will come up, and you can start the SPA app by visiting `https://localhost:7161` in your browser.\n\n## How it Works\n\nThe application leverage Redis OM for \n\n1. Index Creation\n2. Document/Vector creation \u0026 insertion\n3. Document/Vector querying.\n\nLet's explore each of these\n\n### Index Creation\n\nAll Index creation is handled by one line inside of `SeedDatabase/Program.cs`:\n\n```cs\nawait provider.Connection.CreateIndexAsync(typeof(Product))\n```\n\nRedis OM looks at the class `Product`, and basis it's decision about how to generate the index based off of that, let's take a look at this class in `ProductCatalog.Shared/Model/Product.cs`:\n\n``` cs\n[Document(StorageType = StorageType.Json)]\npublic class Product\n{\n    [Indexed(DistanceMetric = DistanceMetric.COSINE, Algorithm = VectorAlgorithm.HNSW)] \n    [ImageVectorizer]\n    public Vector\u003cstring\u003e ImageUrl { get; set; }    \n\n    [Indexed(Algorithm = VectorAlgorithm.HNSW, DistanceMetric = DistanceMetric.COSINE)] \n    [SentenceVectorizer] \n    public Vector\u003cstring\u003e ProductDisplayName { get; set; }\n    \n    public VectorScores? Scores { get; set; }\n\n    // ... other indexed facets\n}\n```\n\nThe two key fields are `ImageUrl` and `ProductDisplayName`, they are both of type `Vector\u003cstring\u003e`. The `IndexedAttribute` decorating each of them tells Redis OM that the item is meant to be indexed, and the Particular Vectorizers above each of them `ImageVectorizer` and `SentenceVectorizer` above each of them contain the behavior for how the vectorization should be performed for each. The `ImageVectorizer` downloads the image and runs it through ResNet18, and the `SentenceVectorizer` simply runs the ProductDisplayName through [All-MiniLM-L6-V2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2). Both use ML.NET for vectorization.\n\n### Insertion\n\nThe Insertion tasks are all performed in `SeedDatabase/Program.cs` For the sake of speeding up the initial load, we leverage the batch-vectorizers from both `ImageVectorizer` and `SentenceVectorizer`, so there's a tiny bit more to insertions (as you create the embeddings and the set the Vectors embedding to the embeddings), but generally, insertion is as simple as:\n\n```cs\nvar entry = new Product { \n            Id = id, \n            ImageUrl = Vector.Of(imageUrl), \n            ProductDisplayName = Vector.Of(productDisplayName)\n            // other fields\n        };\nawait collection.InsertAsync(entry)\n```\n\n### Querying Nearest Neighbors\n\nTo query Nearest Neighbors using Redis OM, all you need to do is invoke the `NearestNeighbors` extension of the RedisCollection. See the `Filter` method in `ProductCatalog/Controllers/ProductController.cs`,\n\n```cs\ncollection = collection.NearestNeighbors(x =\u003e x.ImageUrl, numNeighbors,  $\"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/{options.ImageUrl}\").OrderBy(x=\u003ex.Scores!.NearestNeighborsScore);\n```\n\nThat's it, simply provide the Field, the number of neighbors you want to query, and the item you want to compare.\n\n### Hybrid Queries\n\nIf you want to perform hybrid queries, Nearest Neighbor queries first filtered by other facets, simply query those indexed fields from `Product` that interest you. E.g.\n\n```cs\ncollection = collection.Where(x =\u003e options.Genders.Contains(x.Gender));\n```\n\nThat's it!\n\n## What if I want to use My own Vectorization logic\n\nImplementing your own Vectorizers is simple, all you need to do is create a class that Extends `VectorizerAttribute\u003cT\u003e` and another `IVectorizer\u003cT\u003e` that actually performs the vectorization logic. You will just need to know the shape of your vectors ahead of time.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Fproduct-catalog-redis-om-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredis-developer%2Fproduct-catalog-redis-om-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Fproduct-catalog-redis-om-dotnet/lists"}