package hotsearchmod import ( "context" "fmt" "hkdj-web-server/pub/common/log" "hkdj-web-server/pub/common/srvdef" "hkdj-web-server/pub/mongos" "strings" "time" "unicode" "unicode/utf8" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) var db *mongos.Collection func Init(ctx context.Context) { db = mongos.Shop.Coll(TN.HotSearch) indexes := []mongo.IndexModel{ { Keys: bson.D{{Key: FN.HotSearch.Keyword, Value: 1}}, Options: options.Index().SetUnique(true), }, { Keys: bson.D{ {Key: FN.HotSearch.Count, Value: -1}, {Key: FN.HotSearch.UpdatedAt, Value: -1}, }, }, } if _, err := db.CreateIndex(ctx, indexes); err != nil { panic(fmt.Sprintf("(hotsearchmod:Init) Create HotSearch Index failed! err:%+v:", err)) } } // NormalizeKeyword 去掉首尾空白、压缩中间空格,并限制长度。 func NormalizeKeyword(raw string) string { raw = strings.TrimSpace(raw) if raw == "" { return "" } fields := strings.FieldsFunc(raw, unicode.IsSpace) raw = strings.Join(fields, " ") if utf8.RuneCountInString(raw) > MaxKeywordRunes { raw = string([]rune(raw)[:MaxKeywordRunes]) } return raw } // IncrByKeyword 按搜索词累加次数,不存在则插入。 func IncrByKeyword(ctx context.Context, keyword string) *srvdef.SrvErr { keyword = NormalizeKeyword(keyword) if keyword == "" { return nil } now := time.Now() filter := bson.M{FN.HotSearch.Keyword: keyword} update := bson.M{ "$inc": bson.M{FN.HotSearch.Count: 1}, "$set": bson.M{FN.HotSearch.UpdatedAt: now}, "$setOnInsert": bson.M{ FN.HotSearch.Id: mongos.Lid.HotSearch.Get(), FN.HotSearch.Keyword: keyword, FN.HotSearch.CreatedAt: now, }, } if _, err := db.UpsertOne(ctx, filter, update); err != nil { if _, retryErr := db.UpdateOne(ctx, filter, bson.M{ "$inc": bson.M{FN.HotSearch.Count: 1}, "$set": bson.M{FN.HotSearch.UpdatedAt: now}, }); retryErr != nil { log.Warn("hotsearchmod:IncrByKeyword failed", log.E(err), log.E(retryErr), log.Any("keyword", keyword)) return srvdef.New(srvdef.ErrDbUpdateError, "", "") } } return nil } func FindTopHotSearch(ctx context.Context, limit int64) (HotSearchList, *srvdef.SrvErr) { if limit <= 0 { limit = TopLimit } opts := options.Find(). SetSort(bson.D{ {Key: FN.HotSearch.Count, Value: -1}, {Key: FN.HotSearch.UpdatedAt, Value: -1}, {Key: FN.HotSearch.Id, Value: -1}, }). SetLimit(limit). SetProjection(bson.D{ {Key: FN.HotSearch.Id, Value: 1}, {Key: FN.HotSearch.Keyword, Value: 1}, {Key: FN.HotSearch.Count, Value: 1}, }) data := make(HotSearchList, 0) if err := db.Find(ctx, &data, bson.M{}, opts); err != nil { log.Warn("hotsearchmod:FindTopHotSearch db.Find failed", log.E(err)) return nil, srvdef.New(srvdef.ErrDbQueryError, "", "") } return data, nil }