The server for Open Course World

dyna: advanced searches, move course_info into course and add like_ratio, boo_ratio and clear_rate

mm2srv c559a0cc a622763a

+107 -29
+5 -5
db/dyna/course_info.go
··· 13 13 clears = 1 14 14 } 15 15 _, err := s.Conn.Exec(context.Background(), ` 16 - INSERT INTO course_info (id, data_id, plays, tries, deaths, clears, likes, boos) VALUES (DEFAULT, $1, 1, $2, $3, $4, 0, 0) 17 - ON CONFLICT (data_id) DO UPDATE SET plays = course_info.plays + 1, tries = course_info.tries + $2, deaths = course_info.deaths + $3, clears = course_info.clears + $4 16 + INSERT INTO course (id, data_id, plays, tries, deaths, clears) VALUES (DEFAULT, $1, 1, $2, $3, $4) 17 + ON CONFLICT (data_id) DO UPDATE SET plays = course.plays + 1, tries = course.tries + $2, deaths = course.deaths + $3, clears = course.clears + $4, clear_rate = (course.clears::float / COALESCE(NULLIF(course.tries,0), 1)::float) 18 18 `, result.DataId, result.Tries, result.Deaths, clears) 19 19 return err 20 20 } ··· 28 28 } 29 29 30 30 _, err := s.Conn.Exec(context.Background(), ` 31 - INSERT INTO course_info (id, data_id, plays, tries, deaths, clears, likes, boos) VALUES (DEFAULT, $1, 0, 0, 0, 0, $2, $3) 32 - ON CONFLICT (data_id) DO UPDATE SET likes = course_info.likes + $2, boos = course_info.boos + $3 31 + INSERT INTO course (id, data_id, likes, boos) VALUES (DEFAULT, $1, $2, $3) 32 + ON CONFLICT (data_id) DO UPDATE SET likes = course.likes + $2, boos = course.boos + $3, like_ratio = (course.likes::float / COALESCE(NULLIF(course.plays,0), 1)::float), boo_ratio = (course.boos::float / COALESCE(NULLIF(course.plays,0), 1)::float) 33 33 `, dataId, like, boo) 34 34 return err 35 35 } 36 36 37 37 func (s *DB) GetCourseInfoPlayStatsAndRatings(dataId int64) (int, int, int, int, int, int, error) { 38 - row := s.Conn.QueryRow(context.Background(), `SELECT plays, tries, deaths, clears, likes, boos FROM course_info WHERE data_id = $1`, dataId) 38 + row := s.Conn.QueryRow(context.Background(), `SELECT plays, tries, deaths, clears, likes, boos FROM course WHERE data_id = $1`, dataId) 39 39 var plays int 40 40 var tries int 41 41 var deaths int
+44 -12
db/dyna/dyna.go
··· 920 920 func (s *DB) SearchCoursesAdvanced(current_pid datastore.Pid, dumpView *dump_view.DumpView, param view.SearchCoursesParam) ([]datastore.CourseInfo, []uint32, bool, error) { 921 921 infos := []datastore.CourseInfo{} 922 922 923 - sortBy := "ORDER BY time_uploaded DESC" 923 + sortBy := "" 924 924 //sortBy := "ORDER BY id DESC" 925 925 switch param.Advanced.SortType { 926 926 case 0: 927 927 // by popularity 928 - // TODO 929 - case 1: 930 - // by clear rate 931 - // TODO 928 + sortBy = "ORDER BY likes DESC, plays DESC" 932 929 case 2: 933 930 // by popularity in multiplayer versus 934 - // TODO 931 + // but use its as by time_uploaded 932 + sortBy = "ORDER BY time_uploaded DESC" 933 + case 1: 934 + // by clear rate 935 + sortBy = "ORDER BY clear_rate ASC, time_uploaded DESC" 936 + case 10: 937 + // popular tab 938 + sortBy = "ORDER BY like_ratio DESC" 939 + case 11: 940 + // hot tab 941 + sortBy = "ORDER BY boo_ratio ASC, plays DESC" 935 942 } 936 943 937 944 limitUploadDate := "AND time_uploaded IS NOT NULL" ··· 947 954 limitUploadDate = fmt.Sprintf("AND time_uploaded > (CURRENT_DATE - INTERVAL '365 days')") 948 955 case 3: 949 956 // ALL 957 + case 10: 958 + // weekly 959 + limitUploadDate = fmt.Sprintf("AND time_uploaded > (CURRENT_DATE - INTERVAL '7 days')") 960 + case 11: 961 + // monthly 962 + limitUploadDate = fmt.Sprintf("AND time_uploaded > (CURRENT_DATE - INTERVAL '30 days')") 950 963 } 951 964 952 965 limitPlays := "" ··· 964 977 case 3: 965 978 // ALL 966 979 } 967 - limitPlays = "" // TODO: we don't have plays field on course yet 968 980 969 981 courseTheme := "" 970 982 if param.Advanced.CourseTheme != 0xff { ··· 977 989 } 978 990 979 991 difficulty := "" 980 - if param.Advanced.Difficulty != 4 { 981 - difficulty = fmt.Sprintf("difficulty = %d AND ", param.Advanced.Difficulty) 992 + /* 993 + // ignore for now and just use clear_rate 994 + if param.Advanced.Difficulty != 4 { 995 + difficulty = fmt.Sprintf("difficulty = %d AND ", param.Advanced.Difficulty) 996 + } 997 + */ 998 + switch param.Advanced.Difficulty { 999 + case 0: 1000 + // easy 1001 + difficulty = "clear_rate > 0.8 AND " 1002 + case 1: 1003 + // normal 1004 + difficulty = "clear_rate > 0.4 AND clear_rate < 0.81 AND " 1005 + case 2: 1006 + // expert 1007 + difficulty = "clear_rate > 0.2 AND clear_rate < 0.41 AND " 1008 + case 3: 1009 + // super expert 1010 + //difficulty = "plays > 20 AND clear_rate < 0.2 AND " 1011 + difficulty = "clear_rate < 0.2 AND " 1012 + case 4: 1013 + // ALL 982 1014 } 983 1015 984 1016 byTags := "" 985 - if len(param.Advanced.Tags) != 16 { 1017 + if len(param.Advanced.Tags) != 16 && len(param.Advanced.Tags) < 16 { 986 1018 list := []string{} 987 1019 for _, tagId := range param.Advanced.Tags { 988 1020 list = append(list, strconv.Itoa(int(tagId))) ··· 992 1024 } 993 1025 994 1026 rejectRegions := "" 995 - if len(param.Advanced.RejectRegions) != 0 { 1027 + if len(param.Advanced.RejectRegions) != 0 && len(param.Advanced.RejectRegions) < 10 { 996 1028 list := []string{} 997 1029 for _, _id := range param.Advanced.RejectRegions { 998 1030 list = append(list, strconv.Itoa(int(_id))) ··· 1023 1055 } 1024 1056 1025 1057 func (s *DB) GetCoursesLatest(offset, size int) ([]datastore.CourseInfo, error) { 1026 - rows, err := s.Conn.Query(context.Background(), "SELECT data_id FROM course WHERE deleted = False AND time_uploaded IS NOT NULL ORDER BY id DESC LIMIT $1 OFFSET $2", size, offset) 1058 + rows, err := s.Conn.Query(context.Background(), "SELECT data_id FROM course WHERE deleted = False AND time_uploaded IS NOT NULL ORDER BY time_uploaded DESC LIMIT $1 OFFSET $2", size, offset) 1027 1059 if err == pgx.ErrNoRows { 1028 1060 return []datastore.CourseInfo{}, nil 1029 1061 } else if err != nil {
+21
db/migrations/000003_course_searches.down.sql
··· 1 + ALTER TABLE IF EXISTS course DROP COLUMN plays; 2 + ALTER TABLE IF EXISTS course DROP COLUMN tries; 3 + ALTER TABLE IF EXISTS course DROP COLUMN deaths; 4 + ALTER TABLE IF EXISTS course DROP COLUMN clears; 5 + ALTER TABLE IF EXISTS course DROP COLUMN likes; 6 + ALTER TABLE IF EXISTS course DROP COLUMN boos; 7 + ALTER TABLE IF EXISTS course DROP COLUMN like_ratio; 8 + ALTER TABLE IF EXISTS course DROP COLUMN boo_ratio; 9 + ALTER TABLE IF EXISTS course DROP COLUMN clear_rate; 10 + 11 + CREATE TABLE IF NOT EXISTS course_info ( 12 + id BIGSERIAL primary key, 13 + data_id BIGINT, 14 + plays INTEGER, 15 + tries INTEGER, 16 + deaths INTEGER, 17 + clears INTEGER, 18 + likes INTEGER, 19 + boos INTEGER, 20 + UNIQUE (data_id) 21 + );
+10
db/migrations/000003_course_searches.up.sql
··· 1 + DROP TABLE IF EXISTS course_info; 2 + ALTER TABLE IF EXISTS course ADD COLUMN plays INTEGER DEFAULT 0; 3 + ALTER TABLE IF EXISTS course ADD COLUMN tries INTEGER DEFAULT 0; 4 + ALTER TABLE IF EXISTS course ADD COLUMN deaths INTEGER DEFAULT 0; 5 + ALTER TABLE IF EXISTS course ADD COLUMN clears INTEGER DEFAULT 0; 6 + ALTER TABLE IF EXISTS course ADD COLUMN likes INTEGER DEFAULT 0; 7 + ALTER TABLE IF EXISTS course ADD COLUMN boos INTEGER DEFAULT 0; 8 + ALTER TABLE IF EXISTS course ADD COLUMN like_ratio FLOAT DEFAULT 0; 9 + ALTER TABLE IF EXISTS course ADD COLUMN boo_ratio FLOAT DEFAULT 0; 10 + ALTER TABLE IF EXISTS course ADD COLUMN clear_rate FLOAT DEFAULT 0;
+6
db/view/combined_view/view.go
··· 389 389 return s.DB.SearchCourses(state, datastore.Pid(state.Pid), s.DumpView, param) 390 390 case "advanced": 391 391 return s.DB.SearchCourses(state, datastore.Pid(state.Pid), s.DumpView, param) 392 + case "hot": 393 + return s.DB.SearchCourses(state, datastore.Pid(state.Pid), s.DumpView, param) 394 + case "popular_weekly": 395 + return s.DB.SearchCourses(state, datastore.Pid(state.Pid), s.DumpView, param) 396 + case "popular_all_time": 397 + return s.DB.SearchCourses(state, datastore.Pid(state.Pid), s.DumpView, param) 392 398 case "latest": 393 399 courses, err := s.DB.GetCoursesLatest(int(param.Offset), int(param.Size)) 394 400 restSize := param.Size - uint32(len(courses))
+21 -12
nex/rmc/server/smm2/search_courses.go
··· 10 10 func (s *Server) SearchCoursesPickUp(param datastore.SearchCoursesPickUpParam) ([]datastore.CourseInfo, error) { 11 11 fmt.Printf("param %#v\n", param) 12 12 p := view.SearchCoursesParam{ 13 - Type: "hot", 14 - Offset: 0, 15 - Size: 10, 16 - Difficulty: param.Difficulty, 13 + Type: "hot", 14 + Advanced: datastore.SearchCoursesAdvancedParam{ 15 + Difficulty: param.Difficulty, 16 + Range: datastore.ResultRange{Size: 50, Offset: 0}, 17 + SortType: 11, // hot 18 + DateUploaded: 3, // all time 19 + }, 17 20 } 18 21 19 22 courses, _, _, err := s.View.SearchCourses(s.State, p) ··· 25 28 func (s *Server) SearchCoursesTermsRanking(param datastore.SearchCoursesTermsRankingParam) ([]datastore.CourseInfo, []uint32, bool, error) { 26 29 fmt.Printf("param %#v\n", param) 27 30 p := view.SearchCoursesParam{ 28 - Type: "popular_weekly", 29 - Offset: param.Range.Offset, 30 - Size: param.Range.Size, 31 - Difficulty: param.Difficulty, 31 + Type: "popular_weekly", 32 + Advanced: datastore.SearchCoursesAdvancedParam{ 33 + Difficulty: param.Difficulty, 34 + Range: param.Range, 35 + SortType: 10, // popular 36 + DateUploaded: 10, // weekly 37 + }, 32 38 } 33 39 34 40 courses, ranks, _, err := s.View.SearchCourses(s.State, p) ··· 40 46 func (s *Server) SearchCoursesPointRanking(param datastore.SearchCoursesPointRankingParam) ([]datastore.CourseInfo, []uint32, bool, error) { 41 47 fmt.Printf("param %#v\n", param) 42 48 p := view.SearchCoursesParam{ 43 - Type: "popular_all_time", 44 - Offset: param.Range.Offset, 45 - Size: param.Range.Size, 46 - Difficulty: param.Difficulty, 49 + Type: "popular_all_time", 50 + Advanced: datastore.SearchCoursesAdvancedParam{ 51 + Difficulty: param.Difficulty, 52 + Range: param.Range, 53 + SortType: 10, // popular 54 + DateUploaded: 3, // all time 55 + }, 47 56 } 48 57 49 58 courses, ranks, _, err := s.View.SearchCourses(s.State, p)