Skip to content

Commit

Permalink
perf: optimize query page and performance
Browse files Browse the repository at this point in the history
  • Loading branch information
scenery committed Aug 22, 2024
1 parent af3b2a2 commit 840f8ba
Show file tree
Hide file tree
Showing 10 changed files with 932 additions and 55 deletions.
2 changes: 2 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
// 分类页面缓存: page:{subject_type}:{status}:{page_number}
// 分类总数缓存: count:{subject_type}
// 条目缓存: subject:{uuid}
// 搜索缓存: search:{query_key}:{page}
// 搜索总数缓存: count:search:{query_key}
type CacheItem struct {
Value interface{}
Expiration time.Time
Expand Down
42 changes: 33 additions & 9 deletions handlers/search.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
package handlers

import (
"strings"
"fmt"
"time"

"github.com/scenery/mediax/cache"
"github.com/scenery/mediax/database"
"github.com/scenery/mediax/models"
)

func GetSearchResult(query string) ([]models.SubjectSummary, int64, error) {
func GetSearchResult(query string, page int, pageSize int) ([]models.SubjectSummary, int64, error) {
db := database.GetDB()
var subjects []models.SubjectSummary
var total int64
likeQuery := "%" + query + "%"

query = "%" + strings.TrimSpace(query) + "%"
err := db.Table("subject").
Where("title LIKE ?", query).
Find(&subjects).
Count(&total).Error
if err != nil {
return nil, 0, err
cacheSearchKey := fmt.Sprintf("search:%s:%d", query, page)
cacheCountKey := fmt.Sprintf("count:search:%s", query)

if cachedCounts, found := cache.GetCache(cacheCountKey); found {
total = cachedCounts.(int64)
} else {
err := db.Table("subject").
Where("title LIKE ?", likeQuery).
Count(&total).Error
if err != nil {
return nil, 0, err
}
cache.SetCache(cacheCountKey, total, 10*time.Minute)
}

if cachedSubjects, found := cache.GetCache(cacheSearchKey); found {
subjects = cachedSubjects.([]models.SubjectSummary)
} else {
offset := (page - 1) * pageSize
err := db.Table("subject").
Where("title LIKE ?", likeQuery).
Offset(offset).
Limit(pageSize).
Find(&subjects).Error
if err != nil {
return nil, 0, err
}
cache.SetCache(cacheSearchKey, subjects, 10*time.Minute)
}

return subjects, total, nil
Expand Down
12 changes: 8 additions & 4 deletions models/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,19 @@ type CategoryView struct {
Category string
Status int
StatusCounts StatusCounts
Page int
CurrentPage int
TotalPages int
Subjects []CategoryViewItem
}

type SearchView struct {
PageTitle string
TotalCount int64
Subjects []CategoryViewItem
PageTitle string
Query string
QueryType string
TotalCount int64
CurrentPage int
TotalPages int
Subjects []CategoryViewItem
}

type HomeViewItem struct {
Expand Down
2 changes: 1 addition & 1 deletion models/subject.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type Subject struct {
ID uint `gorm:"primaryKey;index:idx_type_status_id;column:id"`
UUID string `gorm:"size:36;unique;column:uuid"`
SubjectType string `gorm:"size:16;index:idx_type_status_id;column:subject_type"`
Title string `gorm:"size:255;column:title"`
Title string `gorm:"size:255;index:idx_title;column:title"`
AltTitle string `gorm:"size:255;column:alt_title"`
Creator string `gorm:"size:512;column:creator"`
Press string `gorm:"size:255;column:press"`
Expand Down
4 changes: 2 additions & 2 deletions routes/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ func handleCategory(w http.ResponseWriter, r *http.Request) {
Category: category,
Status: status,
StatusCounts: statusCounts,
Page: page,
Subjects: processCategoryHTML(subjects),
CurrentPage: page,
TotalPages: totalPages,
Subjects: processCategoryHTML(subjects),
}

renderPage(w, "category.html", data)
Expand Down
52 changes: 45 additions & 7 deletions routes/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,69 @@ package routes

import (
"fmt"
"math"
"net/http"
"strings"

"github.com/scenery/mediax/config"
"github.com/scenery/mediax/handlers"
"github.com/scenery/mediax/helpers"
"github.com/scenery/mediax/models"
)

func handleSearch(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
query := strings.TrimSpace(r.URL.Query().Get("q"))
if len(query) < 4 || len(query) > 32 {
errorMessage := "search keyword must be between 4 and 32 characters (2 至 16 个汉字)"
targetURL := "home"
handleError(w, errorMessage, targetURL, 302)
handleError(w, errorMessage, "home", 302)
return
}

subjects, total, err := handlers.GetSearchResult(query)
validType := map[string]bool{
"all": true,
"book": true,
"movie": true,
"tv": true,
"anime": true,
"game": true,
}
subjectType := r.URL.Query().Get("subject_type")
if !validType[subjectType] {
handleError(w, "Invalid subject type", "home", 400)
return
}

pageSize := config.PageSize
page, err := helpers.StringToInt(r.URL.Query().Get("page"))
if err != nil || page < 1 {
page = 1
}

subjects, total, err := handlers.GetSearchResult(query, page, pageSize)
if err != nil {
handleError(w, fmt.Sprint(err), "add", 500)
return
}

if subjectType != "all" {
var filteredSubjects []models.SubjectSummary
for _, subject := range subjects {
if subject.SubjectType == subjectType {
filteredSubjects = append(filteredSubjects, subject)
}
}
subjects = filteredSubjects
total = int64(len(filteredSubjects))
}

data := models.SearchView{
PageTitle: "搜索结果 " + query,
TotalCount: total,
Subjects: processCategoryHTML(subjects),
PageTitle: "搜索结果 " + query,
Query: query,
QueryType: subjectType,
TotalCount: total,
CurrentPage: page,
TotalPages: int(math.Ceil(float64(total) / float64(pageSize))),
Subjects: processCategoryHTML(subjects),
}

renderPage(w, "search.html", data)
Expand Down
Loading

0 comments on commit 840f8ba

Please sign in to comment.