Search code examples
luaaerospike

Getting a list of values using lua and aerospike aql


I have the following set in aerospike:

INSERT INTO test.set (PK,DAY_OF_MONTH,YEAR,value) VALUES (1,2,2017,10)
INSERT INTO test.set (PK,DAY_OF_MONTH,YEAR,value) VALUES (2,2,2017,11)
INSERT INTO test.set (PK,DAY_OF_MONTH,YEAR,value) VALUES (3,3,2017,12)
INSERT INTO test.set (PK,DAY_OF_MONTH,YEAR,value) VALUES (4,3,2017,13)

I'm new in aerospike and for the moment I just know how to retrieve a single value in LUA, but I would like to know how to retrieve and make groups of values.

For instance, I would like to know how could I return a result like the following in aql:

    AGGREGATE test.someFunction() ON test.set

    +------+--------------+------+
    | YEAR | DAY_OF_MONTH | SUMA |
    +------+--------------+------+
    | 2017 | 2            | 21   | 
    | 2017 | 3            | 25   |
    +------+--------------+------+

Solution

  • If you're doing a mapper-only stream UDF you can return multiple lines, but you wanted to group the counts by day, so that will end up being a single result.

    Note that the return value can only be a supported data type - string, blob, integer, double, list, map (currently). You can't return a record, and it won't show up in AQL exactly as you suggested. Also understand that AQL is a tool for management and data browsing. It's not a client you should build code around. That's what the various language clients are for (Java, C#, Go, Node.js, Python, etc).

    Here's an example of how you'd do what you asked:

    local function reducer(map1, map2)
      return map.merge(map1, map2, function (id1,id2)
        return map.merge(id1, id2, function (val1,val2)
          return (val1 or 0) + (val2 or 0)
        end)
      end)
    end
    
    local function mapper(rec)
      return map{year=rec.YEAR, day=rec.DAY_OF_MONTH, val=rec.value}
    end
    
    local function sum_day(group, rec)
      local year = tostring(rec['year'])
      local day = tostring(rec['day'])
      if not group[year] then
        group[year] = map()
      end
      group[year][day] = (group[year][day] or 0) + rec['val']
      return group
    end
    
    local function check_rec(rec)
      if rec['YEAR'] and rec['DAY_OF_MONTH'] and
         rec['value'] and
         type(rec['value']) == 'number' then
        return true
      else
        return false
      end
    end
    
    function group_by_day(stream)
      return stream : filter(check_rec) :  map(mapper) : aggregate(map(), sum_day) : reduce(reducer)
    end
    

    Now from AQL:

    aql> aggregate aggr.group_by_day() on test.set
    +-----------------------------------+
    | group_by_day                      |
    +-----------------------------------+
    | MAP('{"2017":{"3":25, "2":21}}')  |
    +-----------------------------------+