Secondary index queries
Use the Aerospike C client to create and delete c indexes from the Aerospike database.
To continue, the client must have an established the cluster connection.
These examples are excerpts from examples/query_examples
in the Aerospike C client package.
Creating a Secondary Index
Secondary indexes can only be created once on the server as a combination of namespace, set, and bin name with either integer or string data types. For example, if you define a secondary index to index bin x that contains integer values, then only records containing bins named x with integer values are indexed. Other records with a bin named x that contain non-integer values are not indexed.
When an index management call is made to any node in the Aerospike Server cluster, the information automatically propagates to the remaining nodes.
Secondary index creation and removal are expensive operations, and should be performed as administrative tasks, and not as runtime tasks of an application. Aerospike provides a number of tools such as aql
to create, remove, manage, and monitor secondary indexes. The APIs here are provided to enable the building of these and other tools.
Use these operations to create secondary indexes, and specify the namespace, set, bin, and a secondary index name to uniquely identify it to the namespace:
aerospike_index_integer_create()
— Create an index on bins with integer values.aerospike_index_string_create()
— Create an index on bins with string values.
To create an integer index on the binX bin, for records in namespace test within set demoset with the secondary index name idx_binX:
as_error err;
if (aerospike_index_integer_create(&as, &err, NULL, "test", "demoset", "binX", "idx_binX") != AEROSPIKE_OK) { LOG("aerospike_index_integer_create() returned %d - %s", err.code, err.message); return false;}
Removing a Secondary Index
Remove secondary indexes using aerospike_index_remove()
, which takes the namespace and secondary index name.
as_error err;
aerospike_index_remove(&as, &err, NULL, "test", "idx_binX");
A query can:
- Make a callback that returns each record satisfying the query.
- Make a callback that returns the result of applying a Stream UDF on the set of records resulting from query.
See Aggregate for information on Stream UDFs.
These examples are excerpts from examples/query_examples/simple in the Aerospike C client package.
See Manage Indexes for information on secondary indexes.
To continue, the client must have an established the cluster connection.
Defining the Query
To initialize and build a query object to find records in bin test-bin, in the namespace test within set demoset that contain the integer value 7:
as_query query;as_query_init(&query, "test", "demoset");
as_query_where_inita(&query, 1);as_query_where(&query, "test-bin", integer_equals(7));
The equivalent SQL clause is: select * from test.demoset where test-bin equal 7
.
Invoking the Query
To execute the query, invoke aerospike_query_foreach()
:
if (aerospike_query_foreach(&as, &err, NULL, &query, query_cb, NULL) != AEROSPIKE_OK) { LOG("aerospike_query_foreach() returned %d - %s", err.code, err.message); as_query_destroy(&query); cleanup(&as); exit(-1);}
aerospike_query_foreach()
initiates one query for each node in the cluster. The Aerospike C client, internally has five NUM_QUERY_THREADS
query worker threads processing all query jobs for all nodes.
- If no secondary index was created on the specified query object, an
AEROSPIKE_ERR_INDEX_NOT_FOUND
error returns. - If an index creation was initiated but did not complete and then a query executes, an
AEROSPIKE_ERR_INDEX_NOT_READABLE
error returns.
Processing Results
aerospike_query_foreach()
takes query_cb
as a parameter of type:
typedef bool (*aerospike_query_foreach_callback)(const as_val *value, void *udata);
aerospike_query_foreach()
is called for each record that returns from any node in no particular order.
Because value
is a const as_val *
, the callback is not responsible for destroying value
, and value
is only available within the scope of the callback. The callback should not send value
outside the scope of the callback.
The callback is called with a NULL value
when there are no more results.
When value
is expected to be a record, cast the value into a record using as_record_fromval()
:
- If
value
is a record, then the function returns the record. - If
value
is not a record, then NULL returns.
You can also use as_val_type()
to check the value
data type.
bool callback(const as_val *value, void *udata) { if (value == NULL) { // query is complete return true; }
as_record *rec = as_record_fromval(value);
if (rec != NULL) { // process record }
return true;}
To pass a global
object each time during the callback, place a userdata
parameter in as_query_foreach()
.
Cleaning Up Resources
On query completion, use as_query_destroy()
to safely destroy the query
object and its member objects.
The example does not use an explicit as_query_destroy()
, but uses the stack-allocated as_query
object and as_query_where_inita()
, which avoids internal heap usage.