Apply a UDF
Single record
Use the Aerospike C client API aerospike_key_apply()
to apply a Record UDF against a record in the database.
Before using aerospike_key_apply()
, the UDF module that contains the function must register with the Aerospike server. See Register UDF.
This example is an excerpt from examples/basic_examples/get in the Aerospike C client package.
To continue, the client must have an established the cluster connection.
Defining the UDF
To define bin_transform
in the basice_udf
module:
function bin_transform(record, bin_name, x, y)
record[bin_name] = (record[bin_name] * x) + y
aerospike:update(record)
return record[bin_name]
end
This simple arithmetic UDF has three arguments: bin_name, x, and y. It updates the value in the specified bin after performing the arithmetic operation, and returns the resulting bin value.
Initializing a Key
The application identifies records in the database using a key. In this example, the key value is the string test-key, stored in namespace test within set test-set. key can be other data types such as integer or blob.
as_key key;
as_key_init_str(&key, "test", "test-set", "test-key");
Passing Parameters to the UDF
The bin_transform UDF requires a string parameter and two integer parameters, so first, populate an argument list:
as_arraylist args;
as_arraylist_inita(&args, 3);
as_arraylist_append_str(&args, "test-bin-2");
as_arraylist_append_int64(&args, 4);
as_arraylist_append_int64(&args, 400);
Applying a UDF on a Record
To call the UDF on the record in the database using key:
as_val * result = NULL;
if (aerospike_key_apply(&as, &err, NULL, &key, "mymodule", "add",
(as_list *) &args, &result) != AEROSPIKE_OK) {
fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);
}
The value from the bin_transform()
UDF returns in the result
parameter:
- If key does not exist,
AEROSPIKE_ERR_RECORD_NOT_FOUND
returns. - If the UDF is found or if there is a run-time error executing the UDF, details on the error returns in
as_error
.
Cleaning Up Resources
Use as_val_destroy()
to release the UDF and associated resources:
as_val_destroy(&result);
Use as_arraylist_destroy()
to clean up the arguments list:
as_arraylist_destroy(&args);
The key does not require an explicit destroy call since it and its members are created on the stack.
Transform
Use the Aerospike C client to scan the records in the database and transform each record using UDFs.
In SQL, a transformation on all rows in a table is performed as an UPDATE
statement without predicates:
UPDATE test.demo
SET a = 1, b = 2, c = 3
The Aerospike C client provides similar capabilities, but goes beyond what SQL provides by allowing you to transform records by applying a Record UDF on each record. These Record UDFs are applied to individual records, can have arguments, and can read and write the bins of a record and perform calculations.
Scanning and applying a Record UDF on each record can only be performed in the background; that is, the client sends the scan request to the database and does not wait for results. The scan is queued and runs on the database, and no results return to the client. The client has a scan ID, so can check status.
Defining the Scan
For scans that transform each record, define a UDF to execute on each record and execute the scan using the background scan operation, aerospike_scan_background()
.
You build the scan just like in Scan Records, but use as_scan_apply_each()
:
as_scan scan;
as_scan_init(&scan, "test", "demo");
as_scan_apply_each(&scan, "mymodule", "mytransform", NULL);
Operation sequence:
- Create an
as_scan
on the stack (line 1). - Initialize the scan to scan the Namespace test within set demo (line 2).
- Add a Record UDF to apply to each record scanned.
The UDF mytransform()
is defined in the mymodule
UDF module. The UDF in this example is provided arguments.
Defining the Record UDF
The example uses the mytransform
Record UDF defined in mymodule
and mimics the SQL statement above.
function mytransform(rec)
rec['a'] = 1
rec['b'] = 2
rec['c'] = 3
aerospike:update(rec)
end
This more elaborate example increments a, calculates b based on a, and calculates c based on the values of a and b:
function mytransform(rec)
rec['a'] = rec['a'] + 1
rec['b'] = rec['a'] * 2
rec['c'] = rec['a'] + rec['b']
aerospike:update(rec)
end
Executing the Scan
To execute the scan using aerospike_scan_background()
:
uint64_t scan_id = 0;
if (aerospike_scan_background(&as, &err, NULL, &scan, &scan_id) != AEROSPIKE_OK) {
fprintf(stderr, "error(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);
}
scan_id
queries the scan status. If scan_id
= 0 (zero), the scan operation generates and sets the value of scan_id
.
Checking Scan Status
To query scan status using aerospike_scan_info()
:
as_scan_info scan_info;
if (aerospike_scan_info(&as, &err, NULL, scan_id, &scan_info) != AEROSPIKE_OK) {
fprintf(stderr, "error(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);
}
This populates as_scan_info
with the scan status.