Skip to content

Filter expressions

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This page is for developers using Aerospike client libraries. Complete Setup first. After reading this page, you can attach filter expressions to all Aerospike operations to select records server-side.

Filter expressions are so named because they are used as a condition to select or discard a record. They always evaluate to a boolean value to indicate whether the record is selected (true) or filtered out (false). A filter expression is sent to the server through the API’s policy object parameter.

Policy policy = new Policy();
policy.filterExp = Exp.build( // sent through filterExp attribute of policy
Exp.eq(
Exp.intBin("a"),
Exp.val(11)));
...
client.query(policy, stmt) // policy is specified as a parameter in API calls

With the Developer SDK, the same filter is AEL text passed to .where():

DataSet records = DataSet.of(NAMESPACE, SET_NAME);
RecordStream stream = session.query(records)
.where("$.a == 11")
.execute();

Code example

The following example illustrates the capabilities of filtering on metadata and use of List APIs.

In this illustrative example the filter selects:

  • recently updated (sinceUpdate < 2) records
  • with list bin having values that range from max to min greater than 1000.
  1. Populate the test data with 20 records with an integer bin “bin1” values 1-20 and a list bin having 3 randomly selected numbers in the range 0 to 1999.
  2. Sleep for 2 seconds,
  3. Touch the even numbered records.
  4. Run the query with the filter.

The results should only contain even valued bin1 and bin2 with value range > 1000.

import java.util.ArrayList;
import java.util.Random;
import com.aerospike.client.AerospikeException;
import com.aerospike.client.Bin;
import com.aerospike.client.Key;
import com.aerospike.client.policy.WritePolicy;
import com.aerospike.client.policy.QueryPolicy;
import com.aerospike.client.exp.Exp;
import com.aerospike.client.exp.ListExp;
import com.aerospike.client.Operation;
import com.aerospike.client.task.ExecuteTask;
import com.aerospike.client.query.Statement;
import com.aerospike.client.query.RecordSet;
import com.aerospike.client.Record;
import com.aerospike.client.cdt.ListReturnType;
// start with a clean state
truncateTestData();
// 1. Populate the test data with 20 records with an integer bin "bin1" values 1-20
// and a list bin having 3 randomly selected numbers in the range 1 to 2000.
Random rand = new Random(1);
final int LIST_RANGE = 2000;
WritePolicy wpolicy = client.copyWritePolicy();
wpolicy.sendKey = true;
for (int i = 1; i <= 20; i++) {
Key key = new Key(NAMESPACE, SET_NAME, "id-"+i);
Bin bin1 = new Bin("bin1", i);
List<Integer> intList = List.of(
rand.nextInt(LIST_RANGE),
rand.nextInt(LIST_RANGE),
rand.nextInt(LIST_RANGE));
Bin bin2 = new Bin("bin2", intList);
client.put(wpolicy, key, bin1, bin2);
}
System.out.println("Test data populated.");;
// 2. Sleep for 2 seconds,
Thread.sleep(2000);
// 3. Touch the even numbered records.
Statement stmt = new Statement();
stmt.setNamespace(NAMESPACE);
stmt.setSetName(SET_NAME);
WritePolicy policy = client.copyWritePolicy();
policy.filterExp = Exp.build(
Exp.eq(
Exp.mod(Exp.intBin("bin1"), Exp.val(2)),
Exp.val(0)));
ExecuteTask task = client.execute(policy, stmt, Operation.touch());
task.waitTillComplete(500, 1000);
System.out.println("Touched even numbered records.");;
// 4. Run the query with the filter.
// records updated in last 2 seconds and whose list value range is more than 1000
stmt = new Statement();
stmt.setNamespace(NAMESPACE);
stmt.setSetName(SET_NAME);
// expression filter is specifed in the operation policy
QueryPolicy policy = client.copyQueryPolicy();
policy.filterExp = Exp.build(
Exp.and(
Exp.lt(Exp.sinceUpdate(), Exp.val(2000)), // updated in last 2s
Exp.gt( // range of values in bin2 greater than 1000
Exp.sub(ListExp.getByRank(ListReturnType.VALUE, Exp.Type.INT, Exp.val(-1), Exp.listBin("bin2")), // largest
ListExp.getByRank(ListReturnType.VALUE, Exp.Type.INT, Exp.val(0), Exp.listBin("bin2"))), // smallest
Exp.val(1000))));
RecordSet rs = client.query(policy, stmt);
System.out.println("Results of filter expression query (all even records with bin2 max-min > 1000):");
while (rs.next()) {
Key key = rs.getKey();
Record record = rs.getRecord();
System.out.format("key=%s bins=%s\n", key.userKey, record.bins);
}
rs.close();

Output:

Test data populated.
Touched even numbered records.
Results of filter expression query (all even records with bin2 max-min > 1000):
key=id-4 bins={bin1=4, bin2=[1748, 569, 473]}
key=id-10 bins={bin1=10, bin2=[153, 1437, 1302]}
key=id-18 bins={bin1=18, bin2=[333, 1676, 55]}
key=id-16 bins={bin1=16, bin2=[592, 220, 1888]}

You may view the state of the database and ensure correctness of the output by running the following command in the terminal tab:

aql -c "select * from test.expressions"

AEL text equivalent

The Developer SDK (Java or Python) can author both filters above as AEL text instead of building an Exp tree. The touch filter (even-valued bin1) is:

$.bin1 % 2 == 0

The query filter (updated in the last 2 seconds, with bin2’s value range greater than 1000) uses the same [#0]/[#-1] rank selectors as ListExp.getByRank — rank 0 is the smallest value and rank -1 is the largest:

$.timeSinceLastUpdate() < 2000 and ($.bin2.[#-1] - $.bin2.[#0]) > 1000

For example, the query filter with .where():

DataSet records = DataSet.of(NAMESPACE, SET_NAME);
RecordStream stream = session.query(records)
.where("$.timeSinceLastUpdate() < 2000 and ($.bin2.[#-1] - $.bin2.[#0]) > 1000")
.execute();

Next

Continue to Operation expressions.