Redis OM
Redis OM 是 Redis 官方推出的物件對映框架,即:Object Mapping。讓開發人員更簡單、方便的操作 Redis 資料。Redis 儲存的資料抽象為物件對映,支援基於物件的 Redis 資料持久化、流式查詢操作。
目前只支援 4 種開發語言:
- Redis OM for Spring
- Redis OM for .NET
- Redis OM for Node.js
- Redis OM for Python
Redis OM .NET
Redis OM .NET 是.Net 平臺的 Redis OM,依賴 StackExchange.Redis 實現。藉助 Redis OM .NET 可以實現物件操作的方式操作 Redis 資料,脫離 key/value 的操作方式。
查詢支援大部分.Neter 最愛的 LINQ。
快速開始
安裝對應包
dotnet add package Redis.OM
Redis 環境準備
直接使用 Docker 的方式安裝 Redis 環境。
docker run -p 6379:6379 redislabs/redismod:preview
標準的官方映象是無法支援 Redis OM,需要 Redis Modules 支援,Redis OM 核心建立索引、查詢資料依賴
RediSearch
這個 Module 實現。依賴的 Module 有:RediSearch、RedisJSON。
RedisJSON 的依賴不是必須的,但是會缺少相應的功能,如:模型巢狀、複雜查詢(只支援 key 查詢)
Coding
增加抽象物件定義
[Document]
public class Customer
{
[RedisIdField]
public string Id { get; set; }
[Indexed(Sortable = true, Aggregatable = true)]
public string FirstName { get; set; }
[Indexed(Sortable = true, Aggregatable = true)]
public string LastName { get; set; }
[Indexed]
public string Email { get; set; }
[Indexed(Sortable = true)]
public int Age { get; set; }
}
Document、Indexed、Searchable 等特性介紹,介紹參考 Github -> document-attribute
獲取抽象物件的操作集合、建立索引
var provider = new RedisConnectionProvider("redis://localhost:6377");
var connection = provider.Connection;
var customers = provider.RedisCollection<Customer>();
connection.CreateIndex(typeof(Customer));
查詢資料、聚合操作等需要依據索引,所以一定要先呼叫connection.CreateIndex
建立索引,對應 RediSearch 的FT.CREATE
命令。
connection.CreateIndex(typeof(Customer)) 建立索引重複執行會丟擲異常
Index already exists
。雖然可以通過connection.Execute("FT.INFO", $"customer-idx")
獲取索引資訊,但是第一次索引不存在時會丟擲Unknown Index name
。所以實際使用中可能需要一個 try-catch 包住CreateIndex
方法避免異常。
插入資料
var id = customers.Insert(new Customer { FirstName = "Steve", Email = "xxxx@masa.com", Age = 1 });
var id2 = customers.Insert(new Customer { FirstName = "FirstName", LastName = "LastName", Email = "xxxx@masa.com" });
id,id2 為插入資料的 key,沒有指定 Document 的 Prefixes 和 IdGenerationStrategy,則預設為 ULID 格式為{DocumentName}:{Ulid}
,如:`Cust
插入資料時需要注意的是,如果對沒有明確指定欄位的值,如 LastName 不明確賦值:
customers.Insert(new Customer { FirstName = "Steve", Email = "xxxx@masa.com", Age = 1 });
,檢視 Redis 中存的資料可以發現當前 key 儲存的 json 資料沒有未指定的欄位對應的 key(此時 Query 或 Aggregations 會有些奇怪的錯誤)。可以根據自己需要,顯示的為欄位賦個零值或者在定義實體時使用public string LastName { get; set; } = string.Empty;
的方式。
查詢資料
var customer = customers.Where(x => x.Age == 0).OrderBy(a => a.FirstName).FirstOrDefault();
var customerById = customers.FindById(id);//根據Id查詢
var emails = customers.Select(x => x.Email);//僅查詢指定欄位
var takes = customers.Where(x => x.Age > 0).Take(10);//獲取指定條數
var adults = customers.Where(x => x.Age >= 0).Skip(5);//查詢偏移
對於空值的判斷,x.FirstName == ""【語法錯誤】 或 string.IsNullOrEmpty(x.FirstName)【不支援】。Redis 雜湊中不能有空字串,所以類似的查詢應該通過聚合操作的Exists
方法實現
foreach (var agg in customerAggregations.Apply(x => ApplyFunctions.Exists(x.RecordShell.LastName), "LastNameExists"))
{
Console.WriteLine($"{agg["LastNameExists"]}");
}
聚合操作
流水線(Pipelining)同時傳送多個請求,從而減輕延遲。結果的查詢和轉化都在 Redis 端完成。
RecordShell 是遠端 Index 型別的結構,RecordShell 應該只在聚合操作流水線內部使用,執行時並沒有真正的值。
拼湊 FirstName 和 LastName,返回 FullName
var customerAggregations = provider.AggregationSet<Customer>();
var age = customerAggregations.Average(x => x.RecordShell.Age);
var sets = customerAggregations.Where(a => a.RecordShell.FirstName == "Steve").Apply(x => string.Format("{0} {1}", x.RecordShell.FirstName, x.RecordShell.LastName), "FullName");
foreach (var item in sets)
{
Console.WriteLine(item["FullName"].ToString());
}
聚合分組
通過 GroupBy 方法,依據不同屬性進行分組聚合(支援單欄位分組和多欄位分組)。
var res = customerAggregations
.GroupBy(x => x.RecordShell.FirstName)
.GroupBy(x => x.RecordShell.LastName)
.ToArray();
var res1 = customerAggregations.GroupBy(x => x.RecordShell.FirstName).CloseGroup().ToArray();
CloseGroup 可以關閉分組,轉換為正常的聚合操作,即 GroupedAggregationSet 到 RedisAggregationSet 的一個轉換。
public static RedisAggregationSet<T> CloseGroup<T>(this GroupedAggregationSet<T> source)
{
return new RedisAggregationSet<T>(source, source.Expression);
}
結尾
本文只是對 Redis OM .NET 用法的簡單梳理和可用性驗證。
更多用法以及用法更新參考Github
我們正在行動,新的框架、新的生態
我們的目標是自由的
、易用的
、可塑性強的
、功能豐富的
、健壯的
。
所以我們借鑑Building blocks的設計理念,正在做一個新的框架MASA Framework
,它有哪些特點呢?
- 原生支援Dapr,且允許將Dapr替換成傳統通訊方式
- 架構不限,單體應用、SOA、微服務都支援
- 支援.Net原生框架,降低學習負擔,除特定領域必須引入的概念,堅持不造新輪子
- 豐富的生態支援,除了框架以外還有元件庫、許可權中心、配置中心、故障排查中心、報警中心等一系列產品
- 核心程式碼庫的單元測試覆蓋率90%+
- 開源、免費、社群驅動
- 還有什麼?我們在等你,一起來討論
經過幾個月的生產專案實踐,已完成POC,目前正在把之前的積累重構到新的開源專案中
目前原始碼已開始同步到Github(文件站點在規劃中,會慢慢完善起來):
QQ群:7424099
微信群:加技術運營微信(MasaStackTechOps),備註來意,邀請進群
------ END ------
作者簡介
馬躍:MASA技術團隊成員。