init: web_hgcg_server 初始化提交

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 16:44:55 +08:00
co-authored by Claude Opus 4.7
commit 189556e702
627 changed files with 126228 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
package esmod
import (
"context"
"time"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
FiveMinuteScale = 5 //对齐时间(分钟)
)
var (
playletIndex = "web91djweb_playlet_index_v1"
)
func GetPlayletIndex() string {
return playletIndex
}
func GetRecordByESIndex(ctx context.Context, esIndex string) (
*ESTimestamp, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return &esRecord.Timestamp, nil
}
func SetOneEsRecord(ctx context.Context, esIndex string,
timestamp *ESTimestamp) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.Timestamp.T: timestamp.T,
FN.ESRecord.Timestamp.I: timestamp.I,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+181
View File
@@ -0,0 +1,181 @@
package esmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/esmanager"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
// Init 初始化数据
func Init(ctx context.Context) {
initDBIndex(ctx)
initIndex()
return
}
// initIndex 初始化索引
func initIndex() {
if esmanager.Instance == nil {
return
}
initPlayletIndex(playletIndex)
}
// initDBIndex 初始化数据库索引
func initDBIndex(ctx context.Context) {
//获取数据库表
db = mongos.Shop.Coll(TN.ESRecord)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ESRecord.EsIndex, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(esmod:initDBIndex) Create es_record Index failed! err:%+v:", err))
}
}
func initPlayletIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESPlaylet.Id: esmanager.M{
"type": "long",
},
FN.ESPlaylet.Status: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.IsFeatured: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.IsRecommend: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.OperateType: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.ShowOnBanner: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.Banner: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.OnlineAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.ThemeIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.ThemeNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Title: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Description: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.Slug: esmanager.M{
"type": "keyword",
},
FN.ESPlaylet.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Anchor: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Cover: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.TagIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.TagNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.TotalEpisode: esmanager.M{
"type": "long",
},
FN.ESPlaylet.UpdateStatus: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.CountBrowse: esmanager.M{
"type": "long",
},
FN.ESPlaylet.HeatValue: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountCollect: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountLike: esmanager.M{
"type": "long",
},
FN.ESPlaylet.UpdatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.CreatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.SeoInfo: esmanager.M{
"properties": esmanager.M{
"title": esmanager.M{
"type": "keyword",
"index": false,
},
"keyworld": esmanager.M{
"type": "keyword",
"index": false,
},
"description": esmanager.M{
"type": "keyword",
"index": false,
},
},
},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
log.Warn("初始化短剧ES索引失败,跳过索引创建", log.Any("索引", esIndex), log.E(err))
}
}
+144
View File
@@ -0,0 +1,144 @@
package esmod
import (
"context"
"go.mongodb.org/mongo-driver/bson/primitive"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// InsertOneESRecord 插入ES操作记录
func InsertOneESRecord(ctx context.Context, esRecord *ESRecord) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, esRecord); err != nil {
log.Warn("esmod:InsertOneESRecord db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneESRecord 删除一个ES操作记录
func DelOneESRecord(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("esmod:DelOnAppTag db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneESRecord 查找一个ES操作记录
func FindOneESRecord(ctx context.Context, filter bson.M) (
*ESRecord, *srvdef.SrvErr) {
var esRecord ESRecord
if err := db.FindOneEx(
ctx, &esRecord, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("esmod:FindOnESRecord db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &esRecord, nil
}
// CountESRecords 统计ES操作记录
func CountESRecords(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("esmod:CountMediaCats db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneESRecord 更新ES操作记录
func UpdateOneESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrMediaRecordNotExsit, "", "")
}
return nil
}
// UpsertOneESRecord 插入或更新一条ES操作记录
func UpsertOneESRecord(ctx context.Context,
filter bson.M, update bson.M) *srvdef.SrvErr {
if _, err := db.UpsertOne(ctx, filter, update); err != nil {
log.Info("esmod:UpsertOneESRecord db.InsertOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// UpdateManyESRecord 更新一批ES操作记录
func UpdateManyESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrMediaTagNotExsit, "", "")
}
return nil
}
// FindManyESRecord 查找一批ES操作记录
func FindManyESRecord(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (ESRecordList, *srvdef.SrvErr) {
data := make(ESRecordList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("esmod:FindManyESRecord db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func GetRecordTimeByESIndex(ctx context.Context, esIndex string) (*ESRecord, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return esRecord, nil
}
func SetOneEsRecordTime(ctx context.Context, esIndex string, recordTime time.Time) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.RecordTime: recordTime,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+223
View File
@@ -0,0 +1,223 @@
package esmod
type TagESRecord struct {
CreatedAt string
EsIndex string
Id string
RecordTime string
Timestamp struct {
I string
T string
}
UpdatedAt string
}
type TagESPlaylet struct {
Id string
Status string
IsFeatured string
IsRecommend string
OperateType string
ShowOnBanner string
Banner string
OnlineAt string
ThemeIds string
ThemeNames string
CategoryIds string
Title string
Description string
Slug string
Desc string
Anchor string
Cover string
TagIds string
TagNames string
TotalEpisode string
UpdateStatus string
CountBrowse string
HeatValue string
CountCollect string
CountLike string
UpdatedAt string
CreatedAt string
SeoInfo string
}
type TagESActress struct {
Id string
Alias string
Avatar string
Meas string
Office string
DebutDate string
BornDate string
Region string
Score string
Works string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
Desc string
Status string
CreatedAt string
UpdatedAt string
Rank string
}
type TagESPost struct {
Id string
CreateId string
Title string
Cover string
Thumb string
TagIds string
Kind string
Nodes string
VideoId string
Status string
Remark string
Rank string
AddedTime string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
CreatedAt string
UpdatedAt string
Keyworlds string
FirstTag string
Desc string
IsHot string
Sort string
}
var FN struct {
ESRecord TagESRecord
ESPlaylet TagESPlaylet
ESActress TagESActress
ESPost TagESPost
}
var TN struct {
ESRecord string
ESPlaylet string
ESActress string
ESPost string
}
func init() {
FN.ESRecord = TagESRecord{
CreatedAt: "createdAt",
EsIndex: "esIndex",
Id: "_id",
RecordTime: "recordTime",
Timestamp: struct {
I string
T string
}{
I: "i",
T: "t",
},
UpdatedAt: "updatedAt",
}
FN.ESPlaylet = TagESPlaylet{
Id: "id",
Status: "status",
IsFeatured: "isFeatured",
IsRecommend: "isRecommend",
OperateType: "operateType",
ShowOnBanner: "showOnBanner",
Banner: "banner",
OnlineAt: "onlineAt",
ThemeIds: "themeIds",
ThemeNames: "themeNames",
CategoryIds: "categoryIds",
Title: "title",
Description: "description",
Slug: "slug",
Desc: "desc",
Anchor: "anchor",
Cover: "cover",
TagIds: "tagIds",
TagNames: "tagNames",
TotalEpisode: "totalEpisode",
UpdateStatus: "updateStatus",
CountBrowse: "countBrowse",
HeatValue: "heatValue",
CountCollect: "countCollect",
CountLike: "countLike",
UpdatedAt: "updatedAt",
CreatedAt: "createdAt",
SeoInfo: "seoInfo",
}
FN.ESActress = TagESActress{
Id: "_id",
Alias: "alias",
Avatar: "avatar",
Meas: "meas",
Office: "office",
DebutDate: "debutDate",
BornDate: "bornDate",
Region: "region",
Score: "score",
Works: "works",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
Desc: "desc",
Status: "status",
CreatedAt: "createdAt",
UpdatedAt: "updatedAt",
Rank: "rank",
}
FN.ESPost = TagESPost{
Id: "_id",
CreateId: "createId",
Title: "title",
Cover: "cover",
Thumb: "thumb",
TagIds: "tagIds",
Kind: "kind",
Nodes: "nodes",
VideoId: "videoId",
Status: "status",
Remark: "remark",
Rank: "rank",
AddedTime: "addedTime",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
CreatedAt: "createdAt",
UpdatedAt: "updatedAt",
Keyworlds: "keyworlds",
FirstTag: "firstTag",
Desc: "desc",
IsHot: "isHot",
Sort: "sort",
}
TN.ESRecord = "es_record"
TN.ESPlaylet = "es_playlet"
TN.ESActress = "es_actress"
TN.ESPost = "es_post"
}
+88
View File
@@ -0,0 +1,88 @@
//go:generate gen_bson_tag -m esmod
//esmod essearch数据结构定义
package esmod
import (
"time"
"videoweb/pub/models/playletmod"
"videoweb/pub/pubdef"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type ESTimestamp struct {
T uint32 `json:"t" bson:"t"`
I uint32 `json:"i" bson:"i"`
}
func (v *ESTimestamp) IsZero() bool {
if v == nil {
return true
}
return v.T == 0 && v.I == 0
}
// ESOperator es操作记录
// @table:es_record
type ESRecord struct {
Id primitive.ObjectID `json:"id" bson:"_id"`
EsIndex string `json:"esIndex" bson:"esIndex"` //es索引名称
Timestamp ESTimestamp `json:"timestamp" bson:"timestamp"` //操作时间
RecordTime time.Time `json:"recordTime" bson:"recordTime"` // 操作记录时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` //更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //创建时间
}
type ESRecordList []*ESRecord
type ESTotal struct {
Value int64 `json:"value"`
}
// ESPlaylet es中存储的短剧搜索数据
// @table:es_playlet
type ESPlaylet struct {
Id int64 `json:"id" bson:"id"` // 短剧ID
Status playletmod.Status `json:"status" bson:"status"` // 状态: 0下架 1上架
IsFeatured bool `json:"isFeatured" bson:"isFeatured"` // 是否爆剧(true-是,false-否)
IsRecommend bool `json:"isRecommend" bson:"isRecommend"` // 是否推荐 true-推荐,false-不推荐
OperateType playletmod.OperateType `json:"operateType" bson:"operateType"` // 运营类型 1-短剧 2-漫剧
ShowOnBanner bool `json:"showOnBanner" bson:"showOnBanner"` // 是否显示在首页banner
Banner string `json:"banner" bson:"banner"` // banner图
OnlineAt time.Time `json:"onlineAt" bson:"onlineAt"` // 上架时间
ThemeIds []int64 `json:"themeIds" bson:"themeIds"` // 题材ID集合
ThemeNames []string `json:"themeNames" bson:"themeNames"` // 题材名称集合
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类ID集合
Title string `json:"title" bson:"title"` // 标题
Description string `json:"description" bson:"description"` // SEO Description
Slug string `json:"slug" bson:"slug"` // slug
Desc string `json:"desc" bson:"desc"` // 简介
Anchor string `json:"anchor" bson:"anchor"` // 作者/演员
Cover string `json:"cover" bson:"cover"` // 封面
TagIds []int64 `json:"tagIds" bson:"tagIds"` // 标签ID集合
TagNames []string `json:"tagNames" bson:"tagNames"` // 标签名称集合
TotalEpisode int64 `json:"totalEpisode" bson:"totalEpisode"` // 总集数
UpdateStatus int `json:"updateStatus" bson:"updateStatus"` // 更新状态 1-连载中 2-已完结
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 观看量
HeatValue int64 `json:"heatValue" bson:"heatValue"` // 热度值
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 展示点赞数
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
type ESPlayletList []*ESPlaylet
type ESPlayletSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESPlaylet `json:"_source"`
}
// ESPlayletHits search playlet hits
type ESPlayletHits struct {
Total ESTotal `json:"total"`
Hits []*ESPlayletSource `json:"hits"`
}