✨ finish #2 prefer mode with redis
This commit is contained in:
parent
4d2f304ab7
commit
6f97245961
@ -7,11 +7,13 @@ import (
|
|||||||
"catface/app/http/validator/core/data_transfer"
|
"catface/app/http/validator/core/data_transfer"
|
||||||
"catface/app/model"
|
"catface/app/model"
|
||||||
"catface/app/model_es"
|
"catface/app/model_es"
|
||||||
|
"catface/app/model_redis"
|
||||||
"catface/app/service/animals/curd"
|
"catface/app/service/animals/curd"
|
||||||
"catface/app/service/upload_file"
|
"catface/app/service/upload_file"
|
||||||
"catface/app/utils/query_handler"
|
"catface/app/utils/query_handler"
|
||||||
"catface/app/utils/redis_factory"
|
"catface/app/utils/redis_factory"
|
||||||
"catface/app/utils/response"
|
"catface/app/utils/response"
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -37,37 +39,45 @@ func (a *Animals) List(context *gin.Context) {
|
|||||||
mode := context.GetString(consts.ValidatorPrefix + "mode")
|
mode := context.GetString(consts.ValidatorPrefix + "mode")
|
||||||
|
|
||||||
// TAG prefer MODE 查询模式。
|
// TAG prefer MODE 查询模式。
|
||||||
var redis_preferCatsId []int64
|
|
||||||
var key int64
|
var key int64
|
||||||
|
var redis_selctedCatsId model_redis.SelectedAnimal4Prefer
|
||||||
var animalsWithLike []model.AnimalWithLikeList
|
var animalsWithLike []model.AnimalWithLikeList
|
||||||
if mode == consts.AnimalPreferMode {
|
if mode == consts.AnimalPreferMode {
|
||||||
key = int64(context.GetFloat64(consts.ValidatorPrefix + "key"))
|
key = int64(context.GetFloat64(consts.ValidatorPrefix + "key"))
|
||||||
|
redis_selctedCatsId.Key = key
|
||||||
|
|
||||||
redisClient := redis_factory.GetOneRedisClient()
|
redisClient := redis_factory.GetOneRedisClient()
|
||||||
defer redisClient.ReleaseOneRedisClient()
|
defer redisClient.ReleaseOneRedisClient()
|
||||||
if key != 0 {
|
if key != 0 {
|
||||||
redis_preferCatsId, _ = redisClient.Int64sFromList(redisClient.Execute("lrange", key, 0, -1))
|
if res, err := redisClient.String(redisClient.Execute("get", key)); err == nil {
|
||||||
|
json.Unmarshal([]byte(res), &redis_selctedCatsId)
|
||||||
|
} else {
|
||||||
|
_ = err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
key = variable.SnowFlake.GetId()
|
key = variable.SnowFlake.GetId()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(redis_preferCatsId) == skip {
|
if redis_selctedCatsId.Length() == skip {
|
||||||
preferCatsId, preferCats, _ := getPreferCatsId(int(userId), num, skip, attrs)
|
preferCats, _ := getPreferCats(int(userId), num, attrs, &redis_selctedCatsId)
|
||||||
if len(preferCatsId) > 0 {
|
if len(preferCats) > 0 {
|
||||||
redis_preferCatsId = append(redis_preferCatsId, preferCatsId...)
|
animalsWithLike = preferCats
|
||||||
animalsWithLike = append(animalsWithLike, preferCats...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := redisClient.String(redisClient.Execute("lpush", key, redis_preferCatsId)); err != nil {
|
// TODO 刷新 Redis 有效期
|
||||||
|
if value, err := json.Marshal(redis_selctedCatsId); err == nil {
|
||||||
|
if _, err := redisClient.String(redisClient.Execute("set", key, string(value))); err != nil {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算还需要多少动物
|
// 计算还需要多少毛茸茸
|
||||||
num -= len(animalsWithLike)
|
num -= len(animalsWithLike)
|
||||||
skip = max(0, skip-len(redis_preferCatsId))
|
skip = max(0, skip-redis_selctedCatsId.Length())
|
||||||
if num > 0 {
|
if num > 0 {
|
||||||
additionalAnimals := curd.CreateAnimalsCurdFactory().List(attrs, gender, breed, sterilization, status, department, redis_preferCatsId, num, skip, int(userId))
|
additionalAnimals := curd.CreateAnimalsCurdFactory().List(attrs, gender, breed, sterilization, status, department, redis_selctedCatsId.GetAllIds(), num, skip, int(userId))
|
||||||
// 将 additionalAnimals 整合到 animalsWithLike 的后面
|
// 将 additionalAnimals 整合到 animalsWithLike 的后面
|
||||||
animalsWithLike = append(animalsWithLike, additionalAnimals...)
|
animalsWithLike = append(animalsWithLike, additionalAnimals...)
|
||||||
}
|
}
|
||||||
@ -82,10 +92,43 @@ func (a *Animals) List(context *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UPDATE 就先简单一些,主要就依靠 encounter - animal_id 来获取一个目标。
|
/**
|
||||||
func getPreferCatsId(userId, num, skip int, attrs string) (ids []int64, list []model.AnimalWithLikeList, err error) {
|
* @description: 在常规条件过滤查询之前,通过一定规则获取偏好的目标。
|
||||||
// STAGE - 1 模块一,无视过滤条件,获取路遇“过”的 id 列表;先获取 ID,然后再去查询细节信息。
|
* @param {*} userId
|
||||||
ids, err = model.CreateEncounterFactory("").EncounteredCats(userId, num, skip)
|
* @param {int} num
|
||||||
|
* @param {string} attrs
|
||||||
|
* @param {model_redis.SelectedAnimal4Prefer} redis 使用单独的结构体,更清晰的控制中间状态。
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
func getPreferCats(userId, num int, attrs string, redis *model_redis.SelectedAnimal4Prefer) (list []model.AnimalWithLikeList, err error) {
|
||||||
|
// STAGE #1 无视过滤条件,获取路遇“过”的 id 列表;先获取 ID,然后再去查询细节信息。
|
||||||
|
ids, err := model.CreateEncounterFactory("").EncounteredCatsId(userId, num, redis.NumEnc(), redis.NewCatsId)
|
||||||
|
|
||||||
|
// STAGE #2 获取近期新增的毛茸茸;只在第一次操作 && 数量不够时 启用。
|
||||||
|
var idsNew []int64
|
||||||
|
if !redis.PassNew() && len(ids) < num {
|
||||||
|
// 获取近期新增的毛茸茸
|
||||||
|
newCats, _ := model.CreateAnimalFactory("").NewCatsId(3, 0) // INFO 硬编码获取最新的 3 个。
|
||||||
|
|
||||||
|
// 去重:默认只会在首次查询时启用,所以只需要去重 STAGE#1 的 ids。
|
||||||
|
uniqueIds := make(map[int64]bool)
|
||||||
|
for _, id := range ids {
|
||||||
|
uniqueIds[id] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range newCats {
|
||||||
|
if _, ok := uniqueIds[id]; !ok {
|
||||||
|
idsNew = append(idsNew, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 合并然后查询数据 && 处理 redis 之间的处理。
|
||||||
|
redis.AppendEncIds(ids)
|
||||||
|
if len(idsNew) > 0 {
|
||||||
|
ids = append(ids, idsNew...)
|
||||||
|
redis.NewCatsId = idsNew
|
||||||
|
}
|
||||||
|
|
||||||
if err == nil && len(ids) > 0 {
|
if err == nil && len(ids) > 0 {
|
||||||
attrsSlice := query_handler.StringToStringArray(attrs)
|
attrsSlice := query_handler.StringToStringArray(attrs)
|
||||||
|
@ -134,3 +134,9 @@ func (a *Animal) InsertDate(c *gin.Context) (tmp Animal, ok bool) {
|
|||||||
}
|
}
|
||||||
return tmp, false
|
return tmp, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Animal) NewCatsId(num, skip int) (temp []int64, err error) {
|
||||||
|
db := a.DB.Table(a.TableName()).Limit(int(num)).Offset(int(skip)).Select("id")
|
||||||
|
err = db.Order("updated_at DESC").Find(&temp).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -179,7 +179,7 @@ func (e *Encounter) ShowByIDs(ids []int64, attrs ...string) (temp []Encounter) {
|
|||||||
* @param {int} num 限制查询的数量;
|
* @param {int} num 限制查询的数量;
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
func (e *Encounter) EncounteredCats(user_id, num, skip int) ([]int64, error) {
|
func (e *Encounter) EncounteredCatsId(user_id, num, skip int, notInIds []int64) ([]int64, error) {
|
||||||
sql := `SELECT DISTINCT eal.animal_id
|
sql := `SELECT DISTINCT eal.animal_id
|
||||||
FROM encounter_animal_links eal
|
FROM encounter_animal_links eal
|
||||||
JOIN encounters e
|
JOIN encounters e
|
||||||
|
31
app/model_redis/selectedAnimal4Prefer.go
Normal file
31
app/model_redis/selectedAnimal4Prefer.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package model_redis
|
||||||
|
|
||||||
|
// INFO 辅助 animal - list - prefer 模式下的查询特化。
|
||||||
|
|
||||||
|
type SelectedAnimal4Prefer struct {
|
||||||
|
Key int64 `json:"-"` // redis 的 key 值
|
||||||
|
EncounteredCatsId []int64 `json:"encountered_cats_id"` // #1 对应第一阶段:近期路遇关联
|
||||||
|
NewCatsId []int64 `json:"new_cats_id"` // #2 对应第二阶段:近期新增
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectedAnimal4Prefer) PassNew() bool {
|
||||||
|
return s.Key != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectedAnimal4Prefer) Length() int {
|
||||||
|
return len(s.NewCatsId) + len(s.EncounteredCatsId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectedAnimal4Prefer) NumEnc() int {
|
||||||
|
return len(s.EncounteredCatsId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectedAnimal4Prefer) GetAllIds() []int64 {
|
||||||
|
return append(s.EncounteredCatsId, s.NewCatsId...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectedAnimal4Prefer) AppendEncIds(ids []int64) {
|
||||||
|
for _, id := range ids {
|
||||||
|
s.EncounteredCatsId = append(s.EncounteredCatsId, int64(id))
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,10 @@ package test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"catface/app/global/variable"
|
"catface/app/global/variable"
|
||||||
|
"catface/app/model_redis"
|
||||||
"catface/app/utils/redis_factory"
|
"catface/app/utils/redis_factory"
|
||||||
_ "catface/bootstrap"
|
_ "catface/bootstrap"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -170,3 +172,30 @@ func TestRedisList(t *testing.T) {
|
|||||||
t.Logf("单元测试通过,%v\n", res)
|
t.Logf("单元测试通过,%v\n", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试 struct 处理 By Json
|
||||||
|
func TestStruct(t *testing.T) {
|
||||||
|
redisClient := redis_factory.GetOneRedisClient()
|
||||||
|
defer redisClient.ReleaseOneRedisClient()
|
||||||
|
|
||||||
|
tmp := model_redis.SelectedAnimal4Prefer{
|
||||||
|
Key: 2,
|
||||||
|
NewCatsId: []int64{1, 2},
|
||||||
|
EncounteredCatsId: []int64{3, 4},
|
||||||
|
}
|
||||||
|
|
||||||
|
key := variable.SnowFlake.GetId()
|
||||||
|
value, _ := json.Marshal(tmp)
|
||||||
|
t.Log(value)
|
||||||
|
_, err := redisClient.String(redisClient.Execute("set", key, string(value)))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("单元测试失败,%s\n", err.Error())
|
||||||
|
}
|
||||||
|
if res, err := redisClient.String(redisClient.Execute("get", key)); err != nil {
|
||||||
|
t.Errorf("单元测试失败,%s\n", err.Error())
|
||||||
|
} else {
|
||||||
|
var tmp2 model_redis.SelectedAnimal4Prefer
|
||||||
|
json.Unmarshal([]byte(res), &tmp2)
|
||||||
|
t.Logf("单元测试通过,%v %v %v\n", tmp2, tmp2.NewCatsId, tmp2.EncounteredCatsId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user