From f888dd7dea91052a3320e873166fd0d1ed12c10a Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:29:57 +0200 Subject: [PATCH] migrated dish_name_tag_average --- server/backend/cafeteria.go | 2 +- .../cron/average_rating_computation.go | 36 ------------------- server/backend/cron/cronjobs.go | 15 ++------ server/backend/migration/20220713000000.go | 18 +++++++++- server/backend/migration/20231015000000.go | 29 +++++++++++++-- server/model/dish_name_tag_average.go | 17 --------- server/model/dish_name_tag_statistic.go | 11 ++++++ 7 files changed, 57 insertions(+), 71 deletions(-) delete mode 100644 server/backend/cron/average_rating_computation.go delete mode 100644 server/model/dish_name_tag_average.go create mode 100644 server/model/dish_name_tag_statistic.go diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index 84b762d4..1c409d0b 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -271,7 +271,7 @@ func queryTags(cafeteriaID int32, dishID int32, ratingType ModelType, tx *gorm.D err = tx.Table("dish_to_dish_name_tag mapping"). Where("mapping.dishID = ?", dishID). Select("mapping.nameTagID as tag"). - Joins("JOIN dish_name_tag_average results ON mapping.nameTagID = results.tagID"). + Joins("JOIN dish_name_tag_statistic results ON mapping.nameTagID = results.tagID"). Joins("JOIN dish_name_tag_option options ON mapping.nameTagID = options.dishNameTagOption"). Select("mapping.nameTagID as tagId, results.average as avg, " + "results.min as min, results.max as max, results.std as std"). diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go deleted file mode 100644 index 4fc08f3f..00000000 --- a/server/backend/cron/average_rating_computation.go +++ /dev/null @@ -1,36 +0,0 @@ -package cron - -import ( - "github.com/TUM-Dev/Campus-Backend/server/model" - log "github.com/sirupsen/logrus" -) - -// averageRatingComputation -// This cronjob precomputes average ratings of all cafeteria ratings, dish ratings and all three types of tags. -// They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" -func (c *CronService) averageRatingComputation() error { - computeAverageNameTags(c) - - return nil -} - -func computeAverageNameTags(c *CronService) { - var results []model.DishNameTagAverage - err := c.db.Raw(`SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std -FROM dish_rating mr -JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating -GROUP BY mr.cafeteriaID, mnt.tagnameID`).Scan(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average name tags.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.DishNameTagAverage{}).Error // Does not work with "true" - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - err := c.db.Model(&model.DishNameTagAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average name tag rating in the database.") - } - } -} diff --git a/server/backend/cron/cronjobs.go b/server/backend/cron/cronjobs.go index 95ba45a2..8249c286 100644 --- a/server/backend/cron/cronjobs.go +++ b/server/backend/cron/cronjobs.go @@ -50,23 +50,16 @@ func New(db *gorm.DB) *CronService { func (c *CronService) Run() error { log.WithField("MensaCronActive", env.IsMensaCronActive()).Debug("running cron service") - g := new(errgroup.Group) - - if env.IsMensaCronActive() { - g.Go(func() error { return c.dishNameDownloadCron() }) - g.Go(func() error { return c.averageRatingComputation() }) - } - for { + g := new(errgroup.Group) log.Trace("Cron: checking for pending") var res []model.Crontab c.db.Model(&model.Crontab{}). - Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?, ?)", time.Now().Unix(), NewsType, FileDownloadType, - AverageRatingComputation, DishNameDownload, CanteenHeadcount, IOSNotifications, @@ -106,10 +99,6 @@ func (c *CronService) Run() error { if env.IsMensaCronActive() { g.Go(c.dishNameDownloadCron) } - case AverageRatingComputation: //call every five minutes between 11AM and 4 PM on weekdays - if env.IsMensaCronActive() { - g.Go(c.averageRatingComputation) - } case NewExamResultsHook: g.Go(func() error { return c.newExamResultsHookCron() }) case MovieType: diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 6ed1e2b6..a92c1fee 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -70,6 +70,22 @@ func (n *InitialCafeteriaRatingTagsAverage) TableName() string { return "cafeteria_rating_tag_average" } +// InitialDishNameTagAverage stores all precomputed values for the DishName ratings +type InitialDishNameTagAverage struct { + DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagAverage) TableName() string { + return "dish_name_tag_average" +} + // migrate20220713000000 func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ @@ -86,11 +102,11 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.DishNameTagOptionIncluded{}, &model.DishNameTagOptionExcluded{}, &model.DishNameTag{}, - &model.DishNameTagAverage{}, &model.DishRating{}, &model.DishRatingTag{}, &model.DishRatingTagOption{}, &model.DishToDishNameTag{}, + &InitialDishNameTagAverage{}, &InitialCafeteriaRatingAverage{}, &InitialCafeteriaRatingTagsAverage{}, &InitialDishRatingAverage{}, diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 0c81ed8b..9bf26d06 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -69,13 +69,29 @@ func (n *CafeteriaRatingTagsAverage) TableName() string { return "cafeteria_rating_tag_average" } +// DishNameTagAverage stores all precomputed values for the DishName ratings +type DishNameTagAverage struct { + DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *DishNameTagAverage) TableName() string { + return "dish_name_tag_average" +} + // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { - tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average"} + tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average", "dish_name_tag_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err @@ -109,16 +125,23 @@ JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating GROUP BY cr.cafeteriaID, crt.tagID`).Error; err != nil { return err } + if err := tx.Exec(`CREATE VIEW dish_name_tag_statistics AS +SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std +FROM dish_rating mr +JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating +GROUP BY mr.cafeteriaID, mnt.tagnameID`).Error; err != nil { + return err + } return nil }, Rollback: func(tx *gorm.DB) error { - createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_average"} + createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_statistics", "dish_name_tag_statistics"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}) + return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}, &DishNameTagAverage{}) }, } } diff --git a/server/model/dish_name_tag_average.go b/server/model/dish_name_tag_average.go deleted file mode 100644 index 2ee05076..00000000 --- a/server/model/dish_name_tag_average.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// DishNameTagAverage stores all precomputed values for the DishName ratings -type DishNameTagAverage struct { - DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` - TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` - Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` - Min int8 `gorm:"column:min;type:int;not null;" json:"min"` - Max int8 `gorm:"column:max;type:int;not null;" json:"max"` - Std float32 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *DishNameTagAverage) TableName() string { - return "dish_name_tag_average" -} diff --git a/server/model/dish_name_tag_statistic.go b/server/model/dish_name_tag_statistic.go new file mode 100644 index 00000000..44539206 --- /dev/null +++ b/server/model/dish_name_tag_statistic.go @@ -0,0 +1,11 @@ +package model + +// DishNameTagStatistic is a view for statistics of DishName ratings +type DishNameTagStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +}