Developing Record UDFs
A Record UDF is a User-Defined Function that is applied to a single record. Record UDFs can be used to augment both read and write behavior.
Typical uses for Record-Based UDFs
Record UDFs can be used to implement an atomic operation that does not currently exist in the client. As a UDF will not perform at the same speed and scale as native operations, it is important to consider whether the rich
List and Map API methods cannot achieve the same effect. Combining multiple native operations through the `operate()` command should also be considered, before using a UDF.Record UDFs can be used for single-record, multi-operation transactions where data from one bin is used to determine the value of another bin.
Use record UDFs to extend the existing list of predicate filtering operators for scan and query.
Background UDFs are good for large scale maintenance and data normalization, with a record UDF applied to all the records returned by a scan or query.
General Comments on Record UDFs:
- The first argument of the function, such as
rec
, refers to the database record. Do not name the variablerecord
as this is one of the types in the Aerospike Lua API. - Each subsequent argument is specific to the UDF, and must be one of the types supported by the database: numeric (integer or double), string, list or map.
- A Record UDF should have one or more parameters (the record and optionally
more). If a UDF has N parameters, and only (N-k) arguments passed in, the
last k will automatically be assigned a value of
nil
. - A Record UDF may return one of the types supported by the database: numeric (integer or double), string, bytes, list or map.
- As of server version 4.7, metadata predicate filters may be applied to Record UDF transactions.
- A background UDF, where a single User-Defined Function is applied by scan or query, modifies records without returning a result (write only).
Record TTL and UDF
When creating or updating a record, its new TTL value adheres to the following hierarchy:
- If the UDF explicitly calls
record.set_ttl()
, that value is used. See Setting time-to-live. - If there is a ttl specified in the policy field of the client UDF call, that value is used. See Expiration (Time to Live).
- If the client policy passes a TTL of 0, the namespace'sdefault-ttl will be used.
Example: Record Create or Update
In this simple example, Annotated Record UDF Example, we show how the UDF can create or update an Aerospike record.
Example: String Slice Operator
Aerospike has two atomic operations for the String data type - append and prepend. The following record UDF adds an atomic string slice operator.
function slice(rec, bin, a, b)
local s = rec[bin]
if type(s) == 'string' then
return s:sub(a, b)
end
return nil
end
In aql
aql> register module 'util.lua'
OK, 1 module added.
aql> insert into test.foo (PK, x) values ('1', "Alright I like the beat except the snare, kick and keys")
OK, 1 record affected.
aql> execute util.slice('x', 9, 23) on test.foo where PK='1'
+-------------------+
| slice |
+-------------------+
| "I like the beat" |
+-------------------+
1 row in set (0.001 secs)
Example: Using Protobuf
In this example, a UDF makes use of an external Lua module, which in turns calls a C shared object. The Protobuf Module Example gives more details about the code involved in this example.
aql> select * from test.foo where PK='1'
Error: (2) AEROSPIKE_ERR_RECORD_NOT_FOUND
aql> execute pbuf.vartix(123, 'JDoe', 'j.doe@gmail.com') on test.foo where PK='1'
+--------+
| vartix |
+--------+
| |
+--------+
1 row in set (0.001 secs)
aql> select * from test.foo where PK='1'
+----------------------------------------------------------------------------------------------+
| person |
+----------------------------------------------------------------------------------------------+
| 12 03 57 69 6C 08 7B 1A 16 77 69 6C 2E 6A 61 6D 69 65 73 6F 6E 40 67 6D 61 69 6C 2E 63 6F 6D |
+----------------------------------------------------------------------------------------------+
1 row in set (0.000 secs)
aql> execute pbuf.velkor() on test.foo where PK='1'
+--------+
| velkor |
+--------+
| 123 |
+--------+
1 row in set (0.000 secs)
Example: Using a Background UDF to Reset TTLs
The Background UDF Example resets the TTL of records accidentally set to never expire.