Learn

Apply functions are functions that you can define as expressions to apply to your data in Redis. In essence, they allow you to combine your data together, and extract the information you want.

Data Model#

For the remainder of this article we will be using this data model:

[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();
}

Anatomy of an Apply Function#

Apply is a method on the RedisAggregationSet<T> class which takes two arguments, each of which is a component of the apply function.

First it takes the expression that you want Redis to execute on every record in the pipeline, this expression takes a single parameter, an AggregationResult<T>, where T is the generic type of your RedisAggregationSet. This AggregationResult has two things we should think about, first it contains a RecordShell which is a placeholder for the generic type, and secondly it has an Aggregations property - which is a dictionary containing the results from your pipeline. Both of these can be used in apply functions.

The second component is the alias, that's the name the result of the function is stored in when the pipeline executes.

Adjusted Sales#

Our data model has two properties related to sales, Sales, how much the employee has sold, and SalesAdjustment, a figure used to adjust sales based off various factors, perhaps territory covered, experience, etc. . . The idea being that perhaps a fair way to analyze an employee's performance is a combination of these two fields rather than each individually. So let's say we wanted to find what everyone's adjusted sales were, we could do that by creating an apply function to calculate it.

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"]}");
}

Arithmetic Apply Functions#

Functions that use arithmetic and math can use the mathematical operators + for addition, - for subtraction, * for multiplication, / for division, and % for modular division, also the ^ operator, which is typically used for bitiwise exclusive-or operations, has been reserved for power functions. Additionally, you can use many System.Math library operations within Apply functions, and those will be translated to the appropriate methods for use by Redis.

Available Math Functions#

String Functions#

You can also apply multiple string functions to your data, if for example you wanted to create a birthday message for each employee you could do so by calling String.Format on your records:

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());
}

List of String Functions:#

Time Functions#

You can also perform functions on time data in Redis. If you have a timestamp stored in a useable format, a unix timestamp or a timestamp string that can be translated from strftime, you can operate on them. For example if you wanted to translate a unix timestamp to YYYY-MM-DDTHH:MM::SSZ you can do so by just calling ApplyFunctions.FormatTimestamp on the record inside of your apply function. E.g.

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());
}

Time Functions Available#

Geo Distance#

Another useful function is the GeoDistance function, which allows you computer the distance between two points, e.g. if you wanted to see how far away from the office each employee was you could use the ApplyFunctions.GeoDistance function inside your pipeline:

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());
}