Files
go_process_manager/internal/app/search/bleve/bleve.go
2025-08-29 16:25:43 +08:00

168 lines
4.5 KiB
Go

//go:build !slim
// +build !slim
package bleve
import (
"time"
"github.com/blevesearch/bleve/v2"
"github.com/blevesearch/bleve/v2/search"
_ "github.com/blevesearch/bleve/v2/search/highlight/highlighter/ansi"
"github.com/google/uuid"
"github.com/lzh-1625/go_process_manager/internal/app/model"
sr "github.com/lzh-1625/go_process_manager/internal/app/search"
logger "github.com/lzh-1625/go_process_manager/log"
gse "github.com/vcaesar/gse-bleve"
// gse "github.com/lzh-1625/gse-bleve"
)
func init() {
sr.Register("bleve", new(bleveSearch))
}
type bleveSearch struct {
index bleve.Index
}
func (b *bleveSearch) Init() error {
opt := gse.Option{
Dicts: "embed, zh_s",
Stop: "",
Opt: "search-hmm",
Trim: "trim",
}
indexMapping, err := gse.NewMapping(opt)
if err != nil {
logger.Logger.Errorw("bleve init fail", "err", err)
return err
}
mapping := bleve.NewDocumentMapping()
log := bleve.NewTextFieldMapping()
log.Index = true
time := bleve.NewNumericFieldMapping()
time.Index = true
name := bleve.NewKeywordFieldMapping()
name.Index = true
using := bleve.NewKeywordFieldMapping()
using.Index = true
mapping.AddFieldMappingsAt("log", log)
mapping.AddFieldMappingsAt("time", time)
mapping.AddFieldMappingsAt("name", name)
mapping.AddFieldMappingsAt("using", using)
indexMapping.AddDocumentMapping("server_log_v1", mapping)
index, err := bleve.Open("log.bleve")
if err != nil {
index, err = bleve.New("log.bleve", indexMapping)
if err != nil {
logger.Logger.Errorw("bleve init error", "err", err)
return err
}
}
b.index = index
return nil
}
func (b *bleveSearch) Insert(logContent string, processName string, using string, ts int64) {
if err := b.index.Index(uuid.NewString(), model.ProcessLog{
Log: logContent,
Name: processName,
Using: using,
Time: ts,
}); err != nil {
logger.Logger.Warnw("bleve log insert failed", "err", err)
}
}
func (b *bleveSearch) Search(req model.GetLogReq, filterProcessName ...string) (result model.LogResp) {
buildQuery := bleve.NewBooleanQuery()
for _, v := range sr.QueryStringAnalysis(req.Match.Log) {
switch v.Cond {
case sr.Match, sr.WildCard:
logQuery := bleve.NewMatchQuery(v.Content)
logQuery.SetField("log")
buildQuery.AddMust(logQuery)
case sr.NotMatch, sr.NotWildCard:
logQuery := bleve.NewMatchQuery(v.Content)
logQuery.SetField("log")
buildQuery.AddMustNot(logQuery)
// case sr.WildCard:
// logQuery := bleve.NewWildcardQuery("*" + v.Content + "*")
// logQuery.SetField("log")
// buildQuery.AddMust(logQuery)
// case sr.NotWildCard:
// logQuery := bleve.NewWildcardQuery("*" + v.Content + "*")
// logQuery.SetField("log")
// buildQuery.AddMustNot(logQuery)
}
}
if req.Match.Name != "" {
nameQuery := bleve.NewTermQuery(req.Match.Name)
nameQuery.SetField("name")
buildQuery.AddMust(nameQuery)
}
if req.Match.Using != "" {
usingQuery := bleve.NewWildcardQuery("*" + req.Match.Using + "*")
usingQuery.SetField("using")
buildQuery.AddMust(usingQuery)
}
if req.TimeRange.EndTime != 0 || req.TimeRange.StartTime != 0 {
st := float64(req.TimeRange.StartTime)
et := float64(req.TimeRange.EndTime)
timeQuery := bleve.NewNumericRangeQuery(&st, &et)
buildQuery.AddMust(timeQuery)
} else {
st := float64(0)
et := float64(time.Now().UnixMilli())
timeQuery := bleve.NewNumericRangeQuery(&st, &et)
buildQuery.AddMust(timeQuery)
}
if len(filterProcessName) != 0 {
for _, v := range filterProcessName {
filterQuery := bleve.NewTermQuery(v)
filterQuery.SetField("name")
buildQuery.AddShould(filterQuery)
}
}
sortArgs := ([]string{"-_score"})
if req.Sort == "desc" {
sortArgs = ([]string{"-time"})
}
if req.Sort == "asc" {
sortArgs = ([]string{"time"})
}
hl := bleve.HighlightRequest{}
hl.AddField("log")
style := "ansi"
res, err := b.index.Search(&bleve.SearchRequest{
Query: buildQuery,
Fields: []string{"log", "name", "using", "time"},
From: req.Page.From,
Size: req.Page.Size,
Sort: search.ParseSortOrderStrings(sortArgs),
Highlight: &bleve.HighlightRequest{
Style: &style,
Fields: []string{"log"},
},
})
if err != nil {
logger.Logger.Warnw("bleve search failed", "err", err)
return
}
data := []*model.ProcessLog{}
for _, v := range res.Hits {
data = append(data, &model.ProcessLog{
Log: v.Fragments["log"][0],
Time: int64(v.Fields["time"].(float64)),
Using: v.Fields["using"].(string),
Name: v.Fields["name"].(string),
})
}
result.Data = data
result.Total = int64(res.Total)
return
}