|
@@ -9,13 +9,14 @@ import (
|
|
|
"github.com/shopspring/decimal"
|
|
|
"github.com/yidane/formula"
|
|
|
"math"
|
|
|
+ "regexp"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
func CheckFormula(formula string) map[string]string {
|
|
|
- mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}
|
|
|
+ mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN", "EXP"}
|
|
|
|
|
|
str := strings.ToUpper(formula)
|
|
|
for _, v := range mathFormula {
|
|
@@ -37,22 +38,23 @@ func CheckFormula(formula string) map[string]string {
|
|
|
return byteMap
|
|
|
}
|
|
|
|
|
|
-// CheckFormula2 校验公式是否正常(比如说除法的分母不能为0之类的,实际上就是用预设的字段数据做一次计算)
|
|
|
-func CheckFormula2(edbInfoArr []*data_manage.EdbInfo, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) (ok bool, err error) {
|
|
|
- valArr := make(map[int]float64)
|
|
|
- for _, v := range edbInfoArr {
|
|
|
- valArr[v.EdbInfoId] = 100
|
|
|
- }
|
|
|
- formulaStr = strings.ToUpper(formulaStr)
|
|
|
- formulaFormStr := ReplaceFormula(edbInfoArr, valArr, formulaMap, formulaStr, edbInfoIdBytes)
|
|
|
- if formulaFormStr == "" {
|
|
|
+type FormulaListItem struct {
|
|
|
+ Formula string `json:"f"`
|
|
|
+ Date string `json:"d"`
|
|
|
+}
|
|
|
+
|
|
|
+// CheckFormulaJson 检测计算公式json串是否异常
|
|
|
+func CheckFormulaJson(formula string) (formulaSlice []string, err error) {
|
|
|
+ list := make([]FormulaListItem, 0)
|
|
|
+ err = json.Unmarshal([]byte(formula), &list)
|
|
|
+ if err != nil {
|
|
|
+ err = fmt.Errorf("公式串解析失败: json.Unmarshal Err: %v", err)
|
|
|
return
|
|
|
}
|
|
|
- expression := formula.NewExpression(formulaFormStr)
|
|
|
- _, err = expression.Evaluate()
|
|
|
- if err != nil {
|
|
|
- } else {
|
|
|
- ok = true
|
|
|
+ formulaSlice = make([]string, 0)
|
|
|
+ // 日期排序
|
|
|
+ for _, v := range list {
|
|
|
+ formulaSlice = append(formulaSlice, v.Formula)
|
|
|
}
|
|
|
return
|
|
|
}
|
|
@@ -62,91 +64,8 @@ type CalculateItems struct {
|
|
|
DataMap map[string]float64
|
|
|
}
|
|
|
|
|
|
-func Calculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCode, formulaStr string, edbInfoIdBytes []string) (err error) {
|
|
|
- defer func() {
|
|
|
- if err != nil {
|
|
|
- utils.FileLog.Info("Calculate Err:%s" + err.Error())
|
|
|
- }
|
|
|
- }()
|
|
|
- saveDataMap := make(map[string]map[int]float64)
|
|
|
- for _, v := range edbInfoIdArr {
|
|
|
- var condition string
|
|
|
- var pars []interface{}
|
|
|
- condition += " AND edb_info_id=? "
|
|
|
- pars = append(pars, v.EdbInfoId)
|
|
|
- dataList, err := data_manage.GetEdbDataListAll(condition, pars, v.Source, v.SubSource, 1)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- dataMap := make(map[string]float64)
|
|
|
- for _, dv := range dataList {
|
|
|
- if val, ok := saveDataMap[dv.DataTime]; ok {
|
|
|
- if _, ok := val[v.EdbInfoId]; !ok {
|
|
|
- val[v.EdbInfoId] = dv.Value
|
|
|
- }
|
|
|
- } else {
|
|
|
- temp := make(map[int]float64)
|
|
|
- temp[v.EdbInfoId] = dv.Value
|
|
|
- saveDataMap[dv.DataTime] = temp
|
|
|
- }
|
|
|
- }
|
|
|
- item := new(CalculateItems)
|
|
|
- item.EdbInfoId = v.EdbInfoId
|
|
|
- item.DataMap = dataMap
|
|
|
- }
|
|
|
- formulaMap := CheckFormula(formulaStr)
|
|
|
- addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
|
|
|
- nowStr := time.Now().Format(utils.FormatDateTime)
|
|
|
- var isAdd bool
|
|
|
- for sk, sv := range saveDataMap {
|
|
|
- formulaStr = strings.ToUpper(formulaStr)
|
|
|
- formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
|
|
|
- if formulaStr == "" {
|
|
|
- return
|
|
|
- }
|
|
|
- if formulaFormStr != "" {
|
|
|
- expression := formula.NewExpression(formulaFormStr)
|
|
|
- calResult, err := expression.Evaluate()
|
|
|
- if err != nil {
|
|
|
- err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
|
|
|
- fmt.Println(err)
|
|
|
- return err
|
|
|
- }
|
|
|
- calVal, err := calResult.Float64()
|
|
|
- if err != nil {
|
|
|
- err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
|
|
|
- fmt.Println(err)
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- //需要存入的数据
|
|
|
- {
|
|
|
- dataTime, _ := time.Parse(utils.FormatDate, sk)
|
|
|
- timestamp := dataTime.UnixNano() / 1e6
|
|
|
- timeStr := fmt.Sprintf("%d", timestamp)
|
|
|
- addSql += "("
|
|
|
- addSql += strconv.Itoa(edbInfoId) + "," + "'" + edbCode + "'" + "," + "'" + sk + "'" + "," + utils.SubFloatToString(calVal, 4) + "," + "'" + nowStr + "'" +
|
|
|
- "," + "'" + nowStr + "'" + "," + "1"
|
|
|
- addSql += "," + "'" + timeStr + "'"
|
|
|
- addSql += "),"
|
|
|
- isAdd = true
|
|
|
- }
|
|
|
- } else {
|
|
|
- fmt.Println("formulaFormStr is empty")
|
|
|
- }
|
|
|
- }
|
|
|
- if isAdd {
|
|
|
- addSql = strings.TrimRight(addSql, ",")
|
|
|
- data_manage.AddEdbDataCalculateBySql(addSql)
|
|
|
- if err != nil {
|
|
|
- fmt.Println("AddEdbDataCalculate Err:" + err.Error())
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
- return
|
|
|
-}
|
|
|
-
|
|
|
func ReplaceFormula(edbInfoIdArr []*data_manage.EdbInfo, valArr map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) string {
|
|
|
+ // todo 处理min和max
|
|
|
funMap := GetFormulaMap()
|
|
|
for k, v := range funMap {
|
|
|
formulaStr = strings.Replace(formulaStr, k, v, -1)
|
|
@@ -548,7 +467,22 @@ func RefreshCalculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCod
|
|
|
}
|
|
|
|
|
|
// 处理整个数据
|
|
|
-func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo) {
|
|
|
+func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo, emptyType int) {
|
|
|
+ var startDate, endDate string
|
|
|
+ var startDateT, endDateT time.Time
|
|
|
+ if emptyType == 2 || emptyType == 3 {
|
|
|
+ for k, _ := range realSaveDataMap {
|
|
|
+ if k > endDate {
|
|
|
+ endDate = k
|
|
|
+ }
|
|
|
+ if k < startDate || startDate == "" {
|
|
|
+ startDate = k
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ startDateT, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
|
|
|
+ endDateT, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
|
|
|
+ }
|
|
|
for _, date := range dateList {
|
|
|
tmpDataMap := realSaveDataMap[date]
|
|
|
for _, edbInfo := range edbInfoIdArr {
|
|
@@ -569,8 +503,16 @@ func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[s
|
|
|
// day = 365
|
|
|
//}
|
|
|
// 需求池 255 指标运算文案修改,补数据遍历区间修改(2023-3-7 09:37:23修改)
|
|
|
- day := 35
|
|
|
- handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, day)
|
|
|
+ switch emptyType {
|
|
|
+ case 0:
|
|
|
+ handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, 35)
|
|
|
+ case 2:
|
|
|
+ handleDateDataMapBefore(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
|
|
|
+ case 3:
|
|
|
+ handleDateDataMapAfter(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
|
|
|
+ case 4:
|
|
|
+ handleDateDataMapZero(saveDataMap, date, tmpEdbInfoId)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -711,3 +653,112 @@ func CallCalculateComputeCorrelation(data *data_manage.EdbInfoCalculateBatchSave
|
|
|
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+// handleDateDataMapBefore 前值填充:空值优先以最近的前值填充,没有前值时,用后值填充
|
|
|
+func handleDateDataMapBefore(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
|
|
|
+ currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
+
|
|
|
+ // 后一天
|
|
|
+ nextDateDay := currDate
|
|
|
+
|
|
|
+ // 前一天
|
|
|
+ preDateDay := currDate
|
|
|
+
|
|
|
+ for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
|
|
|
+ // 上个日期的数据
|
|
|
+ {
|
|
|
+ preDateDay = currDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
|
|
|
+ // 下个日期的数据
|
|
|
+ {
|
|
|
+ nextDateDay = currDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// handleDateDataMapAfter 后值填充:空值优先以最近的后值填充,没有后值时,用前值填充
|
|
|
+func handleDateDataMapAfter(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
|
|
|
+ currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
+
|
|
|
+ // 后一天
|
|
|
+ nextDateDay := currDate
|
|
|
+
|
|
|
+ // 前一天
|
|
|
+ preDateDay := currDate
|
|
|
+
|
|
|
+ for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
|
|
|
+ // 下个日期的数据
|
|
|
+ {
|
|
|
+ nextDateDay = currDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
|
|
|
+ // 上个日期的数据
|
|
|
+ {
|
|
|
+ preDateDay = currDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// handleDateDataMapZero 等于0
|
|
|
+func handleDateDataMapZero(saveDataMap map[string]map[int]float64, date string, edbInfoId int) {
|
|
|
+ saveDataMap[date][edbInfoId] = 0
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func GetMaxMinEdbInfo(formula string) string {
|
|
|
+ //formula := "A+min(A,B,max(A,C))"
|
|
|
+ // todo 无法处理max里嵌套max或者min的情况
|
|
|
+ // 使用正则表达式匹配MAX和MIN函数及其参数
|
|
|
+ regex := regexp.MustCompile(`(?i)(MAX|MIN)\((.*?)\)`)
|
|
|
+ matches := regex.FindAllStringSubmatch(formula, -1)
|
|
|
+ // 遍历匹配结果,输出MAX和MIN函数及其参数
|
|
|
+ for _, match := range matches {
|
|
|
+ if len(match) == 3 {
|
|
|
+ parameter := strings.ToLower(match[0]) // 参数
|
|
|
+ formula = strings.ReplaceAll(formula, match[0], parameter)
|
|
|
+ fmt.Printf("formula: %s\n", formula)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ formula = strings.ReplaceAll(formula, "max", "MAX")
|
|
|
+ formula = strings.ReplaceAll(formula, "min", "MIN")
|
|
|
+ return formula
|
|
|
+}
|