go语言+lua5.1语言同步到es中遇到大数字导致精度丢失问题

11 篇文章 0 订阅
7 篇文章 0 订阅

lua5.3之前都会有这个问题。但是目前我们使用的go嵌入lua使用的解释器只有5.1所以这个只能靠自己转换解决。目前是用在go+lua同步es的工具上。

解决方式分这几个步骤:

1.go将传递给lua的14-20位的数字转换为字符串

2.lua调用go往es中塞数据时再次逆转为数字,便可以保证es中 本地数据库中都是数字了,而且不丢失精度。

比较简单。以下给部分代码demo

go往lua中传值类型的处理 


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)
	}

}


lua调用go往es里塞数据的处理


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中的截图

 这里不会丢失精度了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值