neck_ring_handle.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. package crontab
  2. import (
  3. "fmt"
  4. "kpt-pasture/model"
  5. "kpt-pasture/util"
  6. "math"
  7. "sort"
  8. "time"
  9. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  10. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  11. "gitee.com/xuyiping_admin/pkg/xerr"
  12. "go.uber.org/zap"
  13. )
  14. const (
  15. MinChangeFilter = -99
  16. MinRuminaFilter = -99
  17. MinChewFilter = -99
  18. MinChangeHigh = -99
  19. DefaultNb = 30
  20. DefaultScore = 100
  21. )
  22. var (
  23. defaultLimit = int32(1000)
  24. isDelete bool
  25. mergeIsRunning bool
  26. calculateIsRunning bool
  27. )
  28. // NeckRingOriginalMergeData 把脖环数据合并成2个小时的
  29. func (e *Entry) NeckRingOriginalMergeData() (err error) {
  30. if mergeIsRunning {
  31. return nil
  32. }
  33. newTime := time.Now()
  34. mergeIsRunning = true
  35. defer func() {
  36. mergeIsRunning = false
  37. if newTime.Day()%15 == 0 && !isDelete {
  38. // 原始数据删除15天前的
  39. e.DB.Model(new(model.NeckRingOriginal)).
  40. Where("created_at < ?", newTime.AddDate(0, 0, -15).Unix()).
  41. Delete(new(model.NeckRingOriginal))
  42. e.DB.Model(new(model.NeckRingProcess)).
  43. Where("created_at < ?", newTime.AddDate(0, 0, -15).Unix()).
  44. Delete(new(model.NeckRingProcess))
  45. // 活动数据删除6个月前的数据
  46. e.DB.Model(new(model.NeckActiveHabit)).
  47. Where("created_at < ?", newTime.AddDate(0, -6, 0).Unix()).
  48. Delete(new(model.NeckActiveHabit))
  49. isDelete = true
  50. }
  51. }()
  52. limit := e.Cfg.NeckRingLimit
  53. if limit <= 0 {
  54. limit = defaultLimit
  55. }
  56. //createdAt := newTime.Add(-1 * time.Hour)
  57. //neckRingNumber := []string{"10026", "10027", "10028", "10029", "10030", "10031", "10032", "10033", "10034", "10035"}
  58. neckRingNumber := []string{"10027"}
  59. neckRingList := make([]*model.NeckRingOriginal, 0)
  60. if err = e.DB.Model(new(model.NeckRingOriginal)).
  61. Where("is_show = ?", pasturePb.IsShow_No).
  62. Where("neck_ring_number IN (?)", neckRingNumber).
  63. //Where("created_at <= ?", createdAt.Unix()).
  64. Order("active_date,frameid,neck_ring_number").
  65. Limit(int(limit)).Find(&neckRingList).Error; err != nil {
  66. return xerr.WithStack(err)
  67. }
  68. if len(neckRingList) <= 0 {
  69. return nil
  70. }
  71. // 计算合并
  72. neckActiveHabitList := e.recalculate(neckRingList)
  73. if len(neckActiveHabitList) <= 0 {
  74. return nil
  75. }
  76. for _, habit := range neckActiveHabitList {
  77. //更新脖环牛只相关信息 新数据直接插入
  78. historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(habit.NeckRingNumber, habit.HeatDate, habit.Frameid)
  79. if ct <= 0 {
  80. if err = e.DB.Create(habit).Error; err != nil {
  81. zaplog.Info("NeckRingOriginalMergeData-1",
  82. zap.Any("err", err),
  83. zap.Any("neckActiveHabit", habit),
  84. )
  85. }
  86. } else {
  87. // 重新计算
  88. newNeckActiveHabit := e.againRecalculate(historyNeckActiveHabit)
  89. if newNeckActiveHabit == nil {
  90. continue
  91. }
  92. if err = e.DB.Model(new(model.NeckActiveHabit)).
  93. Select("rumina", "intake", "inactive", "gasp", "other", "high", "active", "is_show", "record_count").
  94. Where("id = ?", historyNeckActiveHabit.Id).
  95. Updates(newNeckActiveHabit).Error; err != nil {
  96. zaplog.Error("NeckRingOriginalMergeData-3",
  97. zap.Any("err", err),
  98. zap.Any("ct", ct),
  99. zap.Any("historyNeckActiveHabit", historyNeckActiveHabit),
  100. zap.Any("newNeckActiveHabit", newNeckActiveHabit),
  101. )
  102. }
  103. }
  104. if err = e.UpdateNeckRingOriginalIsShow(habit); err != nil {
  105. zaplog.Error("NeckRingOriginalMergeData-2",
  106. zap.Any("err", err),
  107. zap.Any("neckActiveHabit", habit),
  108. )
  109. }
  110. }
  111. return nil
  112. }
  113. func (e *Entry) NeckRingCalculate() error {
  114. pastureList := e.FindPastureList()
  115. if pastureList == nil || len(pastureList) == 0 {
  116. return nil
  117. }
  118. if calculateIsRunning {
  119. return nil
  120. }
  121. defer func() {
  122. calculateIsRunning = false
  123. }()
  124. calculateIsRunning = true
  125. for _, pasture := range pastureList {
  126. if err := e.EntryUpdateActiveHabit(pasture.Id); err != nil {
  127. zaplog.Error("NeckRingCalculate", zap.Any("err", err), zap.Any("pasture", pasture))
  128. }
  129. zaplog.Info(fmt.Sprintf("NeckRingCalculate Success %d", pasture.Id))
  130. }
  131. return nil
  132. }
  133. // recalculate 合并计算
  134. func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
  135. originalMapData := make(map[string]*model.NeckRingOriginalMerge)
  136. // 合并成2个小时的
  137. for _, v := range neckRingList {
  138. xframeId := util.XFrameId(v.Frameid)
  139. mapKey := fmt.Sprintf("%s%s%s%s%d", v.NeckRingNumber, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001/2023-12-04/0 0001/2023-12-03/4
  140. if originalMapData[mapKey] == nil {
  141. originalMapData[mapKey] = new(model.NeckRingOriginalMerge)
  142. }
  143. originalMapData[mapKey].IsMageData(v, xframeId)
  144. }
  145. currTime := time.Now()
  146. res := make([]*model.NeckActiveHabit, 0)
  147. // 算平均值
  148. for k, v := range originalMapData {
  149. // 过滤掉合并后不等于6条数据
  150. if v.RecordCount > 6 {
  151. delete(originalMapData, k)
  152. continue
  153. } else if v.RecordCount < 6 {
  154. currMaxXframeId := util.FrameIdMapReverse[int32(currTime.Hour())]
  155. activeDateString := fmt.Sprintf("%s %02d:00:00", v.ActiveDate, v.XframeId*2+1)
  156. activeDate, _ := time.Parse(model.LayoutTime, activeDateString)
  157. if currMaxXframeId-v.XframeId <= 1 && currTime.Add(-1*time.Hour).Unix() < activeDate.Unix() {
  158. delete(originalMapData, k)
  159. continue
  160. }
  161. }
  162. v.SumAvg()
  163. }
  164. if len(originalMapData) <= 0 {
  165. return res
  166. }
  167. res = model.NeckRingOriginalMap(originalMapData).ForMatData()
  168. sort.Sort(model.NeckActiveHabitSlice(res))
  169. return res
  170. }
  171. func (e *Entry) againRecalculate(data *model.NeckActiveHabit) *model.NeckActiveHabit {
  172. originalList := make([]*model.NeckRingOriginal, 0)
  173. frameIds := util.FrameIds(data.Frameid)
  174. if err := e.DB.Model(new(model.NeckRingOriginal)).
  175. Where("pasture_id = ?", data.PastureId).
  176. Where("neck_ring_number = ?", data.NeckRingNumber).
  177. Where("active_date = ?", data.HeatDate).
  178. Where("frameid IN (?)", frameIds).
  179. Find(&originalList).Error; err != nil {
  180. return nil
  181. }
  182. newDataList := e.recalculate(originalList)
  183. if len(newDataList) != 1 {
  184. return nil
  185. }
  186. res := newDataList[0]
  187. res.IsShow = pasturePb.IsShow_No
  188. return res
  189. }
  190. func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
  191. // 获取这段执行数据内最大日期和最小日期
  192. xToday := &XToday{}
  193. systemConfigureList, err := e.GetSystemConfigure(pastureId)
  194. if err != nil {
  195. return xerr.WithStack(err)
  196. }
  197. for _, v := range systemConfigureList {
  198. switch v.Name {
  199. case model.MaxHabit:
  200. xToday.LastMaxHabitId = v.Value
  201. case model.High:
  202. xToday.High = int32(v.Value)
  203. case model.Rumina:
  204. xToday.Rumina = int32(v.Value)
  205. case model.XRuminaDisc:
  206. xToday.XRuminaDisc = int32(v.Value)
  207. case model.XChangeDiscount:
  208. xToday.XChangeDiscount = int32(v.Value)
  209. case model.WeeklyActive:
  210. xToday.WeeklyActive = int32(v.Value)
  211. }
  212. }
  213. currMaxHabit := &model.NeckActiveHabit{}
  214. if err = e.DB.Model(new(model.NeckActiveHabit)).
  215. Where("id > ?", xToday.LastMaxHabitId).
  216. Where("pasture_id = ?", pastureId).
  217. Where("is_show = ?", pasturePb.IsShow_No).
  218. Order("id desc").First(currMaxHabit).Error; err != nil {
  219. return xerr.WithStack(err)
  220. }
  221. if currMaxHabit.Id <= 0 || currMaxHabit.Id <= xToday.LastMaxHabitId {
  222. return nil
  223. }
  224. xToday.CurrMaxHabitId = currMaxHabit.Id
  225. defer func() {
  226. // 更新最后一次执行的id值
  227. if err == nil {
  228. e.DB.Model(new(model.SystemConfigure)).
  229. Where("name = ?", model.MaxHabit).
  230. Where("pasture_id = ?", pastureId).
  231. Update("value", currMaxHabit.Id)
  232. }
  233. }()
  234. var processIds []int64
  235. // 更新活动滤波
  236. processIds, err = e.FirstFilterUpdate(pastureId, xToday)
  237. if err != nil {
  238. zaplog.Error("NeckRingCalculate", zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
  239. }
  240. if len(processIds) > 0 {
  241. if err = e.WeeklyUpdateActiveHabit(pastureId, processIds, xToday); err != nil {
  242. zaplog.Error("NeckRingCalculate", zap.Any("WeeklyUpdateActiveHabit", err), zap.Any("xToday", xToday))
  243. }
  244. if err = e.Before3DaysNeckActiveHabit(pastureId, processIds, xToday); err != nil {
  245. zaplog.Error("NeckRingCalculate", zap.Any("Before3DaysNeckActiveHabit", err), zap.Any("xToday", xToday))
  246. }
  247. // 二次更新滤波
  248. if err = e.SecondUpdateChangeFilter(pastureId, xToday); err != nil {
  249. zaplog.Error("NeckRingCalculate", zap.Any("SecondUpdateChangeFilter", err), zap.Any("xToday", xToday))
  250. }
  251. }
  252. // 活动量校正系数和健康评分
  253. if err = e.FilterCorrectAndScoreUpdate(pastureId, xToday); err != nil {
  254. zaplog.Error("NeckRingCalculate", zap.Any("ActivityVolumeChanges", err), zap.Any("xToday", xToday))
  255. }
  256. if err = e.DB.Model(new(model.NeckActiveHabit)).
  257. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  258. Where("pasture_id = ?", pastureId).
  259. Where("is_show = ?", pasturePb.IsShow_No).
  260. Where("change_filter = ?", model.InitChangeFilter).
  261. Updates(map[string]interface{}{
  262. "change_filter": model.DefaultChangeFilter,
  263. "rumina_filter": model.DefaultRuminaFilter,
  264. "chew_filter": model.DefaultChewFilter,
  265. }).Error; err != nil {
  266. zaplog.Error("EntryUpdateActiveHabit", zap.Any("change_filter", err), zap.Any("xToday", xToday))
  267. }
  268. if err = e.DB.Model(new(model.NeckActiveHabit)).
  269. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  270. Where("pasture_id = ?", pastureId).
  271. Where("change_filter < ?", 0).
  272. Where("filter_correct < ?", model.DefaultFilterCorrect).
  273. Updates(map[string]interface{}{
  274. "filter_correct": model.DefaultFilterCorrect,
  275. }).Error; err != nil {
  276. zaplog.Error("EntryUpdateActiveHabit", zap.Any("filter_correct", err), zap.Any("xToday", xToday))
  277. }
  278. // 插入群体校正表
  279. if err = e.UpdateChangeAdJust(pastureId, xToday); err != nil {
  280. zaplog.Error("EntryUpdateActiveHabit", zap.Any("UpdateChangeAdJust", err), zap.Any("xToday", xToday))
  281. }
  282. return nil
  283. }
  284. // FirstFilterUpdate 首次更新活动滤波
  285. func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds []int64, err error) {
  286. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  287. if err = e.DB.Model(new(model.NeckActiveHabit)).
  288. Where("id BETWEEN ? AND ?", xToDay.LastMaxHabitId, xToDay.CurrMaxHabitId).
  289. Where("pasture_id = ?", pastureId).
  290. Where("is_show = ?", pasturePb.IsShow_No).
  291. Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
  292. Order("heat_date,neck_ring_number,frameid").
  293. Limit(int(defaultLimit)).Find(&newNeckActiveHabitList).Error; err != nil {
  294. return nil, xerr.WithStack(err)
  295. }
  296. // 活动量滤波
  297. for _, v := range newNeckActiveHabitList {
  298. // 过滤牛只未绑定的脖环的数据
  299. cowInfo := e.GetCowInfoByNeckRingNumber(v.PastureId, v.NeckRingNumber)
  300. if cowInfo == nil || cowInfo.Id <= 0 {
  301. continue
  302. }
  303. frameId := v.Frameid
  304. heatDate := v.HeatDate
  305. if v.Frameid == 0 {
  306. frameId = 11
  307. heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
  308. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  309. }
  310. firstFilterData := e.FindFirstFilter(pastureId, v.NeckRingNumber, heatDate, frameId)
  311. if v.FilterHigh > 0 {
  312. firstFilterData.FilterHigh = v.FilterHigh
  313. } else {
  314. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  315. firstFilterData.FilterHigh = int32(computeIfPositiveElse(float64(v.High), float64(firstFilterData.FilterHigh), 0.23, 0.77))
  316. } else {
  317. firstFilterData.FilterHigh = v.High
  318. }
  319. }
  320. if v.FilterRumina > 0 {
  321. firstFilterData.FilterRumina = v.FilterRumina
  322. } else {
  323. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  324. firstFilterData.FilterRumina = int32(computeIfPositiveElse(float64(v.Rumina), float64(firstFilterData.FilterRumina), 0.33, 0.67))
  325. } else {
  326. firstFilterData.FilterRumina = v.Rumina
  327. }
  328. }
  329. if v.FilterChew > 0 {
  330. firstFilterData.FilterChew = v.FilterChew
  331. } else {
  332. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  333. firstFilterData.FilterChew = int32(computeIfPositiveElse(float64(v.Rumina+v.Intake), float64(firstFilterData.FilterChew), 0.33, 0.67))
  334. } else {
  335. firstFilterData.FilterChew = v.Rumina + v.Intake
  336. }
  337. }
  338. processIds = append(processIds, v.Id)
  339. // 更新过滤值
  340. if err = e.DB.Model(new(model.NeckActiveHabit)).
  341. Select(
  342. "filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age",
  343. ).Where("id = ?", v.Id).
  344. Updates(map[string]interface{}{
  345. "filter_high": firstFilterData.FilterHigh,
  346. "filter_rumina": firstFilterData.FilterRumina,
  347. "filter_chew": firstFilterData.FilterChew,
  348. "cow_id": cowInfo.Id,
  349. "lact": cowInfo.Lact,
  350. "calving_age": cowInfo.CalvingAge,
  351. }).Error; err != nil {
  352. zaplog.Error("FirstFilterUpdate",
  353. zap.Any("error", err),
  354. zap.Any("firstFilterData", firstFilterData),
  355. zap.Any("NeckActiveHabit", v),
  356. zap.Any("cowInfo", cowInfo),
  357. zap.Any("xToday", xToDay),
  358. )
  359. }
  360. }
  361. return processIds, nil
  362. }
  363. func (e *Entry) WeeklyUpdateActiveHabit(pastureId int64, processIds []int64, xToDay *XToday) (err error) {
  364. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  365. if err = e.DB.Model(new(model.NeckActiveHabit)).
  366. Where("id IN (?)", processIds).
  367. Order("heat_date,neck_ring_number,frameid").
  368. Find(&newNeckActiveHabitList).Error; err != nil {
  369. return xerr.WithStack(err)
  370. }
  371. for _, v := range newNeckActiveHabitList {
  372. // 前七天的
  373. weekHabitData := e.FindWeekHabitData(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid, xToDay)
  374. highDiff := v.FilterHigh - weekHabitData.WeekHighHabit
  375. denominator := float64(v.WeekHigh)*0.6 + float64(weekHabitData.WeekHighHabit)*0.2 + float64(xToDay.WeeklyActive)*0.2
  376. if highDiff > 0 {
  377. v.ChangeHigh = int32(math.Round((float64(highDiff) / denominator) * 100))
  378. } else {
  379. v.ChangeHigh = int32(math.Round(float64(highDiff) / denominator * 100))
  380. }
  381. if weekHabitData.WeekRuminaHabit != 0 {
  382. v.ChangeRumina = int32(math.Round(float64(v.FilterRumina-weekHabitData.WeekRuminaHabit) / float64(weekHabitData.WeekRuminaHabit) * 100))
  383. } else {
  384. v.ChangeRumina = 0
  385. }
  386. if weekHabitData.WeekChewHabit != 0 {
  387. v.ChangeChew = int32(math.Round(float64(v.FilterChew-weekHabitData.WeekChewHabit) / float64(weekHabitData.WeekChewHabit) * 100))
  388. } else {
  389. v.ChangeChew = 0
  390. }
  391. sumHabitData := e.FindSumHabitData(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid, xToDay)
  392. // 更新过滤值
  393. if err = e.DB.Model(new(model.NeckActiveHabit)).
  394. Select(
  395. "week_high_habit", "week_rumina_habit", "week_chew_habit", "week_intake_habit", "week_inactive_habit",
  396. "sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew",
  397. "change_high", "change_rumina", "change_chew", "before_three_sum_rumina", "before_three_sum_intake",
  398. ).Where("id = ?", v.Id).
  399. Updates(map[string]interface{}{
  400. "week_high_habit": weekHabitData.WeekHighHabit,
  401. "week_rumina_habit": weekHabitData.WeekRuminaHabit,
  402. "week_chew_habit": weekHabitData.WeekChewHabit,
  403. "week_intake_habit": weekHabitData.WeekIntakeHabit,
  404. "week_inactive_habit": weekHabitData.WeekIntakeHabit,
  405. "sum_rumina": sumHabitData.SumRumina,
  406. "sum_intake": sumHabitData.SumIntake,
  407. "sum_inactive": sumHabitData.SumInactive,
  408. "sum_active": sumHabitData.SumActive,
  409. "sum_max_high": sumHabitData.SumMaxHigh,
  410. "sum_min_high": sumHabitData.SumMinHigh,
  411. "sum_min_chew": sumHabitData.SumMinChew,
  412. "change_high": v.ChangeHigh,
  413. "change_rumina": v.ChangeRumina,
  414. "change_chew": v.ChangeChew,
  415. }).Error; err != nil {
  416. zaplog.Error("WeeklyUpdateActiveHabit",
  417. zap.Error(err),
  418. zap.Any("NeckActiveHabit", v),
  419. zap.Any("pastureId", pastureId),
  420. )
  421. }
  422. }
  423. return err
  424. }
  425. func (e *Entry) Before3DaysNeckActiveHabit(pastureId int64, processIds []int64, xToDay *XToday) (err error) {
  426. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  427. if err = e.DB.Model(new(model.NeckActiveHabit)).
  428. Where("id IN (?)", processIds).
  429. Order("heat_date,neck_ring_number,frameid").
  430. Find(&newNeckActiveHabitList).Error; err != nil {
  431. return xerr.WithStack(err)
  432. }
  433. for _, v := range newNeckActiveHabitList {
  434. before3DaysNeckActiveHabit := e.FindBefore3DaysNeckActiveHabit(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid)
  435. // 更新过滤值
  436. if err = e.DB.Model(new(model.NeckActiveHabit)).
  437. Select("before_three_sum_rumina", "before_three_sum_intake").
  438. Where("id = ?", v.Id).
  439. Updates(map[string]interface{}{
  440. "before_three_sum_rumina": before3DaysNeckActiveHabit.SumRumina,
  441. "before_three_sum_intake": before3DaysNeckActiveHabit.SumIntake,
  442. }).Error; err != nil {
  443. zaplog.Error("Before3DaysNeckActiveHabit",
  444. zap.Error(err),
  445. zap.Any("NeckActiveHabit", v),
  446. zap.Any("pastureId", pastureId),
  447. )
  448. }
  449. }
  450. return nil
  451. }
  452. // SecondUpdateChangeFilter 第二次更新变化趋势滤波
  453. func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err error) {
  454. newChangeFilterList := make([]*ChangeFilterData, 0)
  455. if err = e.DB.Model(new(model.NeckActiveHabit)).
  456. Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina",
  457. "chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
  458. Where("heat_date >= ?", time.Now().AddDate(0, 0, -2).Format(model.LayoutDate2)).
  459. Where("pasture_id = ?", pastureId).
  460. Where("change_filter = ?", model.InitChangeFilter).
  461. Where("change_high > ?", MinChangeHigh).
  462. Order("neck_ring_number,heat_date,frameid").
  463. Find(&newChangeFilterList).Error; err != nil {
  464. return xerr.WithStack(err)
  465. }
  466. for _, v := range newChangeFilterList {
  467. secondFilterData := &SecondFilterData{}
  468. frameId := v.FrameId
  469. heatDate := v.HeatDate
  470. if v.FrameId == 0 {
  471. frameId = 11
  472. heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
  473. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  474. }
  475. if err = e.DB.Model(new(model.NeckActiveHabit)).
  476. Select("neck_ring_number", "filter_high", "filter_rumina", "filter_chew").
  477. Where("neck_ring_number = ?", v.NeckRingNumber).
  478. Where("heat_date = ?", heatDate).
  479. Where("frameid = ?", frameId).
  480. First(&secondFilterData).Error; err != nil {
  481. zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err))
  482. }
  483. if v.ChangeFilter > MinChangeFilter {
  484. secondFilterData.ChangeFilter = float64(v.ChangeFilter)
  485. } else {
  486. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  487. secondFilterData.ChangeFilter = secondFilterData.ChangeFilter*(1-(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount) +
  488. math.Min(float64(v.ChangeHigh), secondFilterData.ChangeFilter+135)*(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount
  489. } else {
  490. secondFilterData.ChangeFilter = 0
  491. }
  492. }
  493. if v.RuminaFilter > MinRuminaFilter {
  494. secondFilterData.RuminaFilter = float64(v.ChangeFilter)
  495. } else {
  496. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  497. discount := float64(xToday.XRuminaDisc) / 10 * v.XlcDisCount
  498. if math.Abs(float64(v.ChangeRumina)) > 60 {
  499. discount *= 0.5
  500. }
  501. secondFilterData.RuminaFilter = secondFilterData.RuminaFilter*(1-discount) + float64(v.ChangeRumina)*discount
  502. } else {
  503. secondFilterData.RuminaFilter = 0
  504. }
  505. }
  506. secondFilterData.RuminaFilter = math.Min(50, secondFilterData.RuminaFilter)
  507. if v.ChewFilter > MinChewFilter {
  508. secondFilterData.ChewFilter = float64(v.ChangeChew)
  509. } else {
  510. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  511. discount := float64(xToday.XRuminaDisc) / 10
  512. if math.Abs(float64(v.ChangeChew)) > 60 {
  513. discount *= 0.5
  514. }
  515. secondFilterData.ChewFilter = secondFilterData.ChewFilter*(1-discount) + float64(v.ChangeChew)*discount
  516. } else {
  517. secondFilterData.ChewFilter = 0
  518. }
  519. }
  520. secondFilterData.ChewFilter = math.Min(50, secondFilterData.ChewFilter)
  521. if err = e.DB.Model(new(model.NeckActiveHabit)).
  522. Select("change_filter", "rumina_filter", "chew_filter").
  523. Where("id = ?", v.Id).
  524. Updates(map[string]interface{}{
  525. "change_filter": secondFilterData.ChangeFilter,
  526. "rumina_filter": secondFilterData.RuminaFilter,
  527. "chew_filter": secondFilterData.ChewFilter,
  528. }).Error; err != nil {
  529. zaplog.Error("SecondUpdateChangeFilter-1", zap.Any("error", err), zap.Any("xToday", xToday))
  530. }
  531. }
  532. return nil
  533. }
  534. // FilterCorrectAndScoreUpdate 计算活动量变化趋势校正值(活跃度校正)和健康评分
  535. func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) error {
  536. beginDayDate := time.Now()
  537. before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
  538. before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
  539. activityVolumeList := make([]*ActivityVolume, 0)
  540. activityVolumeMap := make(map[string]*ActivityVolume)
  541. if err := e.DB.Model(new(model.NeckActiveHabit)).
  542. Select("neck_ring_number", "AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter",
  543. "ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter", "COUNT(1) as nb").
  544. Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
  545. Where("pasture_id = ?", pastureId).
  546. Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
  547. Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)).
  548. Where("change_filter > ?", MinChangeFilter).
  549. Having("nb > ?", DefaultNb).
  550. Group("neck_ring_number").
  551. Find(&activityVolumeList).Error; err != nil {
  552. zaplog.Error("ActivityVolumeChanges-0", zap.Any("error", err), zap.Any("xToday", xToday))
  553. }
  554. if len(activityVolumeList) > 0 {
  555. for _, v := range activityVolumeList {
  556. activityVolumeMap[v.NeckRingNumber] = v
  557. }
  558. }
  559. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  560. if err := e.DB.Model(new(model.NeckActiveHabit)).
  561. Where("id <= ?", xToday.CurrMaxHabitId).
  562. Where("heat_date >= ?", before1DayDate).
  563. Where("pasture_id = ?", pastureId).
  564. Where(e.DB.Where("high > ?", xToday.High).Or("rumina > ?", xToday.Rumina)).
  565. Find(&neckActiveHabitList).Error; err != nil {
  566. zaplog.Error("ActivityVolumeChanges-1", zap.Any("error", err), zap.Any("xToday", xToday))
  567. return xerr.WithStack(err)
  568. }
  569. for _, v := range neckActiveHabitList {
  570. if filterCorrectMap, ok := activityVolumeMap[v.NeckRingNumber]; ok {
  571. filterCorrect := model.DefaultFilterCorrect - int(math.Floor(filterCorrectMap.AvgFilter/3+float64(filterCorrectMap.StdFilter)/2))
  572. // 活动量校正系数
  573. if err := e.DB.Model(new(model.NeckActiveHabit)).
  574. Where("id = ?", v.Id).
  575. Where("neck_ring_number = ?", v.NeckRingNumber).
  576. Update("filter_correct", filterCorrect).Error; err != nil {
  577. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  578. continue
  579. }
  580. }
  581. cowScore := calculateScore(v)
  582. if err := e.DB.Model(new(model.NeckActiveHabit)).
  583. Where("id = ?", v.Id).
  584. Update("score", cowScore).Error; err != nil {
  585. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  586. continue
  587. }
  588. }
  589. return nil
  590. }
  591. // UpdateChangeAdJust 更新群体校正数据
  592. func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error {
  593. res := make([]*model.NeckRingBarChange, 0)
  594. oneDayAgo := time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2)
  595. if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())).
  596. Select("h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter").
  597. Joins("JOIN cow as c ON h.neck_ring_number = c.neck_ring_number").
  598. Where("h.pasture_id = ?", pastureId).
  599. Where("h.heat_date >= ?", oneDayAgo).
  600. Where("h.cow_id >= ?", 0).
  601. Group("h.heat_date, h.frameid, c.pen_id").
  602. Order("h.heat_date, h.frameid, c.pen_name").
  603. Find(&res).Error; err != nil {
  604. return xerr.WithStack(err)
  605. }
  606. for _, v := range res {
  607. if err := e.DB.Model(new(model.NeckActiveHabit)).
  608. Where("id > ?", xToday.LastMaxHabitId).
  609. Where("heat_date = ?", v.HeatDate).
  610. Where("frameid = ?", v.FrameId).
  611. Where("neck_ring_number = ?", v.NeckRingNumber).
  612. Update("change_adjust", v.ChangeHigh).Error; err != nil {
  613. zaplog.Error("UpdateChangeAdJust-1", zap.Any("error", err), zap.Any("xToday", xToday))
  614. }
  615. }
  616. // 更新所有的显示状态为否的记录为是
  617. if err := e.DB.Model(new(model.NeckActiveHabit)).
  618. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  619. Where("pasture_id = ?", pastureId).
  620. Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
  621. zaplog.Error("UpdateChangeAdJust-2", zap.Any("error", err), zap.Any("xToday", xToday))
  622. }
  623. return nil
  624. }
  625. func (e *Entry) UpdateNeckRingOriginalIsShow(habit *model.NeckActiveHabit) error {
  626. if err := e.DB.Model(new(model.NeckRingOriginal)).
  627. Where("pasture_id = ?", habit.PastureId).
  628. Where("neck_ring_number = ?", habit.NeckRingNumber).
  629. Where("active_date = ?", habit.HeatDate).
  630. Where("frameid IN (?)", util.FrameIds(habit.Frameid)).
  631. Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
  632. return xerr.WithStack(err)
  633. }
  634. return nil
  635. }
  636. // computeIfPositiveElse 辅助函数来计算过滤值
  637. func computeIfPositiveElse(newValue, prevFilterValue float64, weightPrev, weightNew float64) float64 {
  638. return math.Ceil((prevFilterValue * weightPrev) + (weightNew * newValue))
  639. }
  640. // 计算 score 的逻辑
  641. func calculateScore(habit *model.NeckActiveHabit) int {
  642. // 第一部分逻辑
  643. var part1 float64
  644. switch {
  645. case (habit.CalvingAge <= 1 && habit.Lact >= 1) ||
  646. (habit.CalvingAge >= 2 && habit.CalvingAge <= 13 && (habit.SumRumina+habit.SumIntake) == 0) ||
  647. ((habit.Lact == 0 || habit.CalvingAge >= 14) && habit.ChangeFilter == -99):
  648. part1 = -199
  649. case habit.CalvingAge >= 2 && habit.CalvingAge <= 13:
  650. part1 = math.Min((float64(habit.SumRumina+habit.SumIntake)-(100+math.Min(7, float64(habit.CalvingAge))*60))/10*2, 0)
  651. case habit.ChangeFilter > -99:
  652. part1 = math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinHigh), 0)))*0.2 +
  653. math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinChew), 0)))*0.2 +
  654. getRuminaSumIntakeSumScore(float64(habit.SumRumina+habit.SumIntake)) + getAdditionalScore(habit)
  655. default:
  656. part1 = -299
  657. }
  658. // 第二部分逻辑
  659. var part2 float64
  660. switch {
  661. case habit.FirmwareVersion%100 >= 52:
  662. part2 = 1
  663. case habit.FirmwareVersion%100 >= 30 && habit.FirmwareVersion%100 <= 43:
  664. part2 = 0.8
  665. default:
  666. part2 = 0.6
  667. }
  668. // 最终 score
  669. return DefaultScore + int(math.Floor(part1*part2))
  670. }
  671. // 获取值或默认值
  672. func getValueOrDefault(value, defaultValue float64) float64 {
  673. if value > -99 {
  674. return value
  675. }
  676. return defaultValue
  677. }
  678. // 计算累计反刍得分
  679. func getRuminaSumIntakeSumScore(sum float64) float64 {
  680. switch {
  681. case sum < 80:
  682. return -30
  683. case sum < 180:
  684. return -20
  685. case sum < 280:
  686. return -10
  687. default:
  688. return 0
  689. }
  690. }
  691. // 计算额外得分
  692. func getAdditionalScore(habit *model.NeckActiveHabit) float64 {
  693. var score float64
  694. if (habit.SumRumina+habit.SumIntake < 280 || habit.SumMinHigh+habit.SumMinChew < -50) && habit.SumMaxHigh > 50 {
  695. score += 10
  696. }
  697. if habit.ChangeFilter < -30 && habit.ChangeFilter <= habit.SumMinHigh && habit.ChewFilter < -30 && habit.ChewFilter <= habit.SumMinChew {
  698. score -= 5
  699. }
  700. return score
  701. }