dmkach
April 23, 2021, 11:46am
1
Hi, I’m trying to pass bins to UDF function as a map from Java client and I expect it to be a lua table. However on the UDF side I’m getting userdata
type. I found similar issue on github but it’s for GO client:
opened 10:11PM - 22 May 15 UTC
closed 09:26AM - 11 Jun 15 UTC
Whenever I store maps/json using the Go client and try to access that bin using … UDF I keep getting the type as "userdata" instead of a table or a list.
Message: bad argument #1 to 'format' (string expected, got userdata)
```
package main
import (
"fmt"
as "github.com/aerospike/aerospike-client-go"
"log"
"strconv"
"time"
)
const udfFilter = `
function queryTest(s, rec)
local time = os.time()
local function map_value_merger(mapval1, mapval2)
return mapval1 + mapval2
end
local function reduce_results(a,b)
return map.merge(a,b,map_value_merger)
end
function apply_totalmap_cxt(mymap, rec)
local topics = rec["Data"]
if topics ~= nil then
for k in list.iterator(topics) do
warn(k)
if mymap[k] == nil then
mymap = 0
end
mymap[k] = mymap[k] + 1
end
end
return mymap
end
return s : aggregate(map(), apply_totalmap_cxt) : reduce(reduce_results)
end
`
func main() {
client, err := as.NewClient("127.0.0.1", 3000)
if err != nil {
log.Fatal(err)
}
key, _ := as.NewKey("test", "pets", "example_key")
topics := []map[interface{}]interface{}{}
topic1 := map[interface{}]interface{}{}
topic1["animal"] = "Dogs"
topic2 := map[interface{}]interface{}{}
topic2["animal"] = "Cats"
topics = append(topics, topic1)
topics = append(topics, topic2)
data := as.BinMap{
"CreatedAt": time.Now().Unix(),
"bin2": "An elephant is a mouse with an operating system",
"Data": topics,
}
client.Put(nil, key, data)
regTask, err := client.RegisterUDF(nil, []byte(udfFilter), "queryTest.lua", as.LUA)
if err != nil {
log.Fatal(err)
}
for {
if err := <-regTask.OnComplete(); err == nil {
break
} else {
log.Println(err)
}
}
stm := as.NewStatement("test", "pets")
stm.SetAggregateFunction("queryTest", "queryTest", nil, true)
recordset, err := client.Query(nil, stm)
if err != nil {
log.Fatal(err)
}
results := map[string]int{}
L:
for {
select {
case rec, _ := <-recordset.Records:
if rec == nil {
break L
}
if result, ok := rec.Bins["SUCCESS"].(map[interface{}]interface{}); ok {
for k, v := range result {
key := ""
if r, ok := k.(int); ok {
key = fmt.Sprintf("%d", r)
}
if r, ok := k.(string); ok {
key = r
}
if r, ok := v.(int); ok {
results[key] = results[key] + r
}
}
}
}
}
for k, v := range results {
fmt.Println(k + " :: " + strconv.Itoa(v))
}
}
```
Here is the client code example:
client.execute(writePolicy,
key,
config.udfConfig.packageName,
config.udfConfig.functionName,
Value.get(new java.util.HashMap[String, Object]()))
And here is UDF:
function example(rec, bins)
info("VALUE OF bins: %s", tostring(bins))
info("TYPE OF bins: %s", type(bins))
end
tostring
function on bins returns valid data. Something like {“foo”:62 61 72, “baz”:62 61 7A} but it has userdata
type and I can’t do anything with it.
Is there a way to fix this?
Thanks
dmkach
April 23, 2021, 12:02pm
2
I found a solution. It’s possible to work with this object using map functions like map.pairs() as described here: https://www.aerospike.com/docs/udf/api/map.html
system
Closed
July 16, 2021, 12:03pm
3
This topic was automatically closed 84 days after the last reply. New replies are no longer allowed.