refactor: remove Gorse integration and implement HotRank feature
- Removed Gorse-related configurations, handlers, and dependencies from the codebase. - Introduced HotRank feature with configuration options for ranking posts based on recent activity. - Updated application structure to support HotRank processing, including new caching mechanisms and database interactions. - Cleaned up related DTOs and repository methods to reflect the removal of Gorse and the addition of HotRank functionality.
This commit is contained in:
11
internal/cache/cache.go
vendored
11
internal/cache/cache.go
vendored
@@ -8,6 +8,8 @@ import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var ErrKeyNotFound = errors.New("key not found")
|
||||
@@ -52,6 +54,10 @@ type Cache interface {
|
||||
ZRangeByScore(ctx context.Context, key string, min, max string, offset, count int64) ([]string, error)
|
||||
// ZRevRangeByScore 按分数范围获取成员(降序)
|
||||
ZRevRangeByScore(ctx context.Context, key string, max, min string, offset, count int64) ([]string, error)
|
||||
// ZRevRange 按排名倒序取成员(score 从高到低,start/stop 为排名下标,含端点)
|
||||
ZRevRange(ctx context.Context, key string, start, stop int64) ([]string, error)
|
||||
// ZReplaceSortedSet 原子替换整个 ZSET(先删后批量写入)
|
||||
ZReplaceSortedSet(ctx context.Context, key string, members []redis.Z) error
|
||||
// ZRem 删除 Sorted Set 成员
|
||||
ZRem(ctx context.Context, key string, members ...interface{}) error
|
||||
// ZCard 获取 Sorted Set 成员数量
|
||||
@@ -130,6 +136,11 @@ func normalizeKey(key string) string {
|
||||
return cmp.Or(settings.KeyPrefix, "") + ":" + key
|
||||
}
|
||||
|
||||
// ResolveKey 返回带全局前缀的实际 Redis 键(供需直连 Redis 的组件使用)
|
||||
func ResolveKey(key string) string {
|
||||
return normalizeKey(key)
|
||||
}
|
||||
|
||||
func normalizePrefix(prefix string) string {
|
||||
return cmp.Or(settings.KeyPrefix, "") + ":" + prefix
|
||||
}
|
||||
|
||||
16
internal/cache/keys.go
vendored
16
internal/cache/keys.go
vendored
@@ -9,6 +9,10 @@ const (
|
||||
// 帖子相关
|
||||
PrefixPostList = "posts:list"
|
||||
PrefixPost = "posts:detail"
|
||||
// HotRankZSet 热门榜(有序集合,member=post_id,score=归一化热度,仅存 TopN)
|
||||
HotRankZSet = "posts:hot:zset"
|
||||
// HotRankTopIDs 热门榜有序 post_id 列表(JSON []string,供分层缓存本地层命中)
|
||||
HotRankTopIDs = "posts:hot:top_ids"
|
||||
|
||||
// 会话相关
|
||||
PrefixConversationList = "conversations:list"
|
||||
@@ -36,10 +40,20 @@ const (
|
||||
)
|
||||
|
||||
// PostListKey 生成帖子列表缓存键
|
||||
// postType: 帖子类型 (recommend, hot, follow, latest)
|
||||
// postType: 帖子类型 (hot, follow, latest)
|
||||
// page: 页码
|
||||
// pageSize: 每页数量
|
||||
// userID: 用户维度(仅在个性化列表如 follow 场景使用)
|
||||
// HotRankZSetKey 热门榜 Redis ZSET 逻辑键(仅存 TopN,会经 normalizeKey 加前缀)
|
||||
func HotRankZSetKey() string {
|
||||
return HotRankZSet
|
||||
}
|
||||
|
||||
// HotRankTopIDsKey 热门榜 Top 顺序 ID 列表键(会经 normalizeKey 加前缀)
|
||||
func HotRankTopIDsKey() string {
|
||||
return HotRankTopIDs
|
||||
}
|
||||
|
||||
func PostListKey(postType string, userID string, page, pageSize int) string {
|
||||
if userID == "" {
|
||||
return fmt.Sprintf("%s:%s:%d:%d", PrefixPostList, postType, page, pageSize)
|
||||
|
||||
16
internal/cache/layered_cache.go
vendored
16
internal/cache/layered_cache.go
vendored
@@ -7,6 +7,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
redislib "github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
|
||||
redisPkg "carrot_bbs/internal/pkg/redis"
|
||||
@@ -294,6 +295,21 @@ func (c *LayeredCache) ZRevRangeByScore(ctx context.Context, key string, max, mi
|
||||
return c.redis.ZRevRangeByScore(ctx, key, max, min, offset, count)
|
||||
}
|
||||
|
||||
func (c *LayeredCache) ZRevRange(ctx context.Context, key string, start, stop int64) ([]string, error) {
|
||||
if !c.enabled || c.redis == nil {
|
||||
return nil, ErrKeyNotFound
|
||||
}
|
||||
return c.redis.ZRevRange(ctx, key, start, stop)
|
||||
}
|
||||
|
||||
func (c *LayeredCache) ZReplaceSortedSet(ctx context.Context, key string, members []redislib.Z) error {
|
||||
if !c.enabled || c.redis == nil {
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
c.local.Delete(key)
|
||||
return c.redis.ZReplaceSortedSet(ctx, key, members)
|
||||
}
|
||||
|
||||
func (c *LayeredCache) ZRem(ctx context.Context, key string, members ...any) error {
|
||||
if !c.enabled || c.redis == nil {
|
||||
return nil
|
||||
|
||||
23
internal/cache/redis_cache.go
vendored
23
internal/cache/redis_cache.go
vendored
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
redislib "github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
|
||||
redisPkg "carrot_bbs/internal/pkg/redis"
|
||||
@@ -53,7 +53,7 @@ func (c *RedisCache) Get(key string) (interface{}, bool) {
|
||||
key = normalizeKey(key)
|
||||
data, err := c.client.Get(c.ctx, key)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
if err == redislib.Nil {
|
||||
return nil, false
|
||||
}
|
||||
zap.L().Error("Failed to get key",
|
||||
@@ -219,6 +219,25 @@ func (c *RedisCache) ZRevRangeByScore(ctx context.Context, key string, max, min
|
||||
return c.client.ZRevRangeByScore(ctx, key, max, min, offset, count)
|
||||
}
|
||||
|
||||
// ZRevRange 按排名倒序获取成员
|
||||
func (c *RedisCache) ZRevRange(ctx context.Context, key string, start, stop int64) ([]string, error) {
|
||||
key = normalizeKey(key)
|
||||
return c.client.ZRevRange(ctx, key, start, stop)
|
||||
}
|
||||
|
||||
// ZReplaceSortedSet 删除后整表重写 ZSET
|
||||
func (c *RedisCache) ZReplaceSortedSet(ctx context.Context, key string, members []redislib.Z) error {
|
||||
key = normalizeKey(key)
|
||||
rdb := c.client.GetClient()
|
||||
if err := rdb.Del(ctx, key).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(members) == 0 {
|
||||
return nil
|
||||
}
|
||||
return c.client.ZAddArgs(ctx, key, members...)
|
||||
}
|
||||
|
||||
// ZRem 删除 Sorted Set 成员
|
||||
func (c *RedisCache) ZRem(ctx context.Context, key string, members ...interface{}) error {
|
||||
key = normalizeKey(key)
|
||||
|
||||
Reference in New Issue
Block a user