Files
nysoure/server/search/resource.go
2025-12-06 16:32:32 +08:00

154 lines
3.0 KiB
Go

package search
import (
"errors"
"fmt"
"nysoure/server/dao"
"nysoure/server/model"
"nysoure/server/utils"
"os"
"strconv"
"sync"
"time"
"github.com/blevesearch/bleve"
)
var (
index bleve.Index
mu = sync.RWMutex{}
)
type ResourceParams struct {
Id uint
Title string
Subtitles []string
Time time.Time
Characters []ResourceCharacter
}
type ResourceCharacter struct {
Name string
Alias []string
CV string
}
func AddResourceToIndex(r model.Resource) error {
mu.RLock()
defer mu.RUnlock()
cs := make([]ResourceCharacter, 0, len(r.Characters))
for _, c := range r.Characters {
cs = append(cs, ResourceCharacter{
Name: c.Name,
Alias: c.Alias,
CV: c.CV,
})
}
return index.Index(fmt.Sprintf("%d", r.ID), ResourceParams{
Id: r.ID,
Title: r.Title,
Subtitles: r.AlternativeTitles,
Time: r.CreatedAt,
Characters: cs,
})
}
func RemoveResourceFromIndex(id uint) error {
return index.Delete(fmt.Sprintf("%d", id))
}
func createIndex() error {
for !dao.IsReady() {
time.Sleep(1 * time.Second)
}
page := 1
total := 1
for page <= total {
res, totalPages, err := dao.GetResourceList(page, 100, model.RSortTimeAsc)
if err != nil {
return err
}
for _, r := range res {
err := AddResourceToIndex(r)
if err != nil {
return err
}
}
page++
total = totalPages
}
return nil
}
func init() {
indexPath := utils.GetStoragePath() + "/resource_index.bleve"
var err error
index, err = bleve.Open(indexPath)
if errors.Is(err, bleve.ErrorIndexPathDoesNotExist) {
mapping := bleve.NewIndexMapping()
index, err = bleve.New(indexPath, mapping)
if err != nil {
panic("Failed to create search index: " + err.Error())
}
go func() {
err := createIndex()
if err != nil {
panic("Failed to create search index: " + err.Error())
}
}()
} else if err != nil {
panic("Failed to open search index: " + err.Error())
}
}
func SearchResource(keyword string) ([]uint, error) {
mu.RLock()
defer mu.RUnlock()
query := bleve.NewMatchQuery(keyword)
searchRequest := bleve.NewSearchRequest(query)
searchResults, err := index.Search(searchRequest)
if err != nil {
return nil, err
}
results := make([]uint, 0)
for _, hit := range searchResults.Hits {
if hit.Score < 0.2 {
break
}
id, err := strconv.ParseUint(hit.ID, 10, 32)
if err != nil {
continue
}
results = append(results, uint(id))
}
return results, nil
}
func IsStopWord(word string) bool {
mapping := bleve.NewIndexMapping()
analyzerName := mapping.DefaultAnalyzer
analyzer := mapping.AnalyzerNamed(analyzerName)
if analyzer == nil {
return false
}
tokens := analyzer.Analyze([]byte(word))
return len(tokens) == 0
}
func RebuildSearchIndex() error {
mu.Lock()
defer mu.Unlock()
err := index.Close()
if err != nil {
return fmt.Errorf("failed to close search index: %w", err)
}
err = os.Remove(utils.GetStoragePath() + "/resource_index.bleve")
if err != nil {
return fmt.Errorf("failed to remove search index: %w", err)
}
return createIndex()
}