Browse Source

Merge branch 'eta_2.6.1_forecast_year_on_year_diff' of eta_server/eta_index_lib into master

chenhan 2 days ago
parent
commit
1ed4e57edc
4 changed files with 313 additions and 3 deletions
  1. 148 1
      logic/predict_edb.go
  2. 5 0
      models/edb_info.go
  3. 33 2
      models/predict_edb_data_base.go
  4. 127 0
      models/predict_edb_info_rule.go

+ 148 - 1
logic/predict_edb.go

@@ -395,6 +395,73 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName, dataDateType st
 				EndDate:      v.EndDate,
 				EdbInfoIdArr: v.EdbInfoIdArr,
 			}
+		case 17, 18:
+			//关联的指标信息
+			edbInfoList := make([]*models.EdbInfo, 0)
+			// 动态环差规则 关系表
+			trendsMappingList := make([]*models.PredictEdbConfCalculateMapping, 0)
+			edbInfoId, parseErr := strconv.Atoi(v.Value)
+			if parseErr != nil {
+				errMsg = "请填写正确的指标id"
+				err = errors.New(errMsg)
+				return
+			}
+			fromEdbInfo, tmpErr := models.GetEdbInfoById(edbInfoId)
+			if tmpErr != nil {
+				err = tmpErr
+				if err.Error() == utils.ErrNoRow() {
+					errMsg = "指标 " + strconv.Itoa(edbInfoId) + " 不存在"
+					err = errors.New(errMsg)
+					return
+				}
+				errMsg = "获取指标失败:Err:" + err.Error()
+				err = errors.New(errMsg)
+				return
+			}
+
+			edbInfoList = append(edbInfoList, fromEdbInfo)
+
+			//总的 预测指标与所有相关联指标的关系表(不仅仅该条规则)
+			calculateMappingItem = &models.EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 0,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   "",
+				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+				FromEdbCode:               fromEdbInfo.EdbCode,
+				FromEdbName:               fromEdbInfo.EdbName,
+				FromSource:                fromEdbInfo.Source,
+				FromSourceName:            fromEdbInfo.SourceName,
+				//FromTag:                   tmpEdbInfoId.FromTag,
+				Sort:       1,
+				CreateTime: time.Now(),
+				ModifyTime: time.Now(),
+			}
+
+			calculateMappingList = append(calculateMappingList, calculateMappingItem)
+			// 动态同比同差规则 关系表
+			tmpPredictEdbConfCalculateMapping := &models.PredictEdbConfCalculateMapping{
+				//PredictEdbConfCalculateMappingId: 0,
+				EdbInfoId:      0,
+				ConfigId:       0,
+				FromEdbInfoId:  fromEdbInfo.EdbInfoId,
+				FromEdbCode:    fromEdbInfo.EdbCode,
+				FromEdbName:    fromEdbInfo.EdbName,
+				FromSource:     fromEdbInfo.Source,
+				FromSourceName: fromEdbInfo.SourceName,
+				Sort:           1,
+				CreateTime:     time.Now(),
+				ModifyTime:     time.Now(),
+			}
+			trendsMappingList = append(trendsMappingList, tmpPredictEdbConfCalculateMapping)
+			calculateRuleMap[ruleIndex] = models.CalculateRule{
+				TrendsCalculateMappingList: trendsMappingList,
+				EdbInfoList:                edbInfoList,
+				RuleType:                   v.RuleType,
+				EndDate:                    v.EndDate,
+				EdbInfoIdArr:               v.EdbInfoIdArr,
+			}
 		}
 
 		tmpPredictEdbConf := &models.PredictEdbConf{
@@ -416,10 +483,23 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName, dataDateType st
 
 		predictEdbConfList = append(predictEdbConfList, tmpPredictEdbConf)
 	}
+	//calculateMappingList是映射关系,只需要记录一条,因此对list需要去重复
+	calculateMappingList = RemoveDuplicateCalculateMappingList(calculateMappingList)
 	err, errMsg = models.AddPredictEdb(edbInfo, calculateMappingList, predictEdbConfList, calculateRuleMap)
 
 	return
 }
+func RemoveDuplicateCalculateMappingList(list []*models.EdbInfoCalculateMapping) (newList []*models.EdbInfoCalculateMapping) {
+	newList = make([]*models.EdbInfoCalculateMapping, 0)
+	tmpMap := make(map[int]bool)
+	for _, v := range list {
+		if _, ok := tmpMap[v.FromEdbInfoId]; !ok {
+			tmpMap[v.FromEdbInfoId] = true
+			newList = append(newList, v)
+		}
+	}
+	return
+}
 
 // EditPredictEdbInfo 编辑预测指标
 func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string, endDateType int, ruleList []models.RuleConfig, minValue, maxValue float64, lang string) (edbInfo *models.EdbInfo, err error, errMsg string) {
@@ -801,7 +881,73 @@ func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string,
 				EndDate:      v.EndDate,
 				EdbInfoIdArr: v.EdbInfoIdArr,
 			}
+		case 17, 18:
+			//关联的指标信息
+			edbInfoList := make([]*models.EdbInfo, 0)
+			// 动态 关系表
+			trendsMappingList := make([]*models.PredictEdbConfCalculateMapping, 0)
+			relateEdbInfoId, parseErr := strconv.Atoi(v.Value)
+			if parseErr != nil {
+				errMsg = "请填写正确的指标id"
+				err = errors.New(errMsg)
+				return
+			}
+			fromEdbInfo, tmpErr := models.GetEdbInfoById(relateEdbInfoId)
+			if tmpErr != nil {
+				err = tmpErr
+				if err.Error() == utils.ErrNoRow() {
+					errMsg = "指标 " + strconv.Itoa(relateEdbInfoId) + " 不存在"
+					err = errors.New(errMsg)
+					return
+				}
+				errMsg = "获取指标失败:Err:" + err.Error()
+				err = errors.New(errMsg)
+				return
+			}
 
+			edbInfoList = append(edbInfoList, fromEdbInfo)
+
+			//总的 预测指标与所有相关联指标的关系表(不仅仅该条规则)
+			fromEdbMap[relateEdbInfoId] = relateEdbInfoId
+			calculateMappingItem = &models.EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 0,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   "",
+				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+				FromEdbCode:               fromEdbInfo.EdbCode,
+				FromEdbName:               fromEdbInfo.EdbName,
+				FromSource:                fromEdbInfo.Source,
+				FromSourceName:            fromEdbInfo.SourceName,
+				//FromTag:                   tmpEdbInfoId.FromTag,
+				Sort:       1,
+				CreateTime: time.Now(),
+				ModifyTime: time.Now(),
+			}
+			calculateMappingList = append(calculateMappingList, calculateMappingItem)
+			// 动态同比同差规则 关系表
+			tmpPredictEdbConfCalculateMapping := &models.PredictEdbConfCalculateMapping{
+				//PredictEdbConfCalculateMappingId: 0,
+				EdbInfoId:      0,
+				ConfigId:       0,
+				FromEdbInfoId:  fromEdbInfo.EdbInfoId,
+				FromEdbCode:    fromEdbInfo.EdbCode,
+				FromEdbName:    fromEdbInfo.EdbName,
+				FromSource:     fromEdbInfo.Source,
+				FromSourceName: fromEdbInfo.SourceName,
+				Sort:           1,
+				CreateTime:     time.Now(),
+				ModifyTime:     time.Now(),
+			}
+			trendsMappingList = append(trendsMappingList, tmpPredictEdbConfCalculateMapping)
+			calculateRuleMap[ruleIndex] = models.CalculateRule{
+				TrendsCalculateMappingList: trendsMappingList,
+				EdbInfoList:                edbInfoList,
+				RuleType:                   v.RuleType,
+				EndDate:                    v.EndDate,
+				EdbInfoIdArr:               v.EdbInfoIdArr,
+			}
 		}
 
 		tmpPredictEdbConf := &models.PredictEdbConf{
@@ -823,7 +969,8 @@ func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string,
 
 		predictEdbConfList = append(predictEdbConfList, tmpPredictEdbConf)
 	}
-
+	//编辑的时候也需要去重复calcuateMappingList
+	calculateMappingList = RemoveDuplicateCalculateMappingList(calculateMappingList)
 	err, errMsg = models.EditPredictEdb(edbInfo, updateEdbInfoCol, calculateMappingList, predictEdbConfList, calculateRuleMap)
 
 	return

+ 5 - 0
models/edb_info.go

@@ -1166,6 +1166,11 @@ func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbCo
 			if err != nil {
 				return
 			}
+		case 17, 18:
+			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleDynamicYOYComparisonOrDifference(predictEdbConf.RuleType, predictEdbConf.PredictEdbInfoId, predictEdbConf.Value, dayList, realPredictEdbInfoData, existMap)
+			if err != nil {
+				return
+			}
 		}
 
 		// 下一个规则的开始日期

+ 33 - 2
models/predict_edb_data_base.go

@@ -114,7 +114,22 @@ func AddPredictEdb(item *EdbInfo, calculateMappingList []*EdbInfoCalculateMappin
 					return
 				}
 			}
-
+		case 17, 18: //14:根据 一元线性拟合 规则获取预测数据
+			calculateRule := calculateRuleMap[k]
+			calculateRule.ConfigId = v.ConfigId
+			calculateRule.EdbInfoId = v.PredictEdbInfoId
+			// 规则与指标的关系入库
+			lenTrendsCalculateMapping := len(calculateRule.TrendsCalculateMappingList)
+			if lenTrendsCalculateMapping > 0 {
+				for _, vv := range calculateRule.TrendsCalculateMappingList {
+					vv.EdbInfoId = item.EdbInfoId
+					vv.ConfigId = v.ConfigId
+				}
+				err = to.CreateInBatches(calculateRule.TrendsCalculateMappingList, utils.MultiAddNum).Error
+				if err != nil {
+					return
+				}
+			}
 		}
 
 		// 规则配置(含数据)
@@ -262,8 +277,24 @@ func EditPredictEdb(edbInfo *EdbInfo, updateEdbInfoCol []string, calculateMappin
 				if err != nil {
 					return
 				}
-			}
 
+			}
+		case 17, 18: //14:根据 一元线性拟合 规则获取预测数据
+			calculateRule := calculateRuleMap[confIndex]
+			calculateRule.ConfigId = v.ConfigId
+			calculateRule.EdbInfoId = v.PredictEdbInfoId
+			// 规则与指标的关系入库
+			lenTrendsCalculateMapping := len(calculateRule.TrendsCalculateMappingList)
+			if lenTrendsCalculateMapping > 0 {
+				for _, vv := range calculateRule.TrendsCalculateMappingList {
+					vv.EdbInfoId = edbInfo.EdbInfoId
+					vv.ConfigId = v.ConfigId
+				}
+				err = to.CreateInBatches(calculateRule.TrendsCalculateMappingList, utils.MultiAddNum).Error
+				if err != nil {
+					return
+				}
+			}
 		}
 
 		calculateRuleIndex++

+ 127 - 0
models/predict_edb_info_rule.go

@@ -8,6 +8,7 @@ import (
 	"github.com/nosixtools/solarlunar"
 	"github.com/shopspring/decimal"
 	"math"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -1858,3 +1859,129 @@ func getYearListBySeasonConf(configValue string) (yearList []int, seasonConf Sea
 
 	return
 }
+
+// GetChartPredictEdbInfoDataListByRuleDynamicYOYComparisonOrDifference 动态同比
+// 2、指标选择范围为预测指标。
+// 3、动态同比计算方法:预测值=去年同期值*(1+同比指标预测值)
+// 4、上述“去年同期”如果没有严格对应的日期,则前后查找最近35天的值。
+// 5、选择的同比指标日期需要与预测指标未来日期对应上,对应不上的不生成预测值。
+func GetChartPredictEdbInfoDataListByRuleDynamicYOYComparisonOrDifference(ruleType, edbInfoId int, configValue string, dayList []time.Time, realPredictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64, err error) {
+	//预测指标的去年同期数据
+	baseDynamicDataList := make(map[string]decimal.Decimal, len(dayList))
+	//动态同比同差指标
+	DynamicCalculateDataList := make(map[string]decimal.Decimal, len(dayList))
+	index := len(realPredictEdbInfoData)
+	if index <= 0 {
+		return
+	}
+	dynamicYOYComparisonIndexId, err := strconv.Atoi(configValue)
+	if err != nil {
+		return
+	}
+	newPredictEdbInfoData = make([]*EdbInfoSearchData, 0, len(dayList))
+	// 获取同比预测指标的预测数据
+	dynamicYOYComparisonIndex, err := GetEdbInfoById(dynamicYOYComparisonIndexId)
+	if err != nil {
+		return
+	}
+	if dynamicYOYComparisonIndex.EdbInfoType != 1 {
+		err = errors.New("选择的指标不是预测指标")
+		return
+	}
+	startDate, endDate := dayList[0].Format(utils.FormatDate), dayList[len(dayList)-1].Format(utils.FormatDate)
+	//获取动态同比指标对应预测日期的预测数据
+	dynamicYOYComparisonIndexDataList, err := GetEdbDataList(dynamicYOYComparisonIndex.Source, dynamicYOYComparisonIndex.SubSource, dynamicYOYComparisonIndex.EdbInfoId, startDate, endDate)
+	if err != nil {
+		return
+	}
+	if len(dynamicYOYComparisonIndexDataList) <= 0 {
+		return
+	} else {
+		for _, v := range dynamicYOYComparisonIndexDataList {
+			DynamicCalculateDataList[v.DataTime] = decimal.NewFromFloat(v.Value)
+		}
+	}
+	var predictDayList []time.Time
+	//获取上一期的同期数据
+	for _, date := range dayList {
+		preDate := date.AddDate(-1, 0, 0)
+		preDateStr := preDate.Format(utils.FormatDate)
+		if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
+			baseDynamicDataList[preDateStr] = decimal.NewFromFloat(preValue)
+			predictDayList = append(predictDayList, date)
+		} else {
+			if replaceValue, replaceOk := getReplaceValue(existMap, 35, 1, -1, preDate); !replaceOk {
+				continue
+			} else {
+				baseDynamicDataList[preDateStr] = replaceValue
+				predictDayList = append(predictDayList, date)
+			}
+		}
+	}
+
+	//获取后面的预测数据
+
+	for k, currentDate := range predictDayList {
+		var calculateValue decimal.Decimal
+		var dateStr = currentDate.Format(utils.FormatDate)
+		preDate := currentDate.AddDate(-1, 0, 0)
+		preDateStr := preDate.Format(utils.FormatDate)
+		_, dynamicVal := DynamicCalculateDataList[dateStr]
+		_, baseVal := baseDynamicDataList[preDateStr]
+		if dynamicVal && baseVal {
+			switch ruleType {
+			case 17:
+				calculateValue = baseDynamicDataList[preDateStr].Mul(DynamicCalculateDataList[dateStr].Add(decimal.NewFromInt(1)))
+			case 18:
+				calculateValue = baseDynamicDataList[preDateStr].Add(DynamicCalculateDataList[dateStr])
+			default:
+				err = errors.New("计算规则不存在")
+				return
+			}
+			tmpData := &EdbInfoSearchData{
+				EdbDataId:     edbInfoId + 100000 + index + k,
+				EdbInfoId:     edbInfoId,
+				DataTime:      currentDate.Format(utils.FormatDate),
+				DataTimestamp: currentDate.UnixNano() / 1e6,
+			}
+			var val = calculateValue.InexactFloat64()
+			tmpData.Value = val
+			newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
+			existMap[tmpData.DataTime] = val
+			if k == 0 {
+				minValue = val
+				maxValue = val
+			} else {
+				// 最大最小值
+				if val < minValue {
+					minValue = val
+				}
+				if val > maxValue {
+					maxValue = val
+				}
+			}
+		}
+	}
+	return
+}
+func getReplaceValue(replaceValueMap map[string]float64, days, dayStepForward int, dayStepBack int, currentDate time.Time) (replaceValue decimal.Decimal, success bool) {
+	nextDateDay := currentDate
+	backDateDay := currentDate
+	for i := 0; i <= days; i++ {
+		nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+		if preValue, ok := replaceValueMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+			replaceValue = decimal.NewFromFloat(preValue)
+			success = true
+			return
+		}
+		backDateDayStr := backDateDay.Format(utils.FormatDate)
+		if backValue, ok := replaceValueMap[backDateDayStr]; ok { //上一年同期->下一个月找到
+			replaceValue = decimal.NewFromFloat(backValue)
+			success = true
+			return
+		}
+		nextDateDay = nextDateDay.AddDate(0, 0, dayStepForward)
+		backDateDay = nextDateDay.AddDate(0, 0, dayStepBack)
+	}
+	return decimal.NewFromInt(0), false
+}