diff --git a/es/es_config.go b/es/es_config.go index dd583e2..ee4765f 100644 --- a/es/es_config.go +++ b/es/es_config.go @@ -31,27 +31,27 @@ func GetESFieldConfig() *ESFieldConfig { "fix_price": true, "content": true, "is_suit": true, - "day_sale_7": true, - "day_sale_15": true, - "day_sale_30": true, - "day_sale_60": true, - "day_sale_90": true, - "day_sale_180": true, - "day_sale_365": true, - "this_year_sale": true, - "last_year_sale": true, - "total_sale": true, - "buy_counts": true, - "sell_counts": true, - "is_illegal": true, - "is_return": true, - "is_filter": true, - "update_time": true, - "page_count": true, - "word_count": true, - "book_format": true, - "cat_id": true, - "other": true, // 允许更新 other 字段 + //"day_sale_7": true, + //"day_sale_15": true, + //"day_sale_30": true, + //"day_sale_60": true, + //"day_sale_90": true, + //"day_sale_180": true, + //"day_sale_365": true, + //"this_year_sale": true, + //"last_year_sale": true, + //"total_sale": true, + //"buy_counts": true, + //"sell_counts": true, + "is_illegal": true, + "is_return": true, + "is_filter": true, + "update_time": true, + //"page_count": true, + //"word_count": true, + //"book_format": true, + "cat_id": true, + "other": true, // 允许更新 other 字段 }, AllowAdd: map[string]bool{ diff --git a/es/es_search.go b/es/es_search.go index 1e4d250..2a98514 100644 --- a/es/es_search.go +++ b/es/es_search.go @@ -162,6 +162,10 @@ func (book *ESBook) ConvertToResponse() ESBookResponse { publicationTime := book.PublicationTime if publicationTime == "" || publicationTime == "0" || publicationTime == "0000-00-00" { publicationTime = time.Unix(0, 0).Format("2006-01") + } else { + if timeVal, err := strconv.ParseInt(publicationTime, 10, 64); err == nil { + publicationTime = strconv.FormatInt(timeVal-5364000000, 10) + } } return ESBookResponse{ ID: book.ID, @@ -243,18 +247,18 @@ type ESBook struct { Content string `json:"content,omitempty"` IsSuit int `json:"is_suit,omitempty"` // ⭐ 新增的字段 - DaySale7 int `json:"day_sale_7,omitempty"` - DaySale15 int `json:"day_sale_15,omitempty"` - DaySale30 int `json:"day_sale_30,omitempty"` - DaySale60 int `json:"day_sale_60,omitempty"` - DaySale90 int `json:"day_sale_90,omitempty"` - DaySale180 int `json:"day_sale_180,omitempty"` - DaySale365 int `json:"day_sale_365,omitempty"` - ThisYearSale int `json:"this_year_sale,omitempty"` - LastYearSale int `json:"last_year_sale,omitempty"` - TotalSale int `json:"total_sale,omitempty"` - BuyCounts int64 `json:"buy_counts,omitempty"` - SellCounts int64 `json:"sell_counts,omitempty"` + DaySale7 int `json:"day_sale_7"` + DaySale15 int `json:"day_sale_15"` + DaySale30 int `json:"day_sale_30"` + DaySale60 int `json:"day_sale_60"` + DaySale90 int `json:"day_sale_90"` + DaySale180 int `json:"day_sale_180"` + DaySale365 int `json:"day_sale_365"` + ThisYearSale int `json:"this_year_sale"` + LastYearSale int `json:"last_year_sale"` + TotalSale int `json:"total_sale"` + BuyCounts int64 `json:"buy_counts"` + SellCounts int64 `json:"sell_counts"` BookPicObj map[string]interface{} `json:"book_pic_obj,omitempty"` BookPicObjS map[string]interface{} `json:"book_pic_obj_s,omitempty"` UpdateTime NumberOrString `json:"update_time,omitempty"` @@ -1487,11 +1491,6 @@ func (svc *ESSearchService) SearchBookBaseInfoES(c *gin.Context) ([]ESBook, int, } defer res.Body.Close() - //if res.IsError() { - // raw, _ := io.ReadAll(res.Body) - // fmt.Printf("[ERROR] ES error body: %s\n", string(raw)) - // return nil, 0, fmt.Errorf("ES error: %s", string(raw)) - //} // 读取响应 var buf bytes.Buffer // 使用CopyBuffer可以重用缓冲区 @@ -1522,11 +1521,6 @@ func (svc *ESSearchService) SearchBookBaseInfoES(c *gin.Context) ([]ESBook, int, if err := _json.Unmarshal(rawData, &parsed); err != nil { return nil, 0, fmt.Errorf("JSON解析失败: %v, 原始数据: %s", err, string(rawData[:min(200, len(rawData))])) } - //var parsed esHitsWrapper - //if err := json.NewDecoder(res.Body).Decode(&parsed); err != nil { - // fmt.Printf("[ERROR] JSON Decode error: %v\n", err) - // return nil, 0, err - //} list := make([]ESBook, 0, len(parsed.Hits.Hits)) for _, hit := range parsed.Hits.Hits { list = append(list, hit.Source) @@ -1545,7 +1539,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in "bookName": "book_name", "bookPic": "book_pic", "publication_times": "publication_time", - //"isSuit": "is_suit", + "isSuit": "is_suit", } // ===== saleSelect 对应字段映射 ===== @@ -1588,7 +1582,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in continue } // 不作为查询条件的字段 - if key == "page" || key == "pageSize" || key == "per_page" || key == "saleSelect" || key == "picType" || key == "shopType" || key == "isSuit" || key == "is_return" { + if key == "page" || key == "pageSize" || key == "per_page" || key == "saleSelect" || key == "picType" || key == "shopType" { continue } @@ -1678,35 +1672,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in "is_filter": pattern, }, } - if val == "2" { - cond = map[string]interface{}{ - "bool": map[string]interface{}{ - "should": []map[string]interface{}{ - // 情况 1: is_filter 字段null - { - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - {"exists": map[string]interface{}{"field": "is_filter"}}, - }, - }, - }, - // 情况 2: is_filter 空串 - { - "term": map[string]interface{}{ - "is_filter": "", - }, - }, - // 情况 3: is_filter 字段存在且匹配 wildcard 模式 - { - "wildcard": map[string]interface{}{ - "is_filter": pattern, - }, - }, - }, - "minimum_should_match": 1, - }, - } - } must = append(must, cond) fmt.Printf("[DEBUG] must += %v\n", cond) @@ -1841,32 +1806,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in }, }, } - if minVal == 0 { - cond = map[string]interface{}{ - "bool": map[string]interface{}{ - "should": []map[string]interface{}{ - // 情况 1: buy_counts 字段不存在或为 null - { - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - {"exists": map[string]interface{}{"field": "buy_counts"}}, - }, - }, - }, - // 情况 2: buy_counts 在范围内 - { - "range": map[string]interface{}{ - "buy_counts": map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - }, - }, - "minimum_should_match": 1, - }, - } - } + must = append(must, cond) fmt.Printf("[DEBUG] must += %v\n", cond) continue @@ -1901,38 +1841,80 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in }, }, } - if minVal == 0 { - cond = map[string]interface{}{ - "bool": map[string]interface{}{ - "should": []map[string]interface{}{ - // 情况 1: total_sale 字段不存在或为 null - { - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - {"exists": map[string]interface{}{"field": "total_sale"}}, - }, - }, - }, - // 情况 2: total_sale 在范围内 - { - "range": map[string]interface{}{ - "total_sale": map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - }, - }, - "minimum_should_match": 1, - }, - } - } + //if minVal == 0 { + // cond = map[string]interface{}{ + // "bool": map[string]interface{}{ + // "should": []map[string]interface{}{ + // // 情况 1: total_sale 字段不存在或为 null + // { + // "bool": map[string]interface{}{ + // "must_not": []map[string]interface{}{ + // {"exists": map[string]interface{}{"field": "total_sale"}}, + // }, + // }, + // }, + // // 情况 2: total_sale 在范围内 + // { + // "range": map[string]interface{}{ + // "total_sale": map[string]interface{}{ + // "gte": minVal, + // "lte": maxVal, + // }, + // }, + // }, + // }, + // "minimum_should_match": 1, + // }, + // } + //} must = append(must, cond) fmt.Printf("[DEBUG] must += %v\n", cond) continue } } + // ===== page_count 范围查询 ===== + if key == "page_count" { + parts := strings.Split(val, ",") + if len(parts) == 2 { + minVal, _ := strconv.Atoi(parts[0]) + maxVal, _ := strconv.Atoi(parts[1]) + + cond := map[string]interface{}{ + "range": map[string]interface{}{ + "page_count": map[string]interface{}{ + "gte": minVal, + "lte": maxVal, + }, + }, + } + must = append(must, cond) + fmt.Printf("[DEBUG] must += %v (page_count: %d-%d)\n", cond, minVal, maxVal) + continue + } + } + + // ===== word_count 范围查询 ===== + if key == "word_count" { + parts := strings.Split(val, ",") + if len(parts) == 2 { + minVal, _ := strconv.Atoi(parts[0]) + maxVal, _ := strconv.Atoi(parts[1]) + + cond := map[string]interface{}{ + "range": map[string]interface{}{ + "word_count": map[string]interface{}{ + "gte": minVal, + "lte": maxVal, + }, + }, + } + must = append(must, cond) + fmt.Printf("[DEBUG] must += %v (word_count: %d-%d)\n", cond, minVal, maxVal) + continue + } + } + // ===== 数值范围 ===== if key == "sell_counts" || strings.HasPrefix(key, "day_sale_") || @@ -1952,32 +1934,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in }, }, } - if minVal == 0 { - cond = map[string]interface{}{ - "bool": map[string]interface{}{ - "should": []map[string]interface{}{ - // 情况 1: total_sale 字段不存在或为 null - { - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - {"exists": map[string]interface{}{"field": "total_sale"}}, - }, - }, - }, - // 情况 2: total_sale 在范围内 - { - "range": map[string]interface{}{ - key: map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - }, - }, - "minimum_should_match": 1, - }, - } - } + must = append(must, cond) fmt.Printf("[DEBUG] must += %v\n", cond) continue @@ -2010,7 +1967,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in continue } - fmt.Println("key--------------", key) // ===== 默认前缀匹配 ===== cond := map[string]interface{}{ "prefix": map[string]interface{}{key: val}, @@ -2053,21 +2009,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in body, _ := json.MarshalIndent(query, "", " ") fmt.Printf("[DEBUG] ES Query Body:\n%s\n", string(body)) - // ========== 执行 ES 查询 ========== - //res, err := svc.ES.Client.Search( - // svc.ES.Client.Search.WithIndex(ESIndex), - // svc.ES.Client.Search.WithBody(bytes.NewReader(body)), - // svc.ES.Client.Search.WithTrackTotalHits(true), - //) - // - //fmt.Printf("[DEBUG] ES Query Response:\n%s\n", res) - // - //if err != nil { - // fmt.Printf("[ERROR] ES.Client.Search error: %v\n", err) - // return nil, 0, err - //} - //defer res.Body.Close() - endpoint := c.FullPath() monitoredES := monitor.NewMonitoredESClient(svc.ES.Client, endpoint) @@ -2403,166 +2344,6 @@ func (svc *ESSearchService) SearchBookByISBNHandler(c *gin.Context) { }) } -// func (svc *ESSearchService) SearchBooksHandler(c *gin.Context) { -// isbn := c.Query("isbn") -// if isbn == "" { -// c.JSON(400, gin.H{"error": "缺少 isbn 参数"}) -// return -// } -// -// ctx := context.Background() -// -// db4Client, err := redisClient.GetClientByName("db1") -// if err == nil { -// val, err := db4Client.Get(ctx, isbn).Result() -// if err == nil && val != "" { -// log.Printf("[SearchBooksHandler] 从 Redis db1 查询到数据: %s", isbn) -// // 使用 RedisBookInfo 结构体解析 -// var redisBook request.BookInfo -// if err := json.Unmarshal([]byte(val), &redisBook); err == nil { -// // 转换为 ESBook -// esBook := ConvertRedisBookToESBook(&redisBook) -// if esBook != nil { -// responseData := esBook.ConvertToResponse() -// c.JSON(200, gin.H{ -// "data": responseData, -// }) -// return -// } -// } else { -// log.Printf("[SearchBookByISBNHandler] Redis 数据解析失败:%v", err) -// } -// } -// } -// -// result, err := svc.SearchBooks(isbn) -// if err != nil { -// c.JSON(500, gin.H{"error": "ES 查询失败", "details": err.Error()}) -// return -// } -// -// responseList := make([]ESBookResponse, 0, len(result)) -// for _, book := range result { -// responseList = append(responseList, book.ConvertToResponse()) -// } -// -// c.JSON(200, gin.H{ -// "count": len(result), -// "data": responseList, -// }) -// } -//func (svc *ESSearchService) SearchBookByISBNHandler(c *gin.Context) { -// -// isbn := c.Query("isbn") -// if isbn == "" { -// log.Printf("[SearchBookByISBNHandler] 缺少 isbn 参数") -// c.JSON(400, gin.H{"error": "缺少 isbn 参数"}) -// return -// } -// -// log.Printf("[SearchBookByISBNHandler] 查询 ISBN: %s", isbn) -// -// ctx := context.Background() -// -// db4Client, err := redisClient.GetClientByName("db1") -// fmt.Println(db4Client) -// -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] 获取 Redis db1 客户端失败: %v", err) -// } else { -// val, err := db4Client.Get(ctx, isbn).Result() -// if err == nil && val != "" { -// log.Printf("[SearchBookByISBNHandler] 从 Redis db1 查询到数据: %s", isbn) -// // 使用 RedisBookInfo 结构体解析 -// var redisBook request.BookInfo -// if err := json.Unmarshal([]byte(val), &redisBook); err == nil { -// // 转换为 ESBook -// esBook := ConvertRedisBookToESBook(&redisBook) -// if esBook != nil { -// responseData := esBook.ConvertToResponse() -// c.JSON(200, gin.H{ -// "data": responseData, -// }) -// return -// } -// } else { -// log.Printf("[SearchBookByISBNHandler] Redis 数据解析失败:%v", err) -// } -// } else { -// log.Printf("[SearchBookByISBNHandler] Redis db1 中未找到 ISBN: %s", isbn) -// } -// } -// -// result, err := svc.SearchBookByISBN(isbn) -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] ES 查询失败: %v", err) -// c.JSON(500, gin.H{"error": err.Error()}) -// return -// } -// -// if result == nil { -// log.Printf("[SearchBookByISBNHandler] ES 中未找到 ISBN: %s,从孔夫子抓取", isbn) -// -// apiBook, err := kongfz.GetBookImageByISBN(isbn, "CALF_ELEPHANT_PROXY", "1297757178467602432", "QgQBvP7f") -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] 孔夫子 API 查询失败: %v", err) -// c.JSON(500, gin.H{"error": err.Error()}) -// return -// } -// if apiBook == nil || apiBook.Data.ISBN == "" { -// log.Printf("[SearchBookByISBNHandler] 孔夫子 API 未找到图书信息 ISBN: %s", isbn) -// c.JSON(404, gin.H{"error": "未找到图书信息"}) -// return -// } -// -// log.Printf("[SearchBookByISBNHandler] 获取到图书信息: %+v", apiBook.Data) -// -// pddBookPicURL := "" -// if apiBook.Data.BookPic != "" { -// url, err := image.DownloadAndUploadBookImage(apiBook.Data.BookPic, isbn, "true", apiBook.Data.BookName, "true") -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] 上传 book_pic 失败: %v", err) -// } else { -// pddBookPicURL = url -// log.Printf("[SearchBookByISBNHandler] 上传 book_pic 成功: %s", url) -// } -// } -// -// pddBookPicSURL := "" -// if apiBook.Data.BookPicS != "" { -// url, err := image.DownloadAndUploadBookImage(apiBook.Data.BookPicS, isbn, "true", apiBook.Data.BookName, "true") -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] 上传 book_pic_s 失败: %v", err) -// } else { -// pddBookPicSURL = url -// log.Printf("[SearchBookByISBNHandler] 上传 book_pic_s 成功: %s", url) -// } -// } -// -// esBook := ConvertKongfzToESBook(apiBook) -// -// esBook.BookPicS.PddResponse = pddBookPicSURL -// esBook.BookPic.PddPath = pddBookPicURL -// //log.Printf("[SearchBookByISBNHandler] 写入 ES: %+v", esBook) -// -// result, err = svc.AddBookToES(c.Request.Context(), esBook) -// if err != nil { -// log.Printf("[SearchBookByISBNHandler] 写入 ES 失败: %v", err) -// c.JSON(500, gin.H{"error": err.Error()}) -// return -// } -// -// log.Printf("[SearchBookByISBNHandler] 写入 ES 成功, ISBN: %s", isbn) -// } else { -// //log.Printf("[SearchBookByISBNHandler] 从 ES 查询到图书: %+v", result) -// } -// -// responseData := result.ConvertToResponse() -// c.JSON(200, gin.H{ -// "data": responseData, -// }) -//} - // ConvertKongfzToESBook 将第三方接口返回的数据转换为 ESBook 结构 func ConvertKongfzToESBook(apiBook *kongfz.BookResponse) *ESBook { if apiBook == nil || apiBook.Data.ISBN == "" { @@ -2930,8 +2711,6 @@ func (svc *ESSearchService) UpdateBookSuitByISBNHandler(c *gin.Context) { }, } - fmt.Println(body) - payload, _ := json.Marshal(body) res, err := svc.ES.Client.UpdateByQuery( @@ -3019,7 +2798,6 @@ func (svc *ESSearchService) UpdateBookFieldsByISBNHandler(c *gin.Context) { // 先确认 ISBN 是否存在 book, err := svc.SearchBookByISBN(isbn) - fmt.Println("book:", book) if err != nil { c.JSON(500, gin.H{ "error": "查询ES失败", @@ -3128,7 +2906,6 @@ func (svc *ESSearchService) UpdateBookFieldsByISBN( fmt.Sprintf("ctx._source.%s = params.%s;", field, field)) params[field] = value } - fmt.Println("scriptParts:", scriptParts) if len(scriptParts) == 0 { return 0, fmt.Errorf("没有有效的字段可更新") } diff --git a/main.go b/main.go index e510fa4..2b88169 100644 --- a/main.go +++ b/main.go @@ -184,10 +184,15 @@ func main() { // "zDzSXel3PFwx9=6Ybmqv", //) /** ES2 本地测试 **/ + //esClient, err := es.NewESClient( + // []string{"https://103.236.91.138:9200"}, + // "elastic", + // "7AYdoW=mn3yHZ*3A=Z1x", + //) esClient, err := es.NewESClient( - []string{"https://103.236.91.138:9200"}, + []string{"http://36.212.1.63:9200"}, "elastic", - "7AYdoW=mn3yHZ*3A=Z1x", + "zDzSXel3PFwx9=6Ybmqva", ) if err != nil { @@ -197,7 +202,7 @@ func main() { esService := es.NewESSearchService(esClient) redisClient.AddClient("db4", "36.212.12.247:6379", "long6166@@", 2) - redisClient.AddClient("db1", "36.212.12.247:6379", "long6166@@", 1) + redisClient.AddClient("db1", "36.212.12.247:6379", "long6166@@", 7) //redisClient.AddClient("test", "127.0.0.1:6379", "", 0) // =================================================================== diff --git a/model/request/book.go b/model/request/book.go index 1157038..963bb5f 100644 --- a/model/request/book.go +++ b/model/request/book.go @@ -34,6 +34,8 @@ type BookSearchRequest struct { LastYearSale string `form:"last_year_sale"` // 去年销量 TotalSaleRange string `form:"totalSale_range"` // 总销量范围 ID string `form:"id"` // ID + PageCount string `form:"page_count"` // 页数 + WordCount string `form:"word_count"` // 字数 } // BookUpdateRequest 更新图书请求参数 diff --git a/service/book.go b/service/book.go index 1a9ae9e..a0c0391 100644 --- a/service/book.go +++ b/service/book.go @@ -6,15 +6,12 @@ import ( "centerBook/es" "centerBook/model/request" "centerBook/tail" - "centerBook/util" "centerBook/util/redisClient" "context" "encoding/json" "fmt" "io" "log" - "mime/multipart" - "net/http" "strconv" "strings" "time" @@ -120,8 +117,8 @@ func (svc *BookService) SearchBookBaseInfo(request *request.BookSearchRequest) ( } // ========== 构建查询条件 ========== - //svc.buildISuitCondition(queryBuilder, request.IsSuit) - //svc.buildIsReturnCondition(queryBuilder, request.IsReturn) + svc.buildISuitCondition(queryBuilder, request.IsSuit) + svc.buildIsReturnCondition(queryBuilder, request.IsReturn) svc.buildIsFilterCondition(queryBuilder, request.IsFilter, request.ShopType) svc.buildCategoryTypeCondition(queryBuilder, request.CategoryType) svc.buildCategoryCondition(queryBuilder, request.Category) @@ -303,6 +300,12 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_filter = params.is_filter;")) log.Printf("[UpdateBookFieldsByISBN] 检测到 is_suit=1,自动设置 is_filter=100100 | ISBN=%s | 原始类型:%T", request.ISBN, isSuitValue) + } else { + // is_suit 不为 1 时,清空 is_filter + params["is_filter"] = "000000" + scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_filter = params.is_filter;")) + log.Printf("[UpdateBookFieldsByISBN] 检测到 is_suit!=1,清空 is_filter | ISBN=%s | is_suit 值:%v", + request.ISBN, isSuitValue) } } else { // 未传递 is_suit,自动检测并设置 @@ -319,14 +322,39 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques } for field, value := range request.Data { + if field == "is_suit" { + continue + } // 使用配置检查字段是否允许更新 if !fieldConfig.IsAllowUpdate(field) { log.Printf("[UpdateBookFieldsByISBN] 字段 %s 不允许更新,已跳过", field) continue } + // 对 publication_time 字段做特殊处理 + if field == "publication_time" { + // 将原始值转换为 int64 并加上 5364000000 + var pubTime int64 + switch v := value.(type) { + case int: + pubTime = int64(v) + case int64: + pubTime = v + case float64: + pubTime = int64(v) + case string: + // 如果是字符串,尝试解析 + if parsed, err := strconv.ParseInt(v, 10, 64); err == nil { + pubTime = parsed + } + } + pubTime += 5364000000 + params[field] = strconv.FormatInt(pubTime, 10) + log.Printf("[UpdateBookFieldsByISBN] publication_time 偏移处理:%v -> %v | ISBN=%s", value, pubTime, request.ISBN) + } else { + params[field] = value + } scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.%s = params.%s;", field, field)) - params[field] = value } if len(scriptParts) == 0 { return nil, fmt.Errorf("没有有效的更新字段") @@ -344,11 +372,6 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques }, } fmt.Println("[DEBUG] ES UpdateByQuery Request Body:", body) - //return &UpdateBookResult{ - // ISBN: request.ISBN, - // Updated: 1, - // Fields: request.Data, - //}, nil payload, _ := json.Marshal(body) res, err := svc.esClient.Client.UpdateByQuery( []string{es.ESIndex}, @@ -441,58 +464,58 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques //} // AddFilterSet 添加过滤集合(POST form-data) -func (svc *BookService) AddFilterSet(isbn string) error { - fmt.Println("AddFilterSet start") - url := "http://103.236.91.138:8888/api/addFilterSet" - - // 创建 multipart form - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - fmt.Println("[AddFilterSet] 创建 multipart form", isbn) - // 添加表单字段 - _ = writer.WriteField("filterType", "1") - _ = writer.WriteField("limitationType", "0") - _ = writer.WriteField("addWay", "6") - _ = writer.WriteField("addTxt", isbn) - _ = writer.WriteField("createBy", "1") - _ = writer.WriteField("tenantId", "000000") - _ = writer.WriteField("sort", "0,3") - - err := writer.Close() - if err != nil { - return fmt.Errorf("关闭 multipart writer 失败:%v", err) - } - - // 创建 HTTP 请求 - httpReq, err := http.NewRequest("POST", url, body) - if err != nil { - return fmt.Errorf("创建 HTTP 请求失败:%v", err) - } - - httpReq.Header.Set("Content-Type", writer.FormDataContentType()) - // 发送请求 - client := &http.Client{ - Timeout: 30 * time.Second, - } - - resp, err := client.Do(httpReq) - fmt.Println("[AddFilterSet] 发送 HTTP 请求", resp) - if err != nil { - return fmt.Errorf("发送 HTTP 请求失败:%v", err) - } - fmt.Println("[AddFilterSet] 响应状态:%d", resp.StatusCode) - defer resp.Body.Close() - - // 读取响应 - respBody, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("读取响应失败:%v", err) - } - - log.Printf("[AddFilterSet] 响应状态:%d | 响应内容:%s", resp.StatusCode, string(respBody)) - - return nil -} +//func (svc *BookService) AddFilterSet(isbn string) error { +// fmt.Println("AddFilterSet start") +// url := "http://103.236.91.138:8888/api/addFilterSet" +// +// // 创建 multipart form +// body := &bytes.Buffer{} +// writer := multipart.NewWriter(body) +// fmt.Println("[AddFilterSet] 创建 multipart form", isbn) +// // 添加表单字段 +// _ = writer.WriteField("filterType", "1") +// _ = writer.WriteField("limitationType", "0") +// _ = writer.WriteField("addWay", "6") +// _ = writer.WriteField("addTxt", isbn) +// _ = writer.WriteField("createBy", "1") +// _ = writer.WriteField("tenantId", "000000") +// _ = writer.WriteField("sort", "0,3") +// +// err := writer.Close() +// if err != nil { +// return fmt.Errorf("关闭 multipart writer 失败:%v", err) +// } +// +// // 创建 HTTP 请求 +// httpReq, err := http.NewRequest("POST", url, body) +// if err != nil { +// return fmt.Errorf("创建 HTTP 请求失败:%v", err) +// } +// +// httpReq.Header.Set("Content-Type", writer.FormDataContentType()) +// // 发送请求 +// client := &http.Client{ +// Timeout: 30 * time.Second, +// } +// +// resp, err := client.Do(httpReq) +// fmt.Println("[AddFilterSet] 发送 HTTP 请求", resp) +// if err != nil { +// return fmt.Errorf("发送 HTTP 请求失败:%v", err) +// } +// fmt.Println("[AddFilterSet] 响应状态:%d", resp.StatusCode) +// defer resp.Body.Close() +// +// // 读取响应 +// respBody, err := io.ReadAll(resp.Body) +// if err != nil { +// return fmt.Errorf("读取响应失败:%v", err) +// } +// +// log.Printf("[AddFilterSet] 响应状态:%d | 响应内容:%s", resp.StatusCode, string(respBody)) +// +// return nil +//} // UpdateBookCatIdByISBNHandler 更新图书字段 func (svc *BookService) UpdateBookCatIdByISBNHandler(request *request.BookUpdateRequest) (*UpdateBookResult, error) { @@ -740,7 +763,10 @@ func (svc *BookService) addBookToES(ctx context.Context, req *es.ESBook) (*es.ES // 处理出版时间,转换为时间戳 publicationTimeTimestamp := req.PublicationTime if req.PublicationTime != "" && req.PublicationTime != "0" { - publicationTimeTimestamp = strconv.FormatInt(util.ParsePublicationTime(publicationTimeTimestamp), 10) + publicationTimeIn64, err := strconv.ParseInt(req.PublicationTime, 10, 64) + if err == nil { + publicationTimeTimestamp = strconv.FormatInt(publicationTimeIn64+5364000000, 10) + } } // 准备数据映射(使用 Go 字段名) dataMap := make(map[string]interface{}) @@ -789,7 +815,6 @@ func (svc *BookService) addBookToES(ctx context.Context, req *es.ESBook) (*es.ES if req.Other != nil { dataMap["Other"] = req.Other } - fmt.Println("dataMap:", dataMap) // 使用配置构建 ES 文档(自动转换字段名) doc := es.GetESFieldConfig().BuildESDocument(dataMap) @@ -882,7 +907,7 @@ func (svc *BookService) SyncRedisByISBN(isbn string, act string) error { if book.PublicationTime != "" && book.PublicationTime != "0" { publicationTimeIn64, err := strconv.ParseInt(book.PublicationTime, 10, 64) if err == nil { - redisBookInfo.PublicationDate = time.Unix(publicationTimeIn64+5364000000, 0).Format("2006-01") + redisBookInfo.PublicationDate = time.Unix(publicationTimeIn64-5364000000, 0).Format("2006-01") } } if book.BindingLayout != "" { @@ -1166,45 +1191,11 @@ func (svc *BookService) buildISuitCondition(builder *ESQueryBuilder, isSuit stri } log.Printf("[DEBUG] is_suit val=%q", isSuit) if num, err := strconv.Atoi(isSuit); err == nil { - if num == 0 { - valueQuery := map[string]interface{}{ - "term": map[string]interface{}{ - "is_suit": 0, - }, - } - //TODO 兼容 null 值 - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": "is_suit", - }, - }, - }, - }, - } - //TODO 兼容 空串 - emptyQuery := map[string]interface{}{ - "term": map[string]interface{}{ - "is_suit": "", - }, - } - builder.AddBoolQuery("must", []map[string]interface{}{ - { - "bool": map[string]interface{}{ - "should": []map[string]interface{}{valueQuery, nullQuery, emptyQuery}, - }, - }, - }) - log.Printf("[DEBUG] is_suit=0,兼容 null 值") - } else { - builder.AddQuery(&QueryCondition{ - Field: "is_suit", - Value: num, - Type: "term", - }) - } + builder.AddQuery(&QueryCondition{ + Field: "is_suit", + Value: num, + Type: "term", + }) } else { log.Printf("[ERROR] is_suit Atoi error: %v", err) } @@ -1217,45 +1208,11 @@ func (svc *BookService) buildIsReturnCondition(builder *ESQueryBuilder, isReturn } log.Printf("[DEBUG] is_return val=%q", isReturn) if num, err := strconv.Atoi(isReturn); err == nil { - if num == 0 { - valueQuery := map[string]interface{}{ - "term": map[string]interface{}{ - "is_return": 0, - }, - } - //TODO 兼容 null 值 - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": "is_return", - }, - }, - }, - }, - } - //TODO 兼容 空串 - emptyQuery := map[string]interface{}{ - "term": map[string]interface{}{ - "is_return": "", - }, - } - builder.AddBoolQuery("must", []map[string]interface{}{ - { - "bool": map[string]interface{}{ - "should": []map[string]interface{}{valueQuery, nullQuery, emptyQuery}, - }, - }, - }) - log.Printf("[DEBUG] is_return=0,兼容 null 值") - } else { - builder.AddQuery(&QueryCondition{ - Field: "is_return", - Value: num, - Type: "term", - }) - } + builder.AddQuery(&QueryCondition{ + Field: "is_return", + Value: num, + Type: "term", + }) } else { log.Printf("[ERROR] is_return Atoi error: %v", err) } @@ -1286,49 +1243,11 @@ func (svc *BookService) buildIsFilterCondition(builder *ESQueryBuilder, isFilter default: return } - - if isFilter == "2" { - wildcardQuery := map[string]interface{}{ - "wildcard": map[string]interface{}{ - "is_filter": pattern, - }, - } - - //TODO 兼容 null 值 - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": "is_filter", - }, - }, - }, - }, - } - - //TODO 兼容 空串 - emptyQuery := map[string]interface{}{ - "term": map[string]interface{}{ - "is_filter": "", - }, - } - - builder.AddBoolQuery("must", []map[string]interface{}{ - { - "bool": map[string]interface{}{ - "should": []map[string]interface{}{wildcardQuery, nullQuery, emptyQuery}, - }, - }, - }) - log.Printf("[DEBUG] is_filter=2,兼容 null 值 | pattern=%s", pattern) - } else { - builder.AddQuery(&QueryCondition{ - Field: "is_filter", - Type: "wildcard", - Pattern: pattern, - }) - } + builder.AddQuery(&QueryCondition{ + Field: "is_filter", + Type: "wildcard", + Pattern: pattern, + }) } // buildCategoryTypeCondition 构建 categoryType 查询条件 @@ -1421,40 +1340,13 @@ func (svc *BookService) buildBuyCountsCondition(builder *ESQueryBuilder, buyCoun if len(parts) == 2 { minVal, _ := strconv.Atoi(parts[0]) maxVal, _ := strconv.Atoi(parts[1]) - // 如果查询范围包含 0(0-999999),需要同时匹配 null 值 - if minVal == 0 { - // 使用 bool should 查询:匹配范围内值 OR 字段为 null/不存在 - rangeQuery := map[string]interface{}{ - "range": map[string]interface{}{ - "buy_counts": map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - } - - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": "buy_counts", - }, - }, - }, - }, - } - - builder.AddBoolQuery("should", []map[string]interface{}{rangeQuery, nullQuery}) - } else { - // 普通范围查询,不包含 null 值 - builder.AddQuery(&QueryCondition{ - Field: saleField, - Type: "range", - GTE: minVal, - LTE: maxVal, - }) - } + // 普通范围查询,不包含 null 值 + builder.AddQuery(&QueryCondition{ + Field: saleField, + Type: "range", + GTE: minVal, + LTE: maxVal, + }) return } @@ -1476,40 +1368,13 @@ func (svc *BookService) buildTotalSaleRangeCondition(builder *ESQueryBuilder, to if len(parts) == 2 { minVal, _ := strconv.Atoi(parts[0]) maxVal, _ := strconv.Atoi(parts[1]) - // 如果查询范围包含 0(0-999999),需要同时匹配 null 值 - if minVal == 0 { - // 使用 bool should 查询:匹配范围内值 OR 字段为 null/不存在 - rangeQuery := map[string]interface{}{ - "range": map[string]interface{}{ - "total_sale": map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - } - - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": "total_sale", - }, - }, - }, - }, - } - - builder.AddBoolQuery("should", []map[string]interface{}{rangeQuery, nullQuery}) - } else { - // 普通范围查询,不包含 null 值 - builder.AddQuery(&QueryCondition{ - Field: "total_sale", - Type: "range", - GTE: minVal, - LTE: maxVal, - }) - } + // 普通范围查询,不包含 null 值 + builder.AddQuery(&QueryCondition{ + Field: "total_sale", + Type: "range", + GTE: minVal, + LTE: maxVal, + }) } } @@ -1527,6 +1392,8 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req "ThisYearSale": request.ThisYearSale, "LastYearSale": request.LastYearSale, "PublicationTime": request.PublicationTime, + "PageCount": request.PageCount, + "WordCount": request.WordCount, } esFields := map[string]string{ @@ -1541,6 +1408,8 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req "ThisYearSale": "this_year_sale", "LastYearSale": "last_year_sale", "PublicationTime": "publication_time", + "PageCount": "page_count", + "WordCount": "word_count", } for fieldName, value := range fields { @@ -1549,44 +1418,20 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req } esField := esFields[fieldName] parts := strings.Split(value, ",") - fmt.Println("ppp", fieldName, parts) if len(parts) == 2 { minVal, _ := strconv.Atoi(parts[0]) maxVal, _ := strconv.Atoi(parts[1]) - // 如果查询范围包含 0(0-999999),需要同时匹配 null 值 - if minVal == 0 { - // 使用 bool should 查询:匹配范围内值 OR 字段为 null/不存在 - rangeQuery := map[string]interface{}{ - "range": map[string]interface{}{ - esField: map[string]interface{}{ - "gte": minVal, - "lte": maxVal, - }, - }, - } - - nullQuery := map[string]interface{}{ - "bool": map[string]interface{}{ - "must_not": []map[string]interface{}{ - { - "exists": map[string]interface{}{ - "field": esField, - }, - }, - }, - }, - } - - builder.AddBoolQuery("should", []map[string]interface{}{rangeQuery, nullQuery}) - } else { - // 普通范围查询,不包含 null 值 - builder.AddQuery(&QueryCondition{ - Field: esField, - Type: "range", - GTE: minVal, - LTE: maxVal, - }) + if fieldName == "PublicationTime" { + minVal += 5364000000 + maxVal += 5364000000 } + // 普通范围查询,不包含 null 值 + builder.AddQuery(&QueryCondition{ + Field: esField, + Type: "range", + GTE: minVal, + LTE: maxVal, + }) } } }