mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 04:17:23 +00:00
Improve search
This commit is contained in:
@@ -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) {
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
|
Reference in New Issue
Block a user