应用函数是您可以定义为表达式以应用于 Redis 中数据的函数。从本质上讲,它们允许您将数据组合在一起,并提取所需的信息。
在本文的其余部分中,我们将使用此数据模型
[Document]
public class Employee
{
[Indexed(Aggregatable = true)]
public string Name { get; set; }
[Indexed]
public GeoLoc? HomeLoc { get; set; }
[Indexed(Aggregatable = true)]
public int Age { get; set; }
[Indexed(Aggregatable = true)]
public double Sales { get; set; }
[Indexed(Aggregatable = true)]
public double SalesAdjustment { get; set; }
[Searchable(Aggregatable = true)]
public string Department { get; set; }
[Indexed(Aggregatable = true)]
public long LastOnline { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
}
Apply
是 RedisAggregationSet<T>
类上的一个方法,它接受两个参数,每个参数都是应用函数的一个组件。
首先,它接受您希望 Redis 在管道中的每条记录上执行的表达式,该表达式接受一个参数,即 AggregationResult<T>
,其中 T
是 RedisAggregationSet
的泛型类型。此 AggregationResult 有两件事我们应该考虑,首先它包含一个 RecordShell
,它是泛型类型的占位符,其次它有一个 Aggregations
属性 - 它是一个包含来自管道结果的字典。这两者都可以在应用函数中使用。
第二个组件是别名,它是管道执行时函数结果存储的名称。
我们的数据模型有两个与销售额相关的属性,Sales
,表示员工的销售额,以及 SalesAdjustment
,一个用于根据各种因素(可能是覆盖区域、经验等)调整销售额的数字。其理念是,也许分析员工绩效的公平方法是结合这两个字段,而不是单独分析每个字段。假设我们想找出每个人的调整后销售额,我们可以通过创建一个应用函数来计算它。
var adjustedSales = employeeAggregations.Apply(x => x.RecordShell.SalesAdjustment * x.RecordShell.Sales,
"ADJUSTED_SALES");
foreach (var result in adjustedSales)
{
Console.WriteLine($"Adjusted Sales were: {result["ADJUSTED_SALES"]}");
}
使用算术和数学的函数可以使用数学运算符 +
进行加法运算,-
进行减法运算,*
进行乘法运算,/
进行除法运算,以及 %
进行取模运算,此外,通常用于按位异或运算的 ^
运算符已预留用于幂函数。此外,您可以在 Apply 函数中使用许多 System.Math
库运算,这些运算将转换为适当的方法供 Redis 使用。
函数 | 类型 | 描述 | 示例 |
---|---|---|---|
Log10 | 数学 | 产生数字的 10 为底的对数 | Math.Log10(x["AdjustedSales"]) |
Abs | 数学 | 产生所提供数字的绝对值 |
|
Ceil | 数学 | 产生不小于所提供数字的最小整数 |
|
Floor | 数学 | 产生不大于所提供数字的最大整数 |
|
Log | 数学 | 产生所提供数字的 2 为底的对数 |
|
Exp | 数学 | 产生所提供数字的自然指数 (e^y) |
|
Sqrt | 数学 | 产生所提供数字的平方根 |
|
您还可以对数据应用多个字符串函数,例如,如果要为每个员工创建生日消息,可以通过调用 String.Format 来实现:
var birthdayMessages = employeeAggregations.Apply(x =>
string.Format("Congratulations {0} you are {1} years old!", x.RecordShell.Name, x.RecordShell.Age), "message");
await foreach (var message in birthdayMessages)
{
Console.WriteLine(message["message"].ToString());
}
函数 | 类型 | 描述 | 示例 |
---|---|---|---|
ToUpper | 字符串 | 将提供的字符串转换为大写 |
|
ToLower | 字符串 | 将提供的字符串转换为小写 |
|
StartsWith | 字符串 | 布尔表达式 - 如果字符串以参数开头,则产生 1 |
|
Contains | 字符串 | 布尔表达式 - 如果字符串包含参数,则产生 1 |
|
Substring | 字符串 | 产生从给定的从 0 开始的索引开始的子字符串,长度为第二个参数,如果没有提供第二个参数,则 simplemente 返回字符串的剩余部分 |
|
Format | 字符串 | 根据提供的模式格式化字符串 |
|
Split | 字符串 | 使用提供的字符串拆分字符串 - 不幸的是,如果您只传入一个分隔符,由于表达式的运作方式,您需要提供字符串拆分选项,以便在构建表达式时不存在可选参数,只需传递 |
|
您还可以在 Redis 中对时间数据执行函数。如果您的时间戳存储为可用格式,例如 Unix 时间戳或可以从 strftime转换的时间戳字符串,则可以对其进行操作。例如,如果要将 Unix 时间戳转换为 YYYY-MM-DDTHH:MM::SSZ 格式,则只需在应用函数内部调用 ApplyFunctions.FormatTimestamp 即可。例如:
var lastOnline = employeeAggregations.Apply(x => ApplyFunctions.FormatTimestamp(x.RecordShell.LastOnline),
"LAST_ONLINE_STRING");
foreach (var employee in lastOnline)
{
Console.WriteLine(employee["LAST_ONLINE_STRING"].ToString());
}
函数 | 类型 | 描述 | 示例 |
---|---|---|---|
ApplyFunctions.FormatTimestamp | 时间 | 根据 strftime 约定将 Unix 时间戳转换为格式化的时间字符串 |
|
ApplyFunctions.ParseTime | 时间 | 将提供的格式化时间戳解析为 Unix 时间戳 |
|
ApplyFunctions.Day | 时间 | 将 Unix 时间戳舍入到当天的开始时间 |
|
ApplyFunctions.Hour | 时间 | 将 Unix 时间戳舍入到当前小时的开始时间 |
|
ApplyFunctions.Minute | 时间 | 将 Unix 时间戳舍入到当前分钟的开始时间 |
|
ApplyFunctions.Month | 时间 | 将 Unix 时间戳舍入到当前月的开始时间 |
|
ApplyFunctions.DayOfWeek | 时间 | 将 Unix 时间戳转换为星期几,其中星期日为 0 |
|
ApplyFunctions.DayOfMonth | 时间 | 将 Unix 时间戳转换为当前月的哪一天 (1..31) |
|
ApplyFunctions.DayOfYear | 时间 | 将 Unix 时间戳转换为当前年的哪一天 (1..31) |
|
ApplyFunctions.Year | 时间 | 将 Unix 时间戳转换为当前年份 |
|
ApplyFunctions.MonthOfYear | 时间 | 将 Unix 时间戳转换为当前年份 |
|
另一个很有用的函数是 GeoDistance
函数,它允许您计算两点之间的距离,例如,如果您想查看每个员工离办公室有多远,可以使用管道内的 ApplyFunctions.GeoDistance
函数。
var officeLoc = new GeoLoc(-122.064181, 37.377207);
var distanceFromWork =
employeeAggregations.Apply(x => ApplyFunctions.GeoDistance(x.RecordShell.HomeLoc, officeLoc), "DistanceToWork");
await foreach (var element in distancesFromWork)
{
Console.WriteLine(element["DistanceToWork"].ToString());
}