有各种形式来处理次索引查询结果。一个常用的形式就是聚合,就是在整个查询结果集上应用一个函数。
许多开发人员都熟知如何在数据库中使用SQL定义聚合查询。
例如,下面是一条从数据库中统计记录行数的SQL语句:
SELECT count(*) FROM test.demo WHERE d = 50
这条语句统计"test.demo"表中列"d"的值等于50的记录个数。
在Aerospike中,通过使用查询与用户定义函数来完成这个任务。
请先阅读:
使用Aerospike C客户端API实现SQL语句相同的功能,可构建如下查询:
as_query query; as_query_init(&query, "test", "demoset"); as_query_where_inita(&query, 1); as_query_where(&query, "d", integer_equals(50)); as_query_apply(&query, "mymodule", "mycount", NULL);
上面的查询对象,被查找数据所在的namespace名称为“test”、set名称为“demoset”,在其中查找bin名是"d"且整型值等于50的记录。一个名字叫做”mycount()“的streamUDF将应用在查询结果集上,此streamUDF可在模块mymodule中找到。
注意:不带“where"语句的查询会导致全库扫描。
Stream UDF函数mycount()定义于模块mymodule,可以处理数据流。UDF mycont()定义是:
local function one(rec) return 1 end local function add(a, b) return a + b end function mycount(stream) return stream : map(one) : reduce(add); end
函数mycount()是个Stream UDF,应用于流。在此案例中是查询结果流。我们在流上增加要在查询结果上执行的操作。在流上执行的操作是:
map
— 从流中将一个值映射到另一个值。在这个示例中,映射被定义成函数one(),映射记录到数值1。reduce
— 从流中将多个值归纳成一个值。在这个示例中,归纳是将流中的两个值相加,.这些值就是来自映射函数的一堆数值1。 最终结果是一个包含单个值的流:count,或更技术化地讲,是结果集中每条记录对应的”1“的合计。
在一个查询能使用streamUDF之前,UDF函数必须注册到Aerospike服务器。
as_error err; // Register the UDF file in the database cluster. if (aerospike_udf_put(&as, &err, NULL, "mymodule", AS_UDF_TYPE_LUA, &udf_content) != AEROSPIKE_OK) { LOG("aerospike_udf_put() returned %d - %s", err.code, err.message); }
使用aerospike_query_foreach()执行查询:
if (aerospike_query_foreach(&as, &err, NULL, &query, each_value, NULL) != AEROSPIKE_OK) { fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line); }
这将在数据库中执行此查询。
对查询返回的值逐个调用函数each_value()。函数的实现可能类似于:
bool each_value(const as_val *val, void *udata) { if (val == NULL) { // query is complete return true; } as_integer *ival = as_integer_fromval(val); if (ival == NULL) { // abort the query return false; } // process the value return true; }
上面的示例中,返回1个整数,表明满足查询条件的记录计数。??????原文如此。
若想在每次回调时传递一个全局对象出来,请在调用aerospike_query_foreach()时提供一个userdata类型的参数。
一旦查询结束,查询对象与其成员对象可使用as_query_destroy()函数安全地释放。注意在我们的示例中,可以不用显式调用as_query_destroy(),因为是从栈上分配的as_query对象,并且使用了as_query_where_inita(),来避免内部使用堆。