Tutorial for Expression Indexes
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
This tutorial introduces expression indexes in Aerospike Database. This tutorial assumes you are familiar with secondary indexes and expressions in Aerospike Database.
Overview
Expression indexes build sparse secondary indexes over computed values defined by an Aerospike expression. Instead of indexing every record or persisting derived bins, the index evaluates your expression and includes only the records that match.
In this tutorial, you will:
- Create your first expression index
- Run your first query against it
Why it matters
- Simpler application code: push filter logic into the index; no extra bins or duplicated client filters.
- Reduced memory footprint: indexes include only relevant records.
- Total cost of ownership: reduced RAM and compute requirements lower infrastructure spend.
- Faster queries: less to scan means lower latency.
When to use expression indexes
Use them when you would otherwise:
- Persist a derived value solely to make it indexable.
- Index every record even though only a subset are needed for business logic.
- Re-implement the same filter logic across multiple clients or languages.
Get started
Prerequisites
- A running instance of Aerospike Database 8.1.0 or later. The Java SDK and Python SDK examples need Database 8.2.0 or later, which compiles their AEL.
- Updated Client (minimum versions):
Verify your server version using asinfo:
# Verify you’re running Aerospike 8.1.0+asinfo -v buildCreate expression, index, and query
-
Create the expression.
The following example creates the “adult users in target countries” expression. For this example, let’s assume an adult is someone 18 or older, and our target countries are Australia, Canada and Botswana.
For this tutorial, we’ll generate the Base64 representation of the expression in the client and then use the
asadmcommand-line tool to create the index. This approach separates application logic (defining the filter) from database administration (creating the index).import com.aerospike.client.sdk.exp.Expression;// Build an expression that indexes age only for adults in AU/CA/BW that are 18 or older// In AEL: when the customer is 18 or older and lives in a target country, their age;// otherwise `unknown`, which leaves the record out of the indexString ael = "when ($.age >= 18 and ($.country == 'Australia'"+ " or $.country == 'Canada' or $.country == 'Botswana')"+ " => $.age, default => unknown)";// Get the base64 for asadm's `exp_base64`; the server compiles the AEL when it creates the indexString b64 = Expression.fromServerCompiledFilter(ael).getBase64();System.out.println(b64);// Prints: ksyA2YJ3aGVuICgkLmFnZSA+PSAxOCBhbmQgKCQuY291bnRyeSA9PSAnQXVzdHJhbGlhJyBvciAkLmNvdW50cnkgPT0gJ0NhbmFkYScgb3IgJC5jb3VudHJ5ID09ICdCb3Rzd2FuYScpID0+ICQuYWdlLCBkZWZhdWx0ID0+IHVua25vd24p// The SDK can also create the index itself, from the AEL:// session.createIndex(DataSet.of("test", "cust_data"), "cust_index",// IndexType.INTEGER, IndexCollectionType.DEFAULT, ael)// .waitTillComplete();from aerospike_sdk.exp import Exp# Build an expression that indexes age only for adults in AU/CA/BW that are 18 or older# In AEL: when the customer is 18 or older and lives in a target country, their age;# otherwise `unknown`, which leaves the record out of the indexael = ("when ($.age >= 18 and ($.country == 'Australia'"" or $.country == 'Canada' or $.country == 'Botswana')"" => $.age, default => unknown)")# Get the base64 for asadm's `exp_base64`; the server compiles the AEL when it creates the indexb64 = Exp.from_server_compiled_ael(ael).base64()print(b64)# Prints: ksyAxIJ3aGVuICgkLmFnZSA+PSAxOCBhbmQgKCQuY291bnRyeSA9PSAnQXVzdHJhbGlhJyBvciAkLmNvdW50cnkgPT0gJ0NhbmFkYScgb3IgJC5jb3VudHJ5ID09ICdCb3Rzd2FuYScpID0+ICQuYWdlLCBkZWZhdWx0ID0+IHVua25vd24p# The SDK can also create the index itself, from the AEL:# (session.index("test", "cust_data").on_expression(ael).named("cust_index")# .integer().create().wait_till_complete_blocking())use aerospike::expressions::{and, cond, eq, ge, int_bin, int_val, or, string_bin, string_val, unknown};// Build an expression that indexes age only for adults in AU/CA/BW that are 18 or olderlet filter_exp = cond(vec![and(vec![// Is the age 18 or older?ge(int_bin("age".to_string()), int_val(18)),// Do they live in a target country?or(vec![eq(string_bin("country".to_string()), string_val("Australia".to_string())),eq(string_bin("country".to_string()), string_val("Canada".to_string())),eq(string_bin("country".to_string()), string_val("Botswana".to_string())),]),]),// If true, return the age of the customer to be indexedint_bin("age".to_string()),// Otherwise return "unknown" to exclude the record from the indexunknown(),]);println!("{}", filter_exp.base64()?);// Prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA// Build an expression that indexes age only for adults in AU/CA/BWExpression filterExp = Exp.Build(// The `Cond` expression is the top-level IF/THEN/ELSEExp.Cond(// IF block: Defines the conditions for the indexExp.And(// Condition 1: Is the age 18 or older?Exp.GE(Exp.IntBin("age"), Exp.Val(18)),// Condition 2: Do they live in a target country?Exp.Or(Exp.EQ(Exp.StringBin("country"), Exp.Val("Australia")),Exp.EQ(Exp.StringBin("country"), Exp.Val("Canada")),Exp.EQ(Exp.StringBin("country"), Exp.Val("Botswana")))),// If true, return the integer value from the 'age' bin.// This value is what gets indexed.Exp.IntBin("age"),// ELSE If false, return "unknown".// This excludes the record from the index.Exp.Unknown()));// Print the Base64-encoded expression for use with asadmstring exprBase64 = filterExp.GetBase64();Console.WriteLine("Expression Base64:");Console.WriteLine(exprBase64);// Prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA// go get github.com/aerospike/aerospike-client-go/v8import ("fmt"as "github.com/aerospike/aerospike-client-go/v8")// Build an expression that indexes age only for adults in AU/CA/BW that are 18 or olderfilterExp := as.ExpCond(as.ExpAnd(// Is the age 18 or older?as.ExpGreaterEq(as.ExpIntBin("age"), as.ExpIntVal(18)),// Do they live in a target country?as.ExpOr(as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Australia")),as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Canada")),as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Botswana")),),),// If true, return the age of the customer to be indexedas.ExpIntBin("age"),// Otherwise return "unknown" to exclude the record from the indexas.ExpUnknown(),)b64, err := filterExp.Base64()if err != nil {panic(err)}fmt.Println(b64)// Prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA// npm install aerospikeimport Aerospike from "aerospike";const exp = Aerospike.exp;const filterExp = exp.cond(exp.and(exp.ge(exp.binInt("age"), exp.int(18)),exp.or(exp.eq(exp.binStr("country"), exp.str("Australia")),exp.eq(exp.binStr("country"), exp.str("Canada")),exp.eq(exp.binStr("country"), exp.str("Botswana")),),),exp.binInt("age"),exp.unknown(),);// Get Base64 for use with asadm `exp_base64` (requires a connected client)const client = await Aerospike.connect({ hosts: "127.0.0.1:3000" });console.log(client.expressionToBase64(filterExp));// Prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEAawait client.close();as_exp_build(filter_exp,as_exp_cond(as_exp_and(as_exp_cmp_ge(as_exp_bin_int("age"),as_exp_int(18)),as_exp_or(as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Australia")),as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Canada")),as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Botswana")))),// If true, return the value in the age binas_exp_bin_int("age"),// return unknown to exclude value from indexas_exp_unknown()));char* b64 = as_exp_to_base64(filter_exp);printf("Expression base64 = %s\n", b64);// Prints:// Expression base64 = lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEAas_exp_destroy_base64(b64);as_exp_destroy(filter_exp);// Build an expression that indexes age only for adults in AU/CA/BW that are 18 or olderExpression filterExp = Exp.build(Exp.cond(Exp.and(Exp.ge(// Is the age 18 or older?Exp.intBin("age"),Exp.val(18)),Exp.or( // Do they live in a target country?Exp.eq(Exp.stringBin("country"), Exp.val("Australia")),Exp.eq(Exp.stringBin("country"), Exp.val("Canada")),Exp.eq(Exp.stringBin("country"), Exp.val("Botswana")))),Exp.intBin("age"), // If true, return the age of the customer to be indexedExp.unknown() // returns "unknown" to exclude the record from the index));System.out.println(filterExp.getBase64());// Prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA# pip install aerospikeimport aerospikefrom aerospike_helpers import expressions as exptarget_countries = ["Australia", "Canada", "Botswana"]# Build the "OR" condition for the country checkcountry_is_target = exp.Or(*[exp.Eq(exp.StrBin("country"), c) for c in target_countries])# Compile the final expressionfilter_exp = exp.Cond(# IF block: Both conditions must be trueexp.And(exp.GE(exp.IntBin("age"), 18),country_is_target),# Return the value of the 'age' bin for indexingexp.IntBin("age"),# ELSE Return "unknown" to exclude the record from the indexexp.Unknown()).compile()# Get Base64 for use with asadm `exp_base64`client = aerospike.client({"hosts": [("127.0.0.1", 3000)]}).connect()expr_b64 = client.get_expression_base64(filter_exp)print(expr_b64)# prints: lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEAclient.close()The client libraries print the same base64 string. The Java SDK and Python SDK print their AEL’s instead, which the server compiles to the same expression when it creates the index.
-
Create the expression index.
Use
asadmorsindex-createthroughasinfoto create an integer secondary index on the expression. Both accept theintegerkey type in Database 8.2.0 and later. Useasadmfor interactive work andasinfofor automation. Copy the full Base64 string from the previous step’s output and use it in one of the following commands.asadm asadm -e "enable; manage sindex create integer cust_index ns test set cust_data exp_base64 lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA"asinfo asinfo -v 'sindex-create:namespace=test;set=cust_data;indexname=cust_index;indextype=default;exp=lHuTEJMEk1ECo2FnZRKUEZMBk1EDp2NvdW50cnmqA0F1c3RyYWxpYZMBk1EDp2NvdW50cnmnA0NhbmFkYZMBk1EDp2NvdW50cnmpA0JvdHN3YW5hk1ECo2FnZZEA;type=integer' -
Insert some test data.
DataSet custData = DataSet.of("test", "cust_data");// Insert sample customers to demonstrate which records get indexedsession.upsert(custData).bins("name", "age", "country").id(1).values("Tim", 31, "Australia").id(2).values("Bob", 47, "Canada").id(3).values("Jo", 15, "USA") // not indexed.id(4).values("Steven", 23, "Botswana").id(5).values("Susan", 32, "Canada").id(6).values("Jess", 17, "Botswana") // not indexed.id(7).values("Sam", 18, "USA") // not indexed.id(8).values("Alex", 47, "Canada").id(9).values("Pam", 56, "Australia").id(10).values("Vivek", 12, "India") // not indexed.id(11).values("Kiril", 22, "Sweden") // not indexed.id(12).values("Bill", 23, "UK") // not indexed.execute();from aerospike_sdk import DataSetcust_data = DataSet.of("test", "cust_data")# Insert sample customers to demonstrate which records get indexed(session.upsert(cust_data).bins("name", "age", "country").row(1, "Tim", 31, "Australia").row(2, "Bob", 47, "Canada").row(3, "Jo", 15, "USA") # not indexed.row(4, "Steven", 23, "Botswana").row(5, "Susan", 32, "Canada").row(6, "Jess", 17, "Botswana") # not indexed.row(7, "Sam", 18, "USA") # not indexed.row(8, "Alex", 47, "Canada").row(9, "Pam", 56, "Australia").row(10, "Vivek", 12, "India") # not indexed.row(11, "Kiril", 22, "Sweden") # not indexed.row(12, "Bill", 23, "UK") # not indexed.execute())use aerospike::{as_bin, as_key, WritePolicy};// Insert sample customers to demonstrate which records get indexedlet customers = [(1, "Tim", 31, "Australia"),(2, "Bob", 47, "Canada"),(3, "Jo", 15, "USA"), // not indexed(4, "Steven", 23, "Botswana"),(5, "Susan", 32, "Canada"),(6, "Jess", 17, "Botswana"), // not indexed(7, "Sam", 18, "USA"), // not indexed(8, "Alex", 47, "Canada"),(9, "Pam", 56, "Australia"),(10, "Vivek", 12, "India"), // not indexed(11, "Kiril", 22, "Sweden"), // not indexed(12, "Bill", 23, "UK"), // not indexed];for (id, name, age, country) in customers {let key = as_key!("test", "cust_data", id);let bins = [as_bin!("name", name), as_bin!("age", age), as_bin!("country", country)];client.put(&WritePolicy::default(), &key, &bins).await?;}// Define the namespace and set for the recordsconst string NAMESPACE = "test";const string SET = "cust_data";// A helper method to insert a customer recordpublic void Insert(int key, string name, int age, string country){client.Put(null,new Key(NAMESPACE, SET, key),new Bin("name", name),new Bin("age", age),new Bin("country", country));}// Insert sample customers to demonstrate which records get indexedpublic void InsertData(){Insert(1, "Tim", 31, "Australia");Insert(2, "Bob", 47, "Canada");Insert(3, "Jo", 15, "USA"); // not indexedInsert(4, "Steven", 23, "Botswana");Insert(5, "Susan", 32, "Canada");Insert(6, "Jess", 17, "Botswana"); // not indexedInsert(7, "Sam", 18, "USA"); // not indexedInsert(8, "Alex", 47, "Canada");Insert(9, "Pam", 56, "Australia");Insert(10, "Vivek", 12, "India"); // not indexedInsert(11, "Kiril", 22, "Sweden"); // not indexedInsert(12, "Bill", 23, "UK"); // not indexed}import ("fmt"as "github.com/aerospike/aerospike-client-go/v8")// Define the namespace and set for the recordsconst (NAMESPACE = "test"SET = "cust_data")// A helper to insert a customer recordfunc insert(client *as.Client, id int, name string, age int, country string) {key, _ := as.NewKey(NAMESPACE, SET, id)if err := client.PutBins(nil, key,as.NewBin("name", name),as.NewBin("age", age),as.NewBin("country", country)); err != nil {panic(err)}}// Insert sample customers to demonstrate which records get indexedfunc doInsertData(client *as.Client) {insert(client, 1, "Tim", 31, "Australia")insert(client, 2, "Bob", 47, "Canada")insert(client, 3, "Jo", 15, "USA") // not indexedinsert(client, 4, "Steven", 23, "Botswana")insert(client, 5, "Susan", 32, "Canada")insert(client, 6, "Jess", 17, "Botswana") // not indexedinsert(client, 7, "Sam", 18, "USA") // not indexedinsert(client, 8, "Alex", 47, "Canada")insert(client, 9, "Pam", 56, "Australia")insert(client, 10, "Vivek", 12, "India") // not indexedinsert(client, 11, "Kiril", 22, "Sweden") // not indexedinsert(client, 12, "Bill", 23, "UK") // not indexed}// Connect and load the dataclient, err := as.NewClient("127.0.0.1", 3000)if err != nil {panic(err)}defer client.Close()doInsertData(client)fmt.Println("Insert data: done")import Aerospike from "aerospike";const key = Aerospike.Key;// Define the namespace and set for the recordsconst NAMESPACE = "test";const SET = "cust_data";const client = await Aerospike.connect({hosts: "127.0.0.1:3000",});// Sample customer dataconst customers = [{ key: 1, name: "Tim", age: 31, country: "Australia" },{ key: 2, name: "Bob", age: 47, country: "Canada" },{ key: 3, name: "Jo", age: 15, country: "USA" }, // not indexed{ key: 4, name: "Steven", age: 23, country: "Botswana" },{ key: 5, name: "Susan", age: 32, country: "Canada" },{ key: 6, name: "Jess", age: 17, country: "Botswana" }, // not indexed{ key: 7, name: "Sam", age: 18, country: "USA" }, // not indexed{ key: 8, name: "Alex", age: 47, country: "Canada" },{ key: 9, name: "Pam", age: 56, country: "Australia" },{ key: 10, name: "Vivek", age: 12, country: "India" }, // not indexed{ key: 11, name: "Kiril", age: 22, country: "Sweden" }, // not indexed{ key: 12, name: "Bill", age: 23, country: "UK" }, // not indexed];// Insert sample customers to demonstrate which records get indexedconst promises = customers.map((customer) => {return client.put(new key(NAMESPACE, SET, customer.key), {name: customer.name,age: customer.age,country: customer.country,});});await Promise.all(promises);await client.close();// Insert a customer recordstatic voidinsert(aerospike* as, int key, const char* name, int age, const char* country){as_error err;as_key int_key;as_key_init_int64(&int_key, "test", "cust_data", key);as_record rec;as_record_inita(&rec, 3);as_record_set_str(&rec, "name", name);as_record_set_int64(&rec, "age", age);as_record_set_str(&rec, "country", country);if (aerospike_key_put(as, &err, NULL, &int_key, &rec) != AEROSPIKE_OK) {printf("aerospike_key_put() returned %d - %s\n", err.code, err.message);}as_record_destroy(&rec);}// Insert sample customers to demonstrate which records get indexedstatic voiddo_insert_data(aerospike* as){insert(as, 1, "Tim", 31, "Australia");insert(as, 2, "Bob", 47, "Canada");insert(as, 3, "Jo", 15, "USA"); // not indexedinsert(as, 4, "Steven", 23, "Botswana");insert(as, 5, "Susan", 32, "Canada");insert(as, 6, "Jess", 17, "Botswana"); // not indexedinsert(as, 7, "Sam", 18, "USA"); // not indexedinsert(as, 8, "Alex", 47, "Canada");insert(as, 9, "Pam", 56, "Australia");insert(as, 10, "Vivek", 12, "India"); // not indexedinsert(as, 11, "Kiril", 22, "Sweden"); // not indexedinsert(as, 12, "Bill", 23, "UK"); // not indexed}// Define the namespace and set for the recordsfinal String NAMESPACE = "test";final String SET = "cust_data";// A helper method to insert a customer recordpublic void insert(int key, String name, int age, String country) {client.put(null,new Key(NAMESPACE, SET, key),new Bin("name", name),new Bin("age", age),new Bin("country", country));}// Insert sample customers to demonstrate which records get indexedpublic void insertData() {insert(1, "Tim", 31, "Australia");insert(2, "Bob", 47, "Canada");insert(3, "Jo", 15, "USA"); // not indexedinsert(4, "Steven", 23, "Botswana");insert(5, "Susan", 32, "Canada");insert(6, "Jess", 17, "Botswana"); // not indexedinsert(7, "Sam", 18, "USA"); // not indexedinsert(8, "Alex", 47, "Canada");insert(9, "Pam", 56, "Australia");insert(10, "Vivek", 12, "India"); // not indexedinsert(11, "Kiril", 22, "Sweden"); // not indexedinsert(12, "Bill", 23, "UK"); // not indexed}import aerospike# Sample customer datacustomers = [(1, "Tim", 31, "Australia"),(2, "Bob", 47, "Canada"),(3, "Jo", 15, "USA"), # not indexed(4, "Steven", 23, "Botswana"),(5, "Susan", 32, "Canada"),(6, "Jess", 17, "Botswana"), # not indexed(7, "Sam", 18, "USA"), # not indexed(8, "Alex", 47, "Canada"),(9, "Pam", 56, "Australia"),(10, "Vivek", 12, "India"), # not indexed(11, "Kiril", 22, "Sweden"), # not indexed(12, "Bill", 23, "UK"), # not indexed]# Client configuration (replace with your actual configuration)config = {"hosts": [("127.0.0.1", 3000)]}client = aerospike.client(config).connect()# Insert sample customers to demonstrate which records get indexedfor key, name, age, country in customers:client.put(("test", "cust_data", key),{"name": name,"age": age,"country": country})client.close() -
Validate index entries.
A single-node cluster shows 6 entries in the expression index (records 1, 2, 4, 5, 8, 9).
sindex-statreports each node’s own entries, replicas included, so on a larger cluster the nodes’ counts add up to 6 times the replication factor.Terminal window # Confirm only matching records (6) were indexedasinfo -v 'sindex-stat:namespace=test;indexname=cust_index' -lentries=6... -
Query your Expression Index.
Run a query to filter for ages 5 and above. Notice the results still only shows ages 18 and above.
The Java SDK and Python SDK don’t name the index. Their
whererepeats the index’s expression, and the query optimizer serves the query from the index. Write the expression exactly as the index was defined:$.country in [...]builds a different expression from theorthe index uses, and the query fails.// Query via the expression index to fetch records for customers that are 5 and older// A `where` on the index's expression is served by the index; `forIndex` names it.String ael = "when ($.age >= 18 and ($.country == 'Australia'"+ " or $.country == 'Canada' or $.country == 'Botswana')"+ " => $.age, default => unknown)";try (RecordStream rs = session.query(DataSet.of("test", "cust_data")).where(ael + " >= 5").withHint(hint -> hint.forIndex("cust_index")).execute()) {rs.forEach(result -> System.out.println(result.recordOrThrow().bins));}from aerospike_sdk import DataSet, QueryHint# Query via the expression index to fetch records for customers that are 5 and older# A `where` on the index's expression is served by the index; the hint names it.ael = ("when ($.age >= 18 and ($.country == 'Australia'"" or $.country == 'Canada' or $.country == 'Botswana')"" => $.age, default => unknown)")stream = (session.query(DataSet.of("test", "cust_data")).where(ael + " >= 5").with_hint(QueryHint(index_name="cust_index")).execute())for row in stream:print(row.record_or_raise().bins)stream.close()use aerospike::query::{Filter, PartitionFilter};use aerospike::{Bins, QueryPolicy, Statement};use futures::StreamExt;// Query via the expression index to fetch records for customers that are 5 and olderlet mut stmt = Statement::new("test", "cust_data", Bins::All);// Use `range_by_index` to query the expression indexstmt.add_filter(Filter::range_by_index("cust_index", 5, i64::MAX));let rs = client.query(&QueryPolicy::default(), PartitionFilter::all(), stmt).await?;let mut stream = rs.into_stream();while let Some(record) = stream.next().await {println!("{:?}", record?.bins);}// Query via the expression index to fetch records for customers that are 5 and olderStatement stmt = new();stmt.SetNamespace("test");stmt.SetSetName("cust_data");// Use `RangeByIndex` to query the expression indexstmt.SetFilter(Filter.RangeByIndex("cust_index", 5, int.MaxValue));// Execute the query and print the resultsusing RecordSet recordSet = client.Query(null, stmt);while (recordSet.Next()){Console.WriteLine(recordSet.Record);}import ("fmt""math"as "github.com/aerospike/aerospike-client-go/v8")// Query via the expression index to fetch records for customers that are 5 and olderstmt := as.NewStatement("test", "cust_data")// Use `NewRangeWithIndexNameFilter` to query the expression indexstmt.SetFilter(as.NewRangeWithIndexNameFilter("cust_index", 5, math.MaxInt64))rs, err := client.Query(nil, stmt)if err != nil {panic(err)}for rec := range rs.Results() {if rec.Err != nil {fmt.Printf("error: %v\n", rec.Err)continue}fmt.Println(rec.Record.Bins)}import Aerospike from "aerospike";const filter = Aerospike.filter;// Define the namespace and set for the recordsconst NAMESPACE = "test";const SET = "cust_data";const client = await Aerospike.connect({hosts: "127.0.0.1:3000",});// Create a query objectconst query = client.query(NAMESPACE, SET);// Query via the expression index to fetch records for customers that are 5 and olderquery.whereWithIndexName(filter.range(null, 5, Number.MAX_SAFE_INTEGER),"cust_index",);// Execute the query and print the resultsconst results = await query.results();for (const result of results) {console.log(result.bins);}await client.close();static bool query_cb(const as_val*, void*);// Query via the expression index to fetch records for customers that are 5 and olderstatic voiddo_query_by_age_at_least_5(aerospike* as){as_query query;as_query_init(&query, "test", "cust_data");as_query_where_init(&query, 1);as_query_where_with_index_name(&query, "cust_index",as_integer_range(5, INT_MAX));as_error err;if (aerospike_query_foreach(as, &err, NULL, &query, query_cb, NULL) !=AEROSPIKE_OK) {printf("aerospike_query_foreach() returned %d - %s\n", err.code, err.message);}as_query_destroy(&query);}static boolquery_cb(const as_val* val, void* udata){if (! val) {// Query is complete.return false;}// The client calls this from several threads, so print each record in one callas_record* rec = as_record_fromval(val);printf("name=%s age=%" PRId64 " country=%s\n",as_record_get_str(rec, "name"),as_record_get_int64(rec, "age", 0),as_record_get_str(rec, "country"));return true;}// Query via the expression index to fetch records for customers that are 5 and olderStatement stmt = new Statement();stmt.setNamespace("test");stmt.setSetName("cust_data");// Use `rangeByIndex` to query the expression indexstmt.setFilter(Filter.rangeByIndex("cust_index", 5, Integer.MAX_VALUE));// Execute the query and print the resultstry (RecordSet recordSet = client.query(null, stmt)) {while (recordSet.next()) {System.out.println(recordSet.getRecord());}}import sysimport aerospikefrom aerospike import predicates as p# Connect to the databaseconfig = {"hosts": [("127.0.0.1", 3000)]}client = aerospike.client(config).connect()# Query via the expression index to fetch records for customers that are 5 and olderq = client.query("test", "cust_data")# Set the query to use the expression index with a range filterq.where_with_index_name("cust_index",p.range(None, aerospike.INDEX_TYPE_DEFAULT, 5, sys.maxsize))# Define a function to handle each record returned by the querydef handle(record):key, meta, bins = recordprint(bins)# Execute the query and apply the handler to each recordq.foreach(handle)client.close()Since we stored age, you can filter for records above 25 by simply modifying the query:
// Query via the expression index to fetch records for customers that are 25 and older// A `where` on the index's expression is served by the index; `forIndex` names it.String ael = "when ($.age >= 18 and ($.country == 'Australia'"+ " or $.country == 'Canada' or $.country == 'Botswana')"+ " => $.age, default => unknown)";try (RecordStream rs = session.query(DataSet.of("test", "cust_data")).where(ael + " >= 25").withHint(hint -> hint.forIndex("cust_index")).execute()) {rs.forEach(result -> System.out.println(result.recordOrThrow().bins));}from aerospike_sdk import DataSet, QueryHint# Query via the expression index to fetch records for customers that are 25 and older# A `where` on the index's expression is served by the index; the hint names it.ael = ("when ($.age >= 18 and ($.country == 'Australia'"" or $.country == 'Canada' or $.country == 'Botswana')"" => $.age, default => unknown)")stream = (session.query(DataSet.of("test", "cust_data")).where(ael + " >= 25").with_hint(QueryHint(index_name="cust_index")).execute())for row in stream:print(row.record_or_raise().bins)stream.close()use aerospike::query::{Filter, PartitionFilter};use aerospike::{Bins, QueryPolicy, Statement};use futures::StreamExt;// Query via the expression index to fetch records for customers that are 25 and olderlet mut stmt = Statement::new("test", "cust_data", Bins::All);// Use `range_by_index` to query the expression indexstmt.add_filter(Filter::range_by_index("cust_index", 25, i64::MAX));let rs = client.query(&QueryPolicy::default(), PartitionFilter::all(), stmt).await?;let mut stream = rs.into_stream();while let Some(record) = stream.next().await {println!("{:?}", record?.bins);}// Query via the expression index to fetch records for customers that are 25 and olderStatement stmt = new();stmt.SetNamespace("test");stmt.SetSetName("cust_data");// Update the range to start at 25stmt.SetFilter(Filter.RangeByIndex("cust_index", 25, int.MaxValue));// Execute the query and print the resultsusing RecordSet recordSet = client.Query(null, stmt);while (recordSet.Next()){Console.WriteLine(recordSet.Record);}// Requires: import as "github.com/aerospike/aerospike-client-go/v8"// Query via the expression index to fetch records for customers that are 25 and olderstmt := as.NewStatement("test", "cust_data")// Update the range to start at 25stmt.SetFilter(as.NewRangeWithIndexNameFilter("cust_index", 25, math.MaxInt64))rs, err := client.Query(nil, stmt)if err != nil {panic(err)}for rec := range rs.Results() {if rec.Err != nil {fmt.Printf("error: %v\n", rec.Err)continue}fmt.Println(rec.Record.Bins)}import Aerospike from "aerospike";const filter = Aerospike.filter;// Define the namespace and set for the recordsconst NAMESPACE = "test";const SET = "cust_data";const client = await Aerospike.connect({hosts: "127.0.0.1:3000",});// Create a query objectconst query = client.query(NAMESPACE, SET);// Query via the expression index to fetch records for customers that are 25 and olderquery.whereWithIndexName(filter.range(null, 25, Number.MAX_SAFE_INTEGER),"cust_index",);// Execute the query and print the resultsconst results = await query.results();for (const result of results) {console.log(result.bins);}await client.close();// Query via the expression index to fetch records for customers that are 25 and olderstatic voiddo_query_by_age_at_least_25(aerospike* as){as_query query;as_query_init(&query, "test", "cust_data");as_query_where_init(&query, 1);as_query_where_with_index_name(&query, "cust_index",as_integer_range(25, INT_MAX));as_error err;if (aerospike_query_foreach(as, &err, NULL, &query, query_cb, NULL) !=AEROSPIKE_OK) {printf("aerospike_query_foreach() returned %d - %s\n", err.code, err.message);}as_query_destroy(&query);}// Query via the expression index to fetch records for customers that are 25 and olderStatement stmt = new Statement();stmt.setNamespace("test");stmt.setSetName("cust_data");// Update the range to start at 25stmt.setFilter(Filter.rangeByIndex("cust_index", 25, Integer.MAX_VALUE));try (RecordSet recordSet = client.query(null, stmt)) {while (recordSet.next()) {System.out.println(recordSet.getRecord());}}import sysimport aerospikefrom aerospike import predicates as p# Connect to the databaseconfig = {"hosts": [("127.0.0.1", 3000)]}client = aerospike.client(config).connect()# Query via the expression index to fetch records for customers that are 25 and olderq = client.query("test", "cust_data")# Create a query and apply the new rangeq.where_with_index_name("cust_index",p.range(None, aerospike.INDEX_TYPE_DEFAULT, 25, sys.maxsize))# Define a function to handle each record returned by the querydef handle(record):key, meta, bins = recordprint(bins)# Execute the query and apply the handler to each recordq.foreach(handle)client.close() -
That’s it. You’re done!