Improve search

This commit is contained in:
2025-09-08 19:34:57 +08:00
parent b4a63d3935
commit 5fe45611c9
4 changed files with 71 additions and 69 deletions

View File

@@ -391,7 +391,7 @@ func RandomResource() (model.Resource, error) {
} }
} }
func GetResourcesIdWithTag(tagID uint) (map[uint]time.Time, error) { func GetResourcesIdWithTag(tagID uint) ([]uint, error) {
tag, err := GetTagByID(tagID) tag, err := GetTagByID(tagID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -422,11 +422,7 @@ func GetResourcesIdWithTag(tagID uint) (map[uint]time.Time, error) {
return nil, err return nil, err
} }
resMap := make(map[uint]time.Time) return tagIds, nil
for _, r := range result {
resMap[r.ID] = r.CreatedAt
}
return resMap, nil
} }
func BatchGetResources(ids []uint) ([]model.Resource, error) { func BatchGetResources(ids []uint) ([]model.Resource, error) {

View File

@@ -59,13 +59,18 @@ func init() {
if err != nil { if err != nil {
panic("Failed to create search index: " + err.Error()) panic("Failed to create search index: " + err.Error())
} }
go createIndex() go func() {
err := createIndex()
if err != nil {
panic("Failed to create search index: " + err.Error())
}
}()
} else if err != nil { } else if err != nil {
panic("Failed to open search index: " + err.Error()) panic("Failed to open search index: " + err.Error())
} }
} }
func SearchResource(keyword string) (map[uint]time.Time, error) { func SearchResource(keyword string) ([]uint, error) {
query := bleve.NewMatchQuery(keyword) query := bleve.NewMatchQuery(keyword)
searchRequest := bleve.NewSearchRequest(query) searchRequest := bleve.NewSearchRequest(query)
searchRequest.Size = 1000 searchRequest.Size = 1000
@@ -75,7 +80,7 @@ func SearchResource(keyword string) (map[uint]time.Time, error) {
return nil, err return nil, err
} }
results := make(map[uint]time.Time) results := make([]uint, 0)
for _, hit := range searchResults.Hits { for _, hit := range searchResults.Hits {
if hit.Score < 0.8 { if hit.Score < 0.8 {
continue continue
@@ -84,11 +89,7 @@ func SearchResource(keyword string) (map[uint]time.Time, error) {
if err != nil { if err != nil {
continue continue
} }
t, err := time.Parse(time.RFC3339Nano, hit.Fields["Time"].(string)) results = append(results, uint(id))
if err != nil {
continue
}
results[uint(id)] = t
} }
return results, nil return results, nil

View File

@@ -1,23 +1,24 @@
package service package service
import ( import (
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
"net/url" "net/url"
"nysoure/server/config" "nysoure/server/config"
"nysoure/server/dao" "nysoure/server/dao"
"nysoure/server/model" "nysoure/server/model"
"nysoure/server/search" "nysoure/server/search"
"nysoure/server/utils" "nysoure/server/utils"
"sort"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
"gorm.io/gorm" "gorm.io/gorm"
) )
const (
maxSearchQueryLength = 100
)
type ResourceParams struct { type ResourceParams struct {
Title string `json:"title" binding:"required"` Title string `json:"title" binding:"required"`
AlternativeTitles []string `json:"alternative_titles"` AlternativeTitles []string `json:"alternative_titles"`
@@ -208,9 +209,10 @@ func splitQuery(query string) []string {
return keywords return keywords
} }
func searchWithKeyword(keyword string) (map[uint]time.Time, error) { func searchWithKeyword(keyword string) ([]uint, error) {
resources := make(map[uint]time.Time) resources := make([]uint, 0)
if len([]rune(keyword)) <= maxTagLength {
exists, err := dao.ExistsTag(keyword) exists, err := dao.ExistsTag(keyword)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -224,8 +226,7 @@ func searchWithKeyword(keyword string) (map[uint]time.Time, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for id, createdAt := range res { resources = append(resources, res...)
resources[id] = createdAt
} }
} }
@@ -234,19 +235,24 @@ func searchWithKeyword(keyword string) (map[uint]time.Time, error) {
return nil, err return nil, err
} }
for id, createdAt := range searchResult { resources = append(resources, searchResult...)
resources[id] = createdAt
}
return resources, nil return resources, nil
} }
func SearchResource(query string, page int) ([]model.ResourceView, int, error) { func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
if len([]rune(query)) > maxSearchQueryLength {
return nil, 0, model.NewRequestError("Search query is too long")
}
start := (page - 1) * pageSize start := (page - 1) * pageSize
end := start + pageSize end := start + pageSize
resources := make(map[uint]time.Time) resources := make([]uint, 0)
checkTag := func(tag string) error { checkTag := func(tag string) error {
if len([]rune(tag)) > maxTagLength {
return nil
}
exists, err := dao.ExistsTag(tag) exists, err := dao.ExistsTag(tag)
if err != nil { if err != nil {
return err return err
@@ -260,9 +266,7 @@ func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
if err != nil { if err != nil {
return err return err
} }
for id, createdAt := range res { resources = append(resources, res...)
resources[id] = createdAt
}
} }
return nil return nil
} }
@@ -282,7 +286,7 @@ func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
// split query to search // split query to search
keywords := splitQuery(query) keywords := splitQuery(query)
temp := make(map[uint]time.Time) var temp []uint
first := true first := true
for _, keyword := range keywords { for _, keyword := range keywords {
if keyword == "" { if keyword == "" {
@@ -293,17 +297,31 @@ func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
return nil, 0, err return nil, 0, err
} }
if first { if first {
for id, createdAt := range res { for _, id := range res {
temp[id] = createdAt found := false
for _, id2 := range temp {
if id == id2 {
found = true
break
}
}
if !found {
temp = append(temp, id)
}
} }
first = false first = false
} else { } else {
for id := range temp { temp1 := make([]uint, 0)
if _, ok := res[id]; !ok { for _, id := range temp {
delete(temp, id) for _, id2 := range res {
if id == id2 {
temp1 = append(temp1, id)
break
} }
} }
} }
temp = temp1
}
} }
for id, createdAt := range temp { for id, createdAt := range temp {
resources[id] = createdAt resources[id] = createdAt
@@ -313,23 +331,7 @@ func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
return []model.ResourceView{}, 0, nil return []model.ResourceView{}, 0, nil
} }
type IDWithTime struct { total := len(resources)
ID uint
CreatedAt time.Time
}
var idsWithTime []IDWithTime
for id, createdAt := range resources {
idsWithTime = append(idsWithTime, IDWithTime{
ID: id,
CreatedAt: createdAt,
})
}
// sort by createdAt desc
sort.Slice(idsWithTime, func(i, j int) bool {
return idsWithTime[i].CreatedAt.After(idsWithTime[j].CreatedAt)
})
total := len(idsWithTime)
totalPages := (total + pageSize - 1) / pageSize totalPages := (total + pageSize - 1) / pageSize
if start >= total { if start >= total {
return []model.ResourceView{}, totalPages, nil return []model.ResourceView{}, totalPages, nil
@@ -337,13 +339,9 @@ func SearchResource(query string, page int) ([]model.ResourceView, int, error) {
if end > total { if end > total {
end = total end = total
} }
idsPage := idsWithTime[start:end] idsPage := resources[start:end]
var ids []uint
for _, item := range idsPage {
ids = append(ids, item.ID)
}
resourcesPage, err := dao.BatchGetResources(ids) resourcesPage, err := dao.BatchGetResources(idsPage)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }

View File

@@ -9,6 +9,10 @@ import (
"time" "time"
) )
const (
maxTagLength = 20
)
func init() { func init() {
// Start a goroutine to delete unused tags every hour // Start a goroutine to delete unused tags every hour
go func() { go func() {
@@ -25,6 +29,9 @@ func init() {
} }
func CreateTag(uid uint, name string) (*model.TagView, error) { func CreateTag(uid uint, name string) (*model.TagView, error) {
if len([]rune(name)) > maxTagLength {
return nil, model.NewRequestError("Tag name too long")
}
canUpload, err := checkUserCanUpload(uid) canUpload, err := checkUserCanUpload(uid)
if err != nil { if err != nil {
log.Error("Error checking user permissions:", err) log.Error("Error checking user permissions:", err)