lua5.3之前都会有这个问题。但是目前我们使用的go嵌入lua使用的解释器只有5.1所以这个只能靠自己转换解决。目前是用在go+lua同步es的工具上。
解决方式分这几个步骤:
1.go将传递给lua的14-20位的数字转换为字符串
2.lua调用go往es中塞数据时再次逆转为数字,便可以保证es中 本地数据库中都是数字了,而且不丢失精度。
比较简单。以下给部分代码demo
func paddingTable(l *lua.LState, table *lua.LTable, kv map[string]interface{}) {
//为保证lua5.1中雪花算法id不能直接使用 必须转为字符串
if b, err := json.Marshal(kv); err != nil {
panic(err)
} else {
reg := regexp.MustCompile(`(\d{14,20}),`)
l := len(reg.FindAllString(string(b), -1)) //正则匹配16-20位的数字,如果找到了就开始正则替换并解析
if l != 0 {
str := reg.ReplaceAllString(string(b), `"${1}",`) //执行替换{}对象
reg := regexp.MustCompile(`(\d{14,20})}`)
str = reg.ReplaceAllString(str, `"${1}"}`) //执行替换}
reg = regexp.MustCompile(`(\d{14,20})]`)
str = reg.ReplaceAllString(str, `"${1}"]`) //执行替换 []数组
var jdata map[string]interface{}
err := json.Unmarshal([]byte(str), &jdata)
if err != nil {
println("\njson解析失败", str)
panic(err)
}
kv = jdata
}
}
for k, v := range kv {
switch v.(type) {
case float64:
ft := v.(float64)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case float32:
ft := v.(float32)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case int:
ft := v.(int)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case uint:
ft := v.(uint)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case int8:
ft := v.(int8)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case uint8:
ft := v.(uint8)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case int16:
ft := v.(int16)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case uint16:
ft := v.(uint16)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case int32:
ft := v.(int32)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case uint32:
ft := v.(uint32)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case int64:
ft := v.(int64)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case uint64:
ft := v.(uint64)
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
case string:
ft := v.(string)
l.SetTable(table, lua.LString(k), lua.LString(ft))
case []byte:
ft := string(v.([]byte))
l.SetTable(table, lua.LString(k), lua.LString(ft))
case nil:
l.SetTable(table, lua.LString(k), lua.LNil)
default:
jsonValue, _ := json.Marshal(v)
l.SetTable(table, lua.LString(k), lua.LString(jsonValue))
}
}
}
func lvToMap(lv lua.LValue) (map[string]interface{}, bool) {
switch lv.Type() {
case lua.LTTable:
t := lvToInterface(lv, false)
ret := t.(map[string]interface{})
//为保证lua5.1中雪花算法id不能直接使用 必须转为字符串
if b, err := json.Marshal(ret); err != nil {
panic(err)
} else {
reg := regexp.MustCompile(`(\d{14,20}),`)
l := len(reg.FindAllString(string(b), -1)) //正则匹配14-20位的数字,如果找到了就开始正则替换并解析
if l != 0 {
str := reg.ReplaceAllString(string(b), `"${1}",`) //执行替换{}对象
reg := regexp.MustCompile(`(\d{14,20})}`)
str = reg.ReplaceAllString(str, `"${1}"}`) //执行替换}
reg = regexp.MustCompile(`(\d{14,20})]`)
str = reg.ReplaceAllString(str, `"${1}"]`) //执行替换 []数组
var jdata map[string]interface{}
err := json.Unmarshal([]byte(str), &jdata)
if err != nil {
println("\njson解析失败", str)
panic(err)
}
ret = jdata
}
}
return ret, true
default:
return nil, false
}
}
func interfaceToLv(v interface{}) lua.LValue {
switch v.(type) {
case float64:
ft := v.(float64)
return lua.LNumber(ft)
case float32:
ft := v.(float32)
return lua.LNumber(ft)
case int:
vs := gconv.String(v.(int))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(int)
return lua.LNumber(ft)
case uint:
vs := gconv.String(v.(uint))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(uint)
return lua.LNumber(ft)
case int8:
ft := v.(int8)
return lua.LNumber(ft)
case uint8:
ft := v.(uint8)
return lua.LNumber(ft)
case int16:
ft := v.(int16)
return lua.LNumber(ft)
case uint16:
ft := v.(uint16)
return lua.LNumber(ft)
case int32:
vs := gconv.String(v.(int32))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(int32)
return lua.LNumber(ft)
case uint32:
vs := gconv.String(v.(uint32))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(uint32)
return lua.LNumber(ft)
case int64:
vs := gconv.String(v.(int64))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(int64)
return lua.LNumber(ft)
case uint64:
vs := gconv.String(v.(uint64))
if len(vs) > 14 {
return lua.LString(vs)
}
ft := v.(uint64)
return lua.LNumber(ft)
case string:
ft := v.(string)
return lua.LString(ft)
case []byte:
ft := string(v.([]byte))
return lua.LString(ft)
case nil:
return lua.LNil
default:
jsonValue, _ := json.Marshal(v)
return lua.LString(jsonValue)
}
}
func (s *Elastic7Endpoint) prepareBulk(action, index, id, doc string, bulk *elastic.BulkService) {
//为保证lua5.1中雪花算法id不能直接使用 必须转为字符串,但是es里id作为字符串无法正常排序等操作 这里将转为整数
reg := regexp.MustCompile(`"(\d{14,20})",`)
l := len(reg.FindAllString(string(doc), -1)) //正则匹配14-20位的数字,如果找到了就开始正则替换并解析
if l != 0 {
str := reg.ReplaceAllString(string(doc), `${1},`) //执行替换{}对象
reg := regexp.MustCompile(`(\d{14,20})}`)
str = reg.ReplaceAllString(str, `${1}}`) //执行替换}
reg = regexp.MustCompile(`"(\d{14,20})"]`)
str = reg.ReplaceAllString(str, `${1}]`) //执行替换 []数组
doc = str
}
switch action {
case canal.InsertAction:
req := elastic.NewBulkIndexRequest().Index(index).Id(id).Doc(doc)
bulk.Add(req)
case canal.UpdateAction:
req := elastic.NewBulkUpdateRequest().Index(index).Id(id).Doc(doc)
bulk.Add(req)
case canal.DeleteAction:
req := elastic.NewBulkDeleteRequest().Index(index).Id(id)
bulk.Add(req)
}
logs.Infof("index: %s, doc: %s", index, doc)
}
下面是kibana中的截图
这里不会丢失精度了。