Compare commits
No commits in common. "bd6635f5be53065cca2e9ebeaca40c0efff0ea73" and "48b4d895108b306cc45db6a445079ad86606f9c0" have entirely different histories.
bd6635f5be
...
48b4d89510
@ -31,27 +31,27 @@ func GetESFieldConfig() *ESFieldConfig {
|
|||||||
"fix_price": true,
|
"fix_price": true,
|
||||||
"content": true,
|
"content": true,
|
||||||
"is_suit": true,
|
"is_suit": true,
|
||||||
//"day_sale_7": true,
|
"day_sale_7": true,
|
||||||
//"day_sale_15": true,
|
"day_sale_15": true,
|
||||||
//"day_sale_30": true,
|
"day_sale_30": true,
|
||||||
//"day_sale_60": true,
|
"day_sale_60": true,
|
||||||
//"day_sale_90": true,
|
"day_sale_90": true,
|
||||||
//"day_sale_180": true,
|
"day_sale_180": true,
|
||||||
//"day_sale_365": true,
|
"day_sale_365": true,
|
||||||
//"this_year_sale": true,
|
"this_year_sale": true,
|
||||||
//"last_year_sale": true,
|
"last_year_sale": true,
|
||||||
//"total_sale": true,
|
"total_sale": true,
|
||||||
//"buy_counts": true,
|
"buy_counts": true,
|
||||||
//"sell_counts": true,
|
"sell_counts": true,
|
||||||
"is_illegal": true,
|
"is_illegal": true,
|
||||||
"is_return": true,
|
"is_return": true,
|
||||||
"is_filter": true,
|
"is_filter": true,
|
||||||
"update_time": true,
|
"update_time": true,
|
||||||
//"page_count": true,
|
"page_count": true,
|
||||||
//"word_count": true,
|
"word_count": true,
|
||||||
//"book_format": true,
|
"book_format": true,
|
||||||
"cat_id": true,
|
"cat_id": true,
|
||||||
"other": true, // 允许更新 other 字段
|
"other": true, // 允许更新 other 字段
|
||||||
},
|
},
|
||||||
|
|
||||||
AllowAdd: map[string]bool{
|
AllowAdd: map[string]bool{
|
||||||
|
|||||||
708
es/es_search.go
708
es/es_search.go
@ -26,7 +26,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const ESIndex = "books-from-mysql-v2"
|
const ESIndex = "books-from-mysql-v2"
|
||||||
const ESIndexV3 = "books-from-mysql-v3"
|
|
||||||
|
|
||||||
// ESBookResponse 用于返回给Java客户端的格式,ID为简单的int64
|
// ESBookResponse 用于返回给Java客户端的格式,ID为简单的int64
|
||||||
type ESBookResponse struct {
|
type ESBookResponse struct {
|
||||||
@ -71,49 +70,6 @@ type ESBookResponse struct {
|
|||||||
Other map[string]interface{} `json:"other"` // 扩展字段,用于兼容未来新增字段
|
Other map[string]interface{} `json:"other"` // 扩展字段,用于兼容未来新增字段
|
||||||
}
|
}
|
||||||
|
|
||||||
// ESBookResponseByPSI 用于返回给Java客户端的格式,ID为简单的int64
|
|
||||||
type ESBookResponseByPSI struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
BookName string `json:"book_name"`
|
|
||||||
BookPic map[string]interface{} `json:"book_pic"`
|
|
||||||
BookPicS map[string]interface{} `json:"book_pic_s"`
|
|
||||||
BookPicB string `json:"book_pic_b"`
|
|
||||||
BookPicW map[string]interface{} `json:"book_pic_w"`
|
|
||||||
BookDefPic map[string]interface{} `json:"book_def_pic"` // 自制官图,临时用
|
|
||||||
ISBN string `json:"isbn"`
|
|
||||||
Author string `json:"author"`
|
|
||||||
Category string `json:"category"`
|
|
||||||
Publisher string `json:"publisher"`
|
|
||||||
PublicationTime string `json:"publication_time"`
|
|
||||||
BindingLayout string `json:"binding_layout"`
|
|
||||||
FixPrice float64 `json:"fix_price"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
IsSuit int `json:"is_suit"`
|
|
||||||
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"`
|
|
||||||
BookPicObjS map[string]interface{} `json:"book_pic_obj_s"`
|
|
||||||
UpdateTime NumberOrString `json:"update_time"`
|
|
||||||
IsIllegal int `json:"is_illegal"` // 是否非法 示例 000000
|
|
||||||
IsReturn int `json:"is_return"` // 是否为驳回 示例 0 否 1 是
|
|
||||||
IsFilter string `json:"is_filter"` // 过滤字段
|
|
||||||
PageCount NumberOrString `json:"page_count"` // 页数
|
|
||||||
WordCount NumberOrString `json:"word_count"` // 字数
|
|
||||||
BookFormat NumberOrString `json:"book_format"` // 多少开
|
|
||||||
CatId request.CatIdObject `json:"cat_id"` // 类目
|
|
||||||
Other map[string]interface{} `json:"other"` // 扩展字段,用于兼容未来新增字段
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlexibleString 处理可能是字符串或数组的字段
|
// FlexibleString 处理可能是字符串或数组的字段
|
||||||
type FlexibleString struct {
|
type FlexibleString struct {
|
||||||
Value string
|
Value string
|
||||||
@ -206,10 +162,6 @@ func (book *ESBook) ConvertToResponse() ESBookResponse {
|
|||||||
publicationTime := book.PublicationTime
|
publicationTime := book.PublicationTime
|
||||||
if publicationTime == "" || publicationTime == "0" || publicationTime == "0000-00-00" {
|
if publicationTime == "" || publicationTime == "0" || publicationTime == "0000-00-00" {
|
||||||
publicationTime = time.Unix(0, 0).Format("2006-01")
|
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{
|
return ESBookResponse{
|
||||||
ID: book.ID,
|
ID: book.ID,
|
||||||
@ -254,71 +206,6 @@ func (book *ESBook) ConvertToResponse() ESBookResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertToResponseByPsi 将ESBook转换为ESBookResponse,处理ID字段转换
|
|
||||||
func (book *ESBook) ConvertToResponseByPsi() ESBookResponseByPSI {
|
|
||||||
bookPicMap := map[string]interface{}{
|
|
||||||
"localPath": book.BookPic.LocalPath,
|
|
||||||
"pddPath": book.BookPic.PddPath,
|
|
||||||
}
|
|
||||||
bookPicSMap := map[string]interface{}{
|
|
||||||
"localPath": book.BookPicS.LocalPath,
|
|
||||||
"pddResponse": book.BookPicS.PddResponse,
|
|
||||||
}
|
|
||||||
bookDefPic := map[string]interface{}{
|
|
||||||
"localPath": book.BookDefPic.LocalPath,
|
|
||||||
"pddPath": book.BookDefPic.PddPath,
|
|
||||||
}
|
|
||||||
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 ESBookResponseByPSI{
|
|
||||||
ID: book.ID,
|
|
||||||
BookName: book.BookName.Value,
|
|
||||||
BookPic: bookPicMap,
|
|
||||||
BookPicS: bookPicSMap,
|
|
||||||
BookPicB: book.BookPicB,
|
|
||||||
BookPicW: book.BookPicW,
|
|
||||||
BookDefPic: bookDefPic,
|
|
||||||
ISBN: book.ISBN,
|
|
||||||
Author: book.Author,
|
|
||||||
Category: book.Category,
|
|
||||||
Publisher: book.Publisher,
|
|
||||||
PublicationTime: publicationTime,
|
|
||||||
BindingLayout: book.BindingLayout,
|
|
||||||
FixPrice: float64(book.FixPrice),
|
|
||||||
Content: book.Content,
|
|
||||||
IsSuit: book.IsSuit,
|
|
||||||
DaySale7: book.DaySale7,
|
|
||||||
DaySale15: book.DaySale15,
|
|
||||||
DaySale30: book.DaySale30,
|
|
||||||
DaySale60: book.DaySale60,
|
|
||||||
DaySale90: book.DaySale90,
|
|
||||||
DaySale180: book.DaySale180,
|
|
||||||
DaySale365: book.DaySale365,
|
|
||||||
ThisYearSale: book.ThisYearSale,
|
|
||||||
LastYearSale: book.LastYearSale,
|
|
||||||
TotalSale: book.TotalSale,
|
|
||||||
BuyCounts: book.BuyCounts,
|
|
||||||
SellCounts: book.SellCounts,
|
|
||||||
BookPicObj: book.BookPicObj,
|
|
||||||
BookPicObjS: book.BookPicObjS,
|
|
||||||
UpdateTime: book.UpdateTime,
|
|
||||||
IsIllegal: book.IsIllegal,
|
|
||||||
IsReturn: book.IsReturn,
|
|
||||||
IsFilter: book.IsFilter,
|
|
||||||
PageCount: book.PageCount,
|
|
||||||
WordCount: book.WordCount,
|
|
||||||
BookFormat: book.BookFormat,
|
|
||||||
CatId: book.CatId,
|
|
||||||
Other: book.Other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于 book_pic
|
// 用于 book_pic
|
||||||
type BookPicObj struct {
|
type BookPicObj struct {
|
||||||
LocalPath string `json:"localPath"`
|
LocalPath string `json:"localPath"`
|
||||||
@ -356,18 +243,18 @@ type ESBook struct {
|
|||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
IsSuit int `json:"is_suit,omitempty"`
|
IsSuit int `json:"is_suit,omitempty"`
|
||||||
// ⭐ 新增的字段
|
// ⭐ 新增的字段
|
||||||
DaySale7 int `json:"day_sale_7"`
|
DaySale7 int `json:"day_sale_7,omitempty"`
|
||||||
DaySale15 int `json:"day_sale_15"`
|
DaySale15 int `json:"day_sale_15,omitempty"`
|
||||||
DaySale30 int `json:"day_sale_30"`
|
DaySale30 int `json:"day_sale_30,omitempty"`
|
||||||
DaySale60 int `json:"day_sale_60"`
|
DaySale60 int `json:"day_sale_60,omitempty"`
|
||||||
DaySale90 int `json:"day_sale_90"`
|
DaySale90 int `json:"day_sale_90,omitempty"`
|
||||||
DaySale180 int `json:"day_sale_180"`
|
DaySale180 int `json:"day_sale_180,omitempty"`
|
||||||
DaySale365 int `json:"day_sale_365"`
|
DaySale365 int `json:"day_sale_365,omitempty"`
|
||||||
ThisYearSale int `json:"this_year_sale"`
|
ThisYearSale int `json:"this_year_sale,omitempty"`
|
||||||
LastYearSale int `json:"last_year_sale"`
|
LastYearSale int `json:"last_year_sale,omitempty"`
|
||||||
TotalSale int `json:"total_sale"`
|
TotalSale int `json:"total_sale,omitempty"`
|
||||||
BuyCounts int64 `json:"buy_counts"`
|
BuyCounts int64 `json:"buy_counts,omitempty"`
|
||||||
SellCounts int64 `json:"sell_counts"`
|
SellCounts int64 `json:"sell_counts,omitempty"`
|
||||||
BookPicObj map[string]interface{} `json:"book_pic_obj,omitempty"`
|
BookPicObj map[string]interface{} `json:"book_pic_obj,omitempty"`
|
||||||
BookPicObjS map[string]interface{} `json:"book_pic_obj_s,omitempty"`
|
BookPicObjS map[string]interface{} `json:"book_pic_obj_s,omitempty"`
|
||||||
UpdateTime NumberOrString `json:"update_time,omitempty"`
|
UpdateTime NumberOrString `json:"update_time,omitempty"`
|
||||||
@ -431,10 +318,8 @@ type AddBookFullRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ESSearchService struct {
|
type ESSearchService struct {
|
||||||
ES *ESClient
|
ES *ESClient
|
||||||
SyncRedisByISBN func(isbn string, act string) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NumberOrString string
|
type NumberOrString string
|
||||||
|
|
||||||
func (n *NumberOrString) UnmarshalJSON(data []byte) error {
|
func (n *NumberOrString) UnmarshalJSON(data []byte) error {
|
||||||
@ -1602,6 +1487,11 @@ func (svc *ESSearchService) SearchBookBaseInfoES(c *gin.Context) ([]ESBook, int,
|
|||||||
}
|
}
|
||||||
defer res.Body.Close()
|
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
|
var buf bytes.Buffer
|
||||||
// 使用CopyBuffer可以重用缓冲区
|
// 使用CopyBuffer可以重用缓冲区
|
||||||
@ -1632,6 +1522,11 @@ func (svc *ESSearchService) SearchBookBaseInfoES(c *gin.Context) ([]ESBook, int,
|
|||||||
if err := _json.Unmarshal(rawData, &parsed); err != nil {
|
if err := _json.Unmarshal(rawData, &parsed); err != nil {
|
||||||
return nil, 0, fmt.Errorf("JSON解析失败: %v, 原始数据: %s", err, string(rawData[:min(200, len(rawData))]))
|
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))
|
list := make([]ESBook, 0, len(parsed.Hits.Hits))
|
||||||
for _, hit := range parsed.Hits.Hits {
|
for _, hit := range parsed.Hits.Hits {
|
||||||
list = append(list, hit.Source)
|
list = append(list, hit.Source)
|
||||||
@ -1693,7 +1588,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 不作为查询条件的字段
|
// 不作为查询条件的字段
|
||||||
if key == "page" || key == "pageSize" || key == "per_page" || key == "saleSelect" || key == "picType" || key == "shopType" || key == "kongfz_include" {
|
if key == "page" || key == "pageSize" || key == "per_page" || key == "saleSelect" || key == "picType" || key == "shopType" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1715,6 +1610,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
key = nk
|
key = nk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== is_suit =====
|
||||||
if key == "is_suit" {
|
if key == "is_suit" {
|
||||||
fmt.Printf("[DEBUG] is_suit val=%q\n", val)
|
fmt.Printf("[DEBUG] is_suit val=%q\n", val)
|
||||||
if num, err := strconv.Atoi(val); err == nil {
|
if num, err := strconv.Atoi(val); err == nil {
|
||||||
@ -1729,6 +1625,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== is_return =====
|
||||||
if key == "is_return" {
|
if key == "is_return" {
|
||||||
fmt.Printf("[DEBUG] is_return val=%q\n", val)
|
fmt.Printf("[DEBUG] is_return val=%q\n", val)
|
||||||
if num, err := strconv.Atoi(val); err == nil {
|
if num, err := strconv.Atoi(val); err == nil {
|
||||||
@ -1743,6 +1640,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== is_filter =====
|
||||||
// ===== is_filter(按 shopType 位匹配)=====
|
// ===== is_filter(按 shopType 位匹配)=====
|
||||||
if key == "is_filter" {
|
if key == "is_filter" {
|
||||||
fmt.Printf("[DEBUG] is_filter val=%q\n", val)
|
fmt.Printf("[DEBUG] is_filter val=%q\n", val)
|
||||||
@ -1914,7 +1812,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
must = append(must, cond)
|
must = append(must, cond)
|
||||||
fmt.Printf("[DEBUG] must += %v\n", cond)
|
fmt.Printf("[DEBUG] must += %v\n", cond)
|
||||||
continue
|
continue
|
||||||
@ -1940,7 +1837,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
minVal, _ := strconv.Atoi(parts[0])
|
minVal, _ := strconv.Atoi(parts[0])
|
||||||
maxVal, _ := strconv.Atoi(parts[1])
|
maxVal, _ := strconv.Atoi(parts[1])
|
||||||
|
|
||||||
cond := map[string]interface{}{
|
cond := map[string]interface{}{
|
||||||
"range": map[string]interface{}{
|
"range": map[string]interface{}{
|
||||||
"total_sale": map[string]interface{}{
|
"total_sale": map[string]interface{}{
|
||||||
@ -1955,112 +1851,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== kongfz_categories(孔夫子分类)=====
|
|
||||||
if key == "kongfz_categories" {
|
|
||||||
kongfzInclude := c.DefaultQuery("kongfz_include", "1")
|
|
||||||
|
|
||||||
// 分割多个分类ID
|
|
||||||
categories := strings.Split(val, ",")
|
|
||||||
if len(categories) > 0 {
|
|
||||||
// 过滤空值
|
|
||||||
var validCategories []string
|
|
||||||
for _, catID := range categories {
|
|
||||||
catID = strings.TrimSpace(catID)
|
|
||||||
if catID != "" {
|
|
||||||
validCategories = append(validCategories, catID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(validCategories) > 0 {
|
|
||||||
if kongfzInclude == "2" {
|
|
||||||
// 否:查询不包含这些分类的数据(must_not)
|
|
||||||
var mustNotQueries []map[string]interface{}
|
|
||||||
for _, catID := range validCategories {
|
|
||||||
mustNotQueries = append(mustNotQueries, map[string]interface{}{
|
|
||||||
"prefix": map[string]interface{}{
|
|
||||||
"cat_id.kong_fu_zi_cat_id": catID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mustNotQueries) > 0 {
|
|
||||||
cond := map[string]interface{}{
|
|
||||||
"bool": map[string]interface{}{
|
|
||||||
"must_not": mustNotQueries,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
must = append(must, cond)
|
|
||||||
fmt.Printf("[DEBUG] must += %v (kongfz exclude: %d categories)\n", cond, len(mustNotQueries))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 是:查询包含这些分类的数据(should + minimum_should_match=1)
|
|
||||||
var shouldQueries []map[string]interface{}
|
|
||||||
for _, catID := range validCategories {
|
|
||||||
shouldQueries = append(shouldQueries, map[string]interface{}{
|
|
||||||
"prefix": map[string]interface{}{
|
|
||||||
"cat_id.kong_fu_zi_cat_id": catID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(shouldQueries) > 0 {
|
|
||||||
cond := map[string]interface{}{
|
|
||||||
"bool": map[string]interface{}{
|
|
||||||
"should": shouldQueries,
|
|
||||||
"minimum_should_match": 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
must = append(must, cond)
|
|
||||||
fmt.Printf("[DEBUG] must += %v (kongfz include: %d categories)\n", cond, len(shouldQueries))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== 数值范围 =====
|
// ===== 数值范围 =====
|
||||||
if key == "sell_counts" ||
|
if key == "sell_counts" ||
|
||||||
strings.HasPrefix(key, "day_sale_") ||
|
strings.HasPrefix(key, "day_sale_") ||
|
||||||
@ -2080,7 +1870,6 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
must = append(must, cond)
|
must = append(must, cond)
|
||||||
fmt.Printf("[DEBUG] must += %v\n", cond)
|
fmt.Printf("[DEBUG] must += %v\n", cond)
|
||||||
continue
|
continue
|
||||||
@ -2155,6 +1944,21 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
body, _ := json.MarshalIndent(query, "", " ")
|
body, _ := json.MarshalIndent(query, "", " ")
|
||||||
fmt.Printf("[DEBUG] ES Query Body:\n%s\n", string(body))
|
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()
|
endpoint := c.FullPath()
|
||||||
monitoredES := monitor.NewMonitoredESClient(svc.ES.Client, endpoint)
|
monitoredES := monitor.NewMonitoredESClient(svc.ES.Client, endpoint)
|
||||||
|
|
||||||
@ -2168,7 +1972,7 @@ func (svc *ESSearchService) BatchGetBookBaseInfoES(c *gin.Context) ([]ESBook, in
|
|||||||
|
|
||||||
res, duration, err := monitoredES.Search(context.Background(), &req)
|
res, duration, err := monitoredES.Search(context.Background(), &req)
|
||||||
|
|
||||||
//fmt.Printf("[DEBUG] ES Query Response:\n%s\n", res)
|
fmt.Printf("[DEBUG] ES Query Response:\n%s\n", res)
|
||||||
fmt.Printf("[DEBUG] ES 查询耗时:%dms\n", duration.Milliseconds())
|
fmt.Printf("[DEBUG] ES 查询耗时:%dms\n", duration.Milliseconds())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2490,191 +2294,165 @@ func (svc *ESSearchService) SearchBookByISBNHandler(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *ESSearchService) SearchByISBNByXyCallBack(c *gin.Context) {
|
// func (svc *ESSearchService) SearchBooksHandler(c *gin.Context) {
|
||||||
|
// isbn := c.Query("isbn")
|
||||||
isbn := c.Query("isbn")
|
// if isbn == "" {
|
||||||
if isbn == "" {
|
// c.JSON(400, gin.H{"error": "缺少 isbn 参数"})
|
||||||
log.Printf("[SearchBookByISBNHandler] 缺少 isbn 参数")
|
// return
|
||||||
c.JSON(400, gin.H{"error": "缺少 isbn 参数"})
|
// }
|
||||||
return
|
//
|
||||||
}
|
// ctx := context.Background()
|
||||||
|
//
|
||||||
log.Printf("[SearchBookByISBNHandler] 查询 ISBN: %s", isbn)
|
// db4Client, err := redisClient.GetClientByName("db1")
|
||||||
|
// if err == nil {
|
||||||
ctx := context.Background()
|
// val, err := db4Client.Get(ctx, isbn).Result()
|
||||||
endpoint := c.FullPath()
|
// if err == nil && val != "" {
|
||||||
|
// log.Printf("[SearchBooksHandler] 从 Redis db1 查询到数据: %s", isbn)
|
||||||
// ES 查询(使用监控)
|
// // 使用 RedisBookInfo 结构体解析
|
||||||
query := map[string]interface{}{
|
// var redisBook request.BookInfo
|
||||||
"query": map[string]interface{}{
|
// if err := json.Unmarshal([]byte(val), &redisBook); err == nil {
|
||||||
"term": map[string]interface{}{
|
// // 转换为 ESBook
|
||||||
"isbn": isbn,
|
// esBook := ConvertRedisBookToESBook(&redisBook)
|
||||||
},
|
// if esBook != nil {
|
||||||
},
|
// responseData := esBook.ConvertToResponse()
|
||||||
"_source": true,
|
// c.JSON(200, gin.H{
|
||||||
}
|
// "data": responseData,
|
||||||
|
// })
|
||||||
body, err := json.Marshal(query)
|
// return
|
||||||
if err != nil {
|
// }
|
||||||
log.Printf("[SearchBookByISBNHandler] 构建查询 JSON 失败:%v", err)
|
// } else {
|
||||||
c.JSON(500, gin.H{"error": "构建查询失败"})
|
// log.Printf("[SearchBookByISBNHandler] Redis 数据解析失败:%v", err)
|
||||||
return
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
req := esapi.SearchRequest{
|
//
|
||||||
Index: []string{ESIndex},
|
// result, err := svc.SearchBooks(isbn)
|
||||||
Body: bytes.NewReader(body),
|
// if err != nil {
|
||||||
TrackTotalHits: true,
|
// c.JSON(500, gin.H{"error": "ES 查询失败", "details": err.Error()})
|
||||||
Pretty: true,
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 创建监控客户端并执行查询
|
// responseList := make([]ESBookResponse, 0, len(result))
|
||||||
monitoredES := monitor.NewMonitoredESClient(svc.ES.Client, endpoint)
|
// for _, book := range result {
|
||||||
resp, duration, err := monitoredES.Search(ctx, &req)
|
// responseList = append(responseList, book.ConvertToResponse())
|
||||||
|
// }
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 查询耗时:%dms", duration.Milliseconds())
|
//
|
||||||
|
// c.JSON(200, gin.H{
|
||||||
if err != nil {
|
// "count": len(result),
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 查询失败:%v", err)
|
// "data": responseList,
|
||||||
c.JSON(500, gin.H{"error": "ES 查询失败:" + err.Error()})
|
// })
|
||||||
return
|
// }
|
||||||
}
|
//func (svc *ESSearchService) SearchBookByISBNHandler(c *gin.Context) {
|
||||||
defer resp.Body.Close()
|
//
|
||||||
|
// isbn := c.Query("isbn")
|
||||||
if resp.IsError() {
|
// if isbn == "" {
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 返回错误:%s", resp.String())
|
// log.Printf("[SearchBookByISBNHandler] 缺少 isbn 参数")
|
||||||
c.JSON(500, gin.H{"error": "ES 返回错误:" + resp.String()})
|
// c.JSON(400, gin.H{"error": "缺少 isbn 参数"})
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var parsed esHitsWrapper
|
// log.Printf("[SearchBookByISBNHandler] 查询 ISBN: %s", isbn)
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil {
|
//
|
||||||
log.Printf("[SearchBookByISBNHandler] 解析 ES 响应失败:%v", err)
|
// ctx := context.Background()
|
||||||
c.JSON(500, gin.H{"error": "解析响应失败"})
|
//
|
||||||
return
|
// db4Client, err := redisClient.GetClientByName("db1")
|
||||||
}
|
// fmt.Println(db4Client)
|
||||||
|
//
|
||||||
var result *ESBook
|
// if err != nil {
|
||||||
if len(parsed.Hits.Hits) > 0 {
|
// log.Printf("[SearchBookByISBNHandler] 获取 Redis db1 客户端失败: %v", err)
|
||||||
result = &parsed.Hits.Hits[0].Source
|
// } else {
|
||||||
}
|
// val, err := db4Client.Get(ctx, isbn).Result()
|
||||||
|
// if err == nil && val != "" {
|
||||||
if result == nil {
|
// log.Printf("[SearchBookByISBNHandler] 从 Redis db1 查询到数据: %s", isbn)
|
||||||
c.JSON(200, gin.H{
|
// // 使用 RedisBookInfo 结构体解析
|
||||||
"data": nil,
|
// var redisBook request.BookInfo
|
||||||
})
|
// if err := json.Unmarshal([]byte(val), &redisBook); err == nil {
|
||||||
return
|
// // 转换为 ESBook
|
||||||
}
|
// esBook := ConvertRedisBookToESBook(&redisBook)
|
||||||
|
// if esBook != nil {
|
||||||
responseData := result.ConvertToResponse()
|
// responseData := esBook.ConvertToResponse()
|
||||||
c.JSON(200, gin.H{
|
// c.JSON(200, gin.H{
|
||||||
"data": responseData,
|
// "data": responseData,
|
||||||
})
|
// })
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
func (svc *ESSearchService) SearchBookByISBNHandlerToPsi(c *gin.Context) {
|
// } else {
|
||||||
isbn := c.Query("isbn")
|
// log.Printf("[SearchBookByISBNHandler] Redis 数据解析失败:%v", err)
|
||||||
if isbn == "" {
|
// }
|
||||||
log.Printf("[SearchBookByISBNHandler] 缺少 isbn 参数")
|
// } else {
|
||||||
c.JSON(400, gin.H{"error": "缺少 isbn 参数"})
|
// log.Printf("[SearchBookByISBNHandler] Redis db1 中未找到 ISBN: %s", isbn)
|
||||||
return
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
log.Printf("[SearchBookByISBNHandler] 查询 ISBN: %s", isbn)
|
// result, err := svc.SearchBookByISBN(isbn)
|
||||||
|
// if err != nil {
|
||||||
ctx := context.Background()
|
// log.Printf("[SearchBookByISBNHandler] ES 查询失败: %v", err)
|
||||||
endpoint := c.FullPath()
|
// c.JSON(500, gin.H{"error": err.Error()})
|
||||||
|
// return
|
||||||
// Redis 查询(使用监控)
|
// }
|
||||||
db1Client, err := redisClient.GetClientByName("db10")
|
//
|
||||||
if err == nil {
|
// if result == nil {
|
||||||
monitoredRedis := monitor.NewMonitoredRedisClient(db1Client, endpoint)
|
// log.Printf("[SearchBookByISBNHandler] ES 中未找到 ISBN: %s,从孔夫子抓取", isbn)
|
||||||
val, _, err := monitoredRedis.Get(ctx, isbn)
|
//
|
||||||
if err == nil && val != "" {
|
// apiBook, err := kongfz.GetBookImageByISBN(isbn, "CALF_ELEPHANT_PROXY", "1297757178467602432", "QgQBvP7f")
|
||||||
log.Printf("[SearchBookByISBNHandler] 从 Redis db1 查询到数据:%s", isbn)
|
// if err != nil {
|
||||||
var redisBook request.BookInfoByPsi
|
// log.Printf("[SearchBookByISBNHandler] 孔夫子 API 查询失败: %v", err)
|
||||||
if err := json.Unmarshal([]byte(val), &redisBook); err == nil {
|
// c.JSON(500, gin.H{"error": err.Error()})
|
||||||
esBook := ConvertRedisBookToESBookByPsi(&redisBook)
|
// return
|
||||||
if esBook != nil {
|
// }
|
||||||
responseData := esBook.ConvertToResponseByPsi()
|
// if apiBook == nil || apiBook.Data.ISBN == "" {
|
||||||
c.JSON(200, gin.H{
|
// log.Printf("[SearchBookByISBNHandler] 孔夫子 API 未找到图书信息 ISBN: %s", isbn)
|
||||||
"data": responseData,
|
// c.JSON(404, gin.H{"error": "未找到图书信息"})
|
||||||
})
|
// return
|
||||||
return
|
// }
|
||||||
}
|
//
|
||||||
} else {
|
// log.Printf("[SearchBookByISBNHandler] 获取到图书信息: %+v", apiBook.Data)
|
||||||
log.Printf("[SearchBookByISBNHandler] Redis 数据解析失败:%v", err)
|
//
|
||||||
}
|
// pddBookPicURL := ""
|
||||||
}
|
// if apiBook.Data.BookPic != "" {
|
||||||
}
|
// url, err := image.DownloadAndUploadBookImage(apiBook.Data.BookPic, isbn, "true", apiBook.Data.BookName, "true")
|
||||||
|
// if err != nil {
|
||||||
// ES 查询(使用监控)
|
// log.Printf("[SearchBookByISBNHandler] 上传 book_pic 失败: %v", err)
|
||||||
query := map[string]interface{}{
|
// } else {
|
||||||
"query": map[string]interface{}{
|
// pddBookPicURL = url
|
||||||
"term": map[string]interface{}{
|
// log.Printf("[SearchBookByISBNHandler] 上传 book_pic 成功: %s", url)
|
||||||
"isbn": isbn,
|
// }
|
||||||
},
|
// }
|
||||||
},
|
//
|
||||||
"_source": true,
|
// pddBookPicSURL := ""
|
||||||
}
|
// if apiBook.Data.BookPicS != "" {
|
||||||
|
// url, err := image.DownloadAndUploadBookImage(apiBook.Data.BookPicS, isbn, "true", apiBook.Data.BookName, "true")
|
||||||
body, err := json.Marshal(query)
|
// if err != nil {
|
||||||
if err != nil {
|
// log.Printf("[SearchBookByISBNHandler] 上传 book_pic_s 失败: %v", err)
|
||||||
log.Printf("[SearchBookByISBNHandler] 构建查询 JSON 失败:%v", err)
|
// } else {
|
||||||
c.JSON(500, gin.H{"error": "构建查询失败"})
|
// pddBookPicSURL = url
|
||||||
return
|
// log.Printf("[SearchBookByISBNHandler] 上传 book_pic_s 成功: %s", url)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
req := esapi.SearchRequest{
|
//
|
||||||
Index: []string{ESIndex},
|
// esBook := ConvertKongfzToESBook(apiBook)
|
||||||
Body: bytes.NewReader(body),
|
//
|
||||||
TrackTotalHits: true,
|
// esBook.BookPicS.PddResponse = pddBookPicSURL
|
||||||
Pretty: true,
|
// esBook.BookPic.PddPath = pddBookPicURL
|
||||||
}
|
// //log.Printf("[SearchBookByISBNHandler] 写入 ES: %+v", esBook)
|
||||||
|
//
|
||||||
// 创建监控客户端并执行查询
|
// result, err = svc.AddBookToES(c.Request.Context(), esBook)
|
||||||
monitoredES := monitor.NewMonitoredESClient(svc.ES.Client, endpoint)
|
// if err != nil {
|
||||||
resp, duration, err := monitoredES.Search(ctx, &req)
|
// log.Printf("[SearchBookByISBNHandler] 写入 ES 失败: %v", err)
|
||||||
|
// c.JSON(500, gin.H{"error": err.Error()})
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 查询耗时:%dms", duration.Milliseconds())
|
// return
|
||||||
|
// }
|
||||||
if err != nil {
|
//
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 查询失败:%v", err)
|
// log.Printf("[SearchBookByISBNHandler] 写入 ES 成功, ISBN: %s", isbn)
|
||||||
c.JSON(500, gin.H{"error": "ES 查询失败:" + err.Error()})
|
// } else {
|
||||||
return
|
// //log.Printf("[SearchBookByISBNHandler] 从 ES 查询到图书: %+v", result)
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
//
|
||||||
|
// responseData := result.ConvertToResponse()
|
||||||
if resp.IsError() {
|
// c.JSON(200, gin.H{
|
||||||
log.Printf("[SearchBookByISBNHandler] ES 返回错误:%s", resp.String())
|
// "data": responseData,
|
||||||
c.JSON(500, gin.H{"error": "ES 返回错误:" + resp.String()})
|
// })
|
||||||
return
|
//}
|
||||||
}
|
|
||||||
|
|
||||||
var parsed esHitsWrapper
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil {
|
|
||||||
log.Printf("[SearchBookByISBNHandler] 解析 ES 响应失败:%v", err)
|
|
||||||
c.JSON(500, gin.H{"error": "解析响应失败"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *ESBook
|
|
||||||
if len(parsed.Hits.Hits) > 0 {
|
|
||||||
result = &parsed.Hits.Hits[0].Source
|
|
||||||
}
|
|
||||||
|
|
||||||
if result == nil {
|
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"data": nil,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
responseData := result.ConvertToResponseByPsi()
|
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"data": responseData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertKongfzToESBook 将第三方接口返回的数据转换为 ESBook 结构
|
// ConvertKongfzToESBook 将第三方接口返回的数据转换为 ESBook 结构
|
||||||
func ConvertKongfzToESBook(apiBook *kongfz.BookResponse) *ESBook {
|
func ConvertKongfzToESBook(apiBook *kongfz.BookResponse) *ESBook {
|
||||||
@ -3043,6 +2821,8 @@ func (svc *ESSearchService) UpdateBookSuitByISBNHandler(c *gin.Context) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(body)
|
||||||
|
|
||||||
payload, _ := json.Marshal(body)
|
payload, _ := json.Marshal(body)
|
||||||
|
|
||||||
res, err := svc.ES.Client.UpdateByQuery(
|
res, err := svc.ES.Client.UpdateByQuery(
|
||||||
@ -3130,6 +2910,7 @@ func (svc *ESSearchService) UpdateBookFieldsByISBNHandler(c *gin.Context) {
|
|||||||
|
|
||||||
// 先确认 ISBN 是否存在
|
// 先确认 ISBN 是否存在
|
||||||
book, err := svc.SearchBookByISBN(isbn)
|
book, err := svc.SearchBookByISBN(isbn)
|
||||||
|
fmt.Println("book:", book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
"error": "查询ES失败",
|
"error": "查询ES失败",
|
||||||
@ -3238,6 +3019,7 @@ func (svc *ESSearchService) UpdateBookFieldsByISBN(
|
|||||||
fmt.Sprintf("ctx._source.%s = params.%s;", field, field))
|
fmt.Sprintf("ctx._source.%s = params.%s;", field, field))
|
||||||
params[field] = value
|
params[field] = value
|
||||||
}
|
}
|
||||||
|
fmt.Println("scriptParts:", scriptParts)
|
||||||
if len(scriptParts) == 0 {
|
if len(scriptParts) == 0 {
|
||||||
return 0, fmt.Errorf("没有有效的字段可更新")
|
return 0, fmt.Errorf("没有有效的字段可更新")
|
||||||
}
|
}
|
||||||
@ -3844,10 +3626,6 @@ func (svc *ESSearchService) AddBookToES(ctx context.Context, req *ESBook) (*ESBo
|
|||||||
return nil, fmt.Errorf("ES返回错误: %s", res.String())
|
return nil, fmt.Errorf("ES返回错误: %s", res.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步 Redis
|
|
||||||
if svc.SyncRedisByISBN != nil {
|
|
||||||
_ = svc.SyncRedisByISBN(req.ISBN, "update")
|
|
||||||
}
|
|
||||||
return &newBook, nil
|
return &newBook, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4488,77 +4266,3 @@ func ConvertRedisBookToESBook(redisBook *request.BookInfo) *ESBook {
|
|||||||
IsFilter: "000000",
|
IsFilter: "000000",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertRedisBookToESBookByPsi 将 Redis 中的 BookInfo 转换为 ESBook
|
|
||||||
func ConvertRedisBookToESBookByPsi(redisBook *request.BookInfoByPsi) *ESBook {
|
|
||||||
if redisBook == nil || redisBook.Isbn == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建图片对象
|
|
||||||
carouselUrls := []string{}
|
|
||||||
if len(redisBook.ImageObject.CarouselUrlArray) > 0 {
|
|
||||||
carouselUrls = redisBook.ImageObject.CarouselUrlArray
|
|
||||||
}
|
|
||||||
|
|
||||||
liveShootingUrls := []string{}
|
|
||||||
if len(redisBook.ImageObject.DetailUrlObject.LiveShootingUrl) > 0 {
|
|
||||||
liveShootingUrls = redisBook.ImageObject.DetailUrlObject.LiveShootingUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取第一张轮播图作为 book_pic
|
|
||||||
bookPicPath := ""
|
|
||||||
if len(carouselUrls) > 0 {
|
|
||||||
bookPicPath = carouselUrls[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取第一张实拍图作为 book_pic_s
|
|
||||||
bookPicSResponse := ""
|
|
||||||
if len(liveShootingUrls) > 0 {
|
|
||||||
bookPicSResponse = liveShootingUrls[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ESBook{
|
|
||||||
ISBN: redisBook.Isbn,
|
|
||||||
BookName: FlexibleString{Value: redisBook.BookName},
|
|
||||||
Author: redisBook.Author,
|
|
||||||
Publisher: redisBook.Publishing,
|
|
||||||
PublicationTime: redisBook.PublicationDate,
|
|
||||||
BindingLayout: redisBook.Binding,
|
|
||||||
PageCount: NumberOrString(strconv.FormatInt(redisBook.PagesCount, 10)),
|
|
||||||
WordCount: NumberOrString(strconv.FormatInt(redisBook.WordsCount, 10)),
|
|
||||||
BookFormat: NumberOrString(strconv.FormatInt(redisBook.Format, 10)),
|
|
||||||
FixPrice: Float64OrString(redisBook.Price),
|
|
||||||
BookPic: BookPicObj{
|
|
||||||
LocalPath: "",
|
|
||||||
PddPath: bookPicPath,
|
|
||||||
},
|
|
||||||
BookPicS: BookPicSObj{
|
|
||||||
LocalPath: "",
|
|
||||||
PddResponse: bookPicSResponse,
|
|
||||||
},
|
|
||||||
BookDefPic: BookDefPicObj{
|
|
||||||
LocalPath: "",
|
|
||||||
PddPath: redisBook.ImageObject.DefaultImageUrl,
|
|
||||||
},
|
|
||||||
BookPicB: redisBook.ImageObject.WhiteBackgroundUrl,
|
|
||||||
CatId: redisBook.CatIdObject,
|
|
||||||
// 销量等字段默认为 0
|
|
||||||
DaySale7: 0,
|
|
||||||
DaySale15: 0,
|
|
||||||
DaySale30: 0,
|
|
||||||
DaySale60: 0,
|
|
||||||
DaySale90: 0,
|
|
||||||
DaySale180: 0,
|
|
||||||
DaySale365: 0,
|
|
||||||
ThisYearSale: 0,
|
|
||||||
LastYearSale: 0,
|
|
||||||
TotalSale: 0,
|
|
||||||
BuyCounts: 0,
|
|
||||||
SellCounts: 0,
|
|
||||||
IsSuit: redisBook.IsSuit,
|
|
||||||
IsIllegal: 0,
|
|
||||||
IsReturn: 0,
|
|
||||||
IsFilter: "000000",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
34
main.go
34
main.go
@ -163,18 +163,31 @@ func main() {
|
|||||||
//}
|
//}
|
||||||
//defer bookCenter.db.Close()
|
//defer bookCenter.db.Close()
|
||||||
// ======================= 新增:初始化 ES ============================
|
// ======================= 新增:初始化 ES ============================
|
||||||
/** 本地测试公网IP **/
|
/////** 旧ES,ES0 **/
|
||||||
//esClient, err := es.NewESClient(
|
//esClient, err := es.NewESClient(
|
||||||
// []string{"http://36.212.12.92:9527"},
|
// []string{"http://103.236.91.138:9200"},
|
||||||
// "elastic",
|
// "elastic",
|
||||||
// "+Tz5qR_KushZ-bPgZ_H-",
|
// "5mRDIUg52VC0fp14nw-F",
|
||||||
//)
|
//)
|
||||||
|
|
||||||
/** 线上使用内网IP **/
|
///** ES,ES1 **/
|
||||||
|
//esClient, err := es.NewESClient(
|
||||||
|
// []string{"http://103.236.74.207:9200"},
|
||||||
|
// "elastic",
|
||||||
|
// "y3h2fdYyrXewkSrY6uhh",
|
||||||
|
//)
|
||||||
|
|
||||||
|
/** 新ES,任务2 **/
|
||||||
|
//esClient, err := es.NewESClient(
|
||||||
|
// []string{"http://localhost:9200"},
|
||||||
|
// "elastic",
|
||||||
|
// "zDzSXel3PFwx9=6Ybmqv",
|
||||||
|
//)
|
||||||
|
/** ES2 本地测试 **/
|
||||||
esClient, err := es.NewESClient(
|
esClient, err := es.NewESClient(
|
||||||
[]string{"http://192.168.1.211:9527"},
|
[]string{"http://36.212.1.63:9200"},
|
||||||
"elastic",
|
"elastic",
|
||||||
"+Tz5qR_KushZ-bPgZ_H-",
|
"zDzSXel3PFwx9=6Ybmqv",
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -184,7 +197,7 @@ func main() {
|
|||||||
esService := es.NewESSearchService(esClient)
|
esService := es.NewESSearchService(esClient)
|
||||||
|
|
||||||
redisClient.AddClient("db4", "36.212.12.247:6379", "long6166@@", 2)
|
redisClient.AddClient("db4", "36.212.12.247:6379", "long6166@@", 2)
|
||||||
redisClient.AddClient("db1", "36.212.12.247:6379", "long6166@@", 7)
|
redisClient.AddClient("db1", "36.212.12.247:6379", "long6166@@", 1)
|
||||||
//redisClient.AddClient("test", "127.0.0.1:6379", "", 0)
|
//redisClient.AddClient("test", "127.0.0.1:6379", "", 0)
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
@ -293,10 +306,6 @@ func main() {
|
|||||||
r.GET("/api/es/searchByISBNLike", esService.SearchBooksHandler) //监控
|
r.GET("/api/es/searchByISBNLike", esService.SearchBooksHandler) //监控
|
||||||
// ISBN 精确搜索
|
// ISBN 精确搜索
|
||||||
r.GET("/api/es/searchByISBN", esService.SearchBookByISBNHandler) //监控
|
r.GET("/api/es/searchByISBN", esService.SearchBookByISBNHandler) //监控
|
||||||
// ISBN 精确搜索 为咸鱼商品下架回调
|
|
||||||
r.GET("/api/es/searchByISBNByXyCallBack", esService.SearchByISBNByXyCallBack) //监控
|
|
||||||
// ISBN 精确搜索 为psi提供
|
|
||||||
r.GET("/api/es/searchByISBNtoPsi", esService.SearchBookByISBNHandlerToPsi) //监控
|
|
||||||
// 书名搜索
|
// 书名搜索
|
||||||
r.GET("/api/es/searchByBookName", esService.SearchBookByBookNameHandler)
|
r.GET("/api/es/searchByBookName", esService.SearchBookByBookNameHandler)
|
||||||
// 全字段搜索
|
// 全字段搜索
|
||||||
@ -307,7 +316,6 @@ func main() {
|
|||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// 初始化控制器 新
|
// 初始化控制器 新
|
||||||
bookSearchService := service.NewBookService(esClient)
|
bookSearchService := service.NewBookService(esClient)
|
||||||
esService.SyncRedisByISBN = bookSearchService.SyncRedisByISBN
|
|
||||||
bookController := controller.NewBookController(bookSearchService)
|
bookController := controller.NewBookController(bookSearchService)
|
||||||
// 根据条件查询 ES 图书信息
|
// 根据条件查询 ES 图书信息
|
||||||
r.GET("/api/es/getBookBaseInfoES", bookController.SearchBookBaseInfoHandler)
|
r.GET("/api/es/getBookBaseInfoES", bookController.SearchBookBaseInfoHandler)
|
||||||
@ -315,7 +323,7 @@ func main() {
|
|||||||
r.POST("/api/es/addBookToES", bookController.AddBookToESHandler)
|
r.POST("/api/es/addBookToES", bookController.AddBookToESHandler)
|
||||||
// 更新:根据ISBN通用更新图书字段
|
// 更新:根据ISBN通用更新图书字段
|
||||||
r.POST("/api/es/updateBookFieldsByISBN", bookController.UpdateBookFieldsByISBNHandler)
|
r.POST("/api/es/updateBookFieldsByISBN", bookController.UpdateBookFieldsByISBNHandler)
|
||||||
// 更新:根据ISBN更新商品分类字段
|
// 更新:根据ISBN通用更新图书字段
|
||||||
r.POST("/api/es/updateBookCatIdByISBN", bookController.UpdateBookCatIdByISBNHandler)
|
r.POST("/api/es/updateBookCatIdByISBN", bookController.UpdateBookCatIdByISBNHandler)
|
||||||
// 删除:根据ISBN删除ES数据
|
// 删除:根据ISBN删除ES数据
|
||||||
r.GET("/api/es/DeleteBookByISBN", bookController.DeleteBookHandler)
|
r.GET("/api/es/DeleteBookByISBN", bookController.DeleteBookHandler)
|
||||||
|
|||||||
@ -2,42 +2,38 @@ package request
|
|||||||
|
|
||||||
// BookSearchRequest ES 搜索图书请求参数
|
// BookSearchRequest ES 搜索图书请求参数
|
||||||
type BookSearchRequest struct {
|
type BookSearchRequest struct {
|
||||||
Page int `form:"page"` // 页码
|
Page int `form:"page"` // 页码
|
||||||
PageSize int `form:"pageSize"` // 每页数量
|
PageSize int `form:"pageSize"` // 每页数量
|
||||||
PerPage int `form:"per_page"` // 每页数量 (兼容字段)
|
PerPage int `form:"per_page"` // 每页数量 (兼容字段)
|
||||||
SaleSelect string `form:"saleSelect"` // 销量筛选类型
|
SaleSelect string `form:"saleSelect"` // 销量筛选类型
|
||||||
PicType string `form:"picType"` // 图片类型
|
PicType string `form:"picType"` // 图片类型
|
||||||
ShopType string `form:"shopType"` // 店铺类型
|
ShopType string `form:"shopType"` // 店铺类型
|
||||||
BookName string `form:"book_name"` // 书名
|
BookName string `form:"book_name"` // 书名
|
||||||
BookPic string `form:"book_pic"` // 图片筛选
|
BookPic string `form:"book_pic"` // 图片筛选
|
||||||
ISBN string `form:"isbn"` // ISBN
|
ISBN string `form:"isbn"` // ISBN
|
||||||
Author string `form:"author"` // 作者
|
Author string `form:"author"` // 作者
|
||||||
Category string `form:"category"` // 分类
|
Category string `form:"category"` // 分类
|
||||||
CategoryType string `form:"categoryType"` // ISBN分类类型
|
CategoryType string `form:"categoryType"` // ISBN分类类型
|
||||||
Publisher string `form:"publisher"` // 出版社
|
Publisher string `form:"publisher"` // 出版社
|
||||||
PublicationTime string `form:"publication_time"` // 出版时间
|
PublicationTime string `form:"publication_time"` // 出版时间
|
||||||
BindingLayout string `form:"binding_layout"` // 装帧
|
BindingLayout string `form:"binding_layout"` // 装帧
|
||||||
FixPrice string `form:"fix_price"` // 定价
|
FixPrice string `form:"fix_price"` // 定价
|
||||||
IsSuit string `form:"isSuit"` // 是否套装
|
IsSuit string `form:"isSuit"` // 是否套装
|
||||||
IsReturn string `form:"is_return"` // 是否驳回
|
IsReturn string `form:"is_return"` // 是否驳回
|
||||||
IsFilter string `form:"is_filter"` // 过滤字段
|
IsFilter string `form:"is_filter"` // 过滤字段
|
||||||
BuyCounts string `form:"buy_counts"` // 购买次数
|
BuyCounts string `form:"buy_counts"` // 购买次数
|
||||||
SellCounts string `form:"sell_counts"` // 在售数量
|
SellCounts string `form:"sell_counts"` // 在售数量
|
||||||
DaySale7 string `form:"day_sale_7"` // 7 天销量
|
DaySale7 string `form:"day_sale_7"` // 7 天销量
|
||||||
DaySale15 string `form:"day_sale_15"` // 15 天销量
|
DaySale15 string `form:"day_sale_15"` // 15 天销量
|
||||||
DaySale30 string `form:"day_sale_30"` // 30 天销量
|
DaySale30 string `form:"day_sale_30"` // 30 天销量
|
||||||
DaySale60 string `form:"day_sale_60"` // 60 天销量
|
DaySale60 string `form:"day_sale_60"` // 60 天销量
|
||||||
DaySale90 string `form:"day_sale_90"` // 90 天销量
|
DaySale90 string `form:"day_sale_90"` // 90 天销量
|
||||||
DaySale180 string `form:"day_sale_180"` // 180 天销量
|
DaySale180 string `form:"day_sale_180"` // 180 天销量
|
||||||
DaySale365 string `form:"day_sale_365"` // 365 天销量
|
DaySale365 string `form:"day_sale_365"` // 365 天销量
|
||||||
ThisYearSale string `form:"this_year_sale"` // 今年销量
|
ThisYearSale string `form:"this_year_sale"` // 今年销量
|
||||||
LastYearSale string `form:"last_year_sale"` // 去年销量
|
LastYearSale string `form:"last_year_sale"` // 去年销量
|
||||||
TotalSaleRange string `form:"totalSale_range"` // 总销量范围
|
TotalSaleRange string `form:"totalSale_range"` // 总销量范围
|
||||||
ID string `form:"id"` // ID
|
ID string `form:"id"` // ID
|
||||||
PageCount string `form:"page_count"` // 页数
|
|
||||||
WordCount string `form:"word_count"` // 字数
|
|
||||||
KongfzCategories string `form:"kongfz_categories"` // 孔夫子分类列表,多个用逗号分隔
|
|
||||||
KongfzInclude int8 `form:"kongfz_include"` // 是否涵盖:1-是,2-否
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BookUpdateRequest 更新图书请求参数
|
// BookUpdateRequest 更新图书请求参数
|
||||||
@ -72,23 +68,6 @@ type BookInfo struct {
|
|||||||
CatIdObject CatIdObject `json:"cat_id"` // 分类
|
CatIdObject CatIdObject `json:"cat_id"` // 分类
|
||||||
}
|
}
|
||||||
|
|
||||||
// BookInfoByPsi 书籍信息结构
|
|
||||||
type BookInfoByPsi struct {
|
|
||||||
Isbn string `json:"isbn"` // ISBN
|
|
||||||
BookName string `json:"book_name"` // 书名
|
|
||||||
Author string `json:"author"` // 作者
|
|
||||||
Publishing string `json:"publishing"` // 出版社
|
|
||||||
PublicationDate string `json:"publication_date"` // 出版时间
|
|
||||||
Binding string `json:"binding"` // 装帧
|
|
||||||
PagesCount int64 `json:"pages_count"` // 页数
|
|
||||||
WordsCount int64 `json:"words_count"` // 字数
|
|
||||||
Format int64 `json:"format"` // 开本
|
|
||||||
ImageObject *ImageObject `json:"image_object"` // 图片
|
|
||||||
Price int64 `json:"price"` // 售价
|
|
||||||
CatIdObject CatIdObject `json:"cat_id"` // 分类
|
|
||||||
IsSuit int `json:"is_suit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageObject 图片对象结构
|
// ImageObject 图片对象结构
|
||||||
type ImageObject struct {
|
type ImageObject struct {
|
||||||
CarouselUrlArray []string `json:"carousel_url_array"` // 轮播图
|
CarouselUrlArray []string `json:"carousel_url_array"` // 轮播图
|
||||||
|
|||||||
517
service/book.go
517
service/book.go
@ -6,18 +6,18 @@ import (
|
|||||||
"centerBook/es"
|
"centerBook/es"
|
||||||
"centerBook/model/request"
|
"centerBook/model/request"
|
||||||
"centerBook/tail"
|
"centerBook/tail"
|
||||||
|
"centerBook/util"
|
||||||
"centerBook/util/redisClient"
|
"centerBook/util/redisClient"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/elastic/go-elasticsearch/v8/esapi"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/elastic/go-elasticsearch/v8/esapi"
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BookService 图书搜索服务
|
// BookService 图书搜索服务
|
||||||
@ -122,7 +122,6 @@ func (svc *BookService) SearchBookBaseInfo(request *request.BookSearchRequest) (
|
|||||||
svc.buildIsFilterCondition(queryBuilder, request.IsFilter, request.ShopType)
|
svc.buildIsFilterCondition(queryBuilder, request.IsFilter, request.ShopType)
|
||||||
svc.buildCategoryTypeCondition(queryBuilder, request.CategoryType)
|
svc.buildCategoryTypeCondition(queryBuilder, request.CategoryType)
|
||||||
svc.buildCategoryCondition(queryBuilder, request.Category)
|
svc.buildCategoryCondition(queryBuilder, request.Category)
|
||||||
svc.buildKongfzCategoryCondition(queryBuilder, request.KongfzCategories, request.KongfzInclude)
|
|
||||||
svc.buildBookPicCondition(queryBuilder, request.BookPic, request.PicType)
|
svc.buildBookPicCondition(queryBuilder, request.BookPic, request.PicType)
|
||||||
svc.buildBuyCountsCondition(queryBuilder, request.BuyCounts, saleField)
|
svc.buildBuyCountsCondition(queryBuilder, request.BuyCounts, saleField)
|
||||||
svc.buildTotalSaleRangeCondition(queryBuilder, request.TotalSaleRange)
|
svc.buildTotalSaleRangeCondition(queryBuilder, request.TotalSaleRange)
|
||||||
@ -269,44 +268,22 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
|||||||
var scriptParts []string
|
var scriptParts []string
|
||||||
params := make(map[string]interface{})
|
params := make(map[string]interface{})
|
||||||
|
|
||||||
//svc.AddFilterSet(request.ISBN)
|
// 判断 is_suit 是否已传递,如果没传则自动检测
|
||||||
// 先捕获 is_suit 的值,v3 同步/删除在 v2 更新完成后执行
|
if _, exists := request.Data["is_suit"]; !exists {
|
||||||
var hasIsSuitInData bool
|
// 未传递 is_suit,自动检测并设置
|
||||||
var isSuitInData interface{}
|
params["is_suit"] = map[bool]int{true: 1, false: 0}[es.CheckBookSuit(book.BookName.Value)]
|
||||||
if val, exists := request.Data["is_suit"]; exists {
|
scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_suit = params.is_suit;"))
|
||||||
hasIsSuitInData = true
|
|
||||||
isSuitInData = val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for field, value := range request.Data {
|
for field, value := range request.Data {
|
||||||
// 使用配置检查字段是否允许更新
|
// 使用配置检查字段是否允许更新
|
||||||
if !fieldConfig.IsAllowUpdate(field) {
|
if !fieldConfig.IsAllowUpdate(field) {
|
||||||
fmt.Printf("[UpdateBookFieldsByISBN] 字段 %s 不允许更新,已跳过", field)
|
log.Printf("[UpdateBookFieldsByISBN] 字段 %s 不允许更新,已跳过", field)
|
||||||
continue
|
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)
|
|
||||||
} else {
|
|
||||||
params[field] = value
|
|
||||||
}
|
|
||||||
scriptParts = append(scriptParts,
|
scriptParts = append(scriptParts,
|
||||||
fmt.Sprintf("ctx._source.%s = params.%s;", field, field))
|
fmt.Sprintf("ctx._source.%s = params.%s;", field, field))
|
||||||
|
params[field] = value
|
||||||
}
|
}
|
||||||
if len(scriptParts) == 0 {
|
if len(scriptParts) == 0 {
|
||||||
return nil, fmt.Errorf("没有有效的更新字段")
|
return nil, fmt.Errorf("没有有效的更新字段")
|
||||||
@ -323,7 +300,6 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fmt.Println("[DEBUG] ES UpdateByQuery Request Body:", body)
|
|
||||||
payload, _ := json.Marshal(body)
|
payload, _ := json.Marshal(body)
|
||||||
res, err := svc.esClient.Client.UpdateByQuery(
|
res, err := svc.esClient.Client.UpdateByQuery(
|
||||||
[]string{es.ESIndex},
|
[]string{es.ESIndex},
|
||||||
@ -354,18 +330,7 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
|||||||
|
|
||||||
// 同步 Redis
|
// 同步 Redis
|
||||||
_ = svc.SyncRedisByISBN(request.ISBN, "update")
|
_ = svc.SyncRedisByISBN(request.ISBN, "update")
|
||||||
// v2 已更新完成,此时操作 v3 索引
|
|
||||||
if hasIsSuitInData {
|
|
||||||
if isOneValue(isSuitInData) {
|
|
||||||
if err := svc.syncBookToV3Index(request.ISBN); err != nil {
|
|
||||||
log.Printf("[WARN] 同步到v3索引失败: %v", err)
|
|
||||||
}
|
|
||||||
} else if isZeroValue(isSuitInData) {
|
|
||||||
if err := svc.deleteBookFromV3Index(request.ISBN); err != nil {
|
|
||||||
log.Printf("[WARN] 从v3索引删除失败: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &UpdateBookResult{
|
return &UpdateBookResult{
|
||||||
ISBN: request.ISBN,
|
ISBN: request.ISBN,
|
||||||
Updated: parsed.Updated,
|
Updated: parsed.Updated,
|
||||||
@ -373,113 +338,6 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFilterSet 添加过滤集合(POST form-data)
|
|
||||||
//func (svc *BookService) AddFilterSet(isbn string) error {
|
|
||||||
// fmt.Println("AddFilterSet start")
|
|
||||||
// url := "https://erp.buzhiyushu.cn/zhishu/filterSet"
|
|
||||||
//
|
|
||||||
// // 创建 JSON 请求体
|
|
||||||
// jsonData := map[string]interface{}{
|
|
||||||
// "filterType": "1",
|
|
||||||
// "limitationType": "0",
|
|
||||||
// "addWay": "0",
|
|
||||||
// "addTxt": isbn,
|
|
||||||
// "sort": "0,3",
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// jsonBody, err := json.Marshal(jsonData)
|
|
||||||
// if err != nil {
|
|
||||||
// return fmt.Errorf("序列化 JSON 失败:%v", err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fmt.Println("[AddFilterSet] 创建 JSON 请求体", isbn)
|
|
||||||
//
|
|
||||||
// // 创建 HTTP 请求
|
|
||||||
// httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
|
|
||||||
// if err != nil {
|
|
||||||
// return fmt.Errorf("创建 HTTP 请求失败:%v", err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 设置请求头
|
|
||||||
// httpReq.Header.Set("Content-Type", "application/json")
|
|
||||||
//
|
|
||||||
// // 发送请求
|
|
||||||
// client := &http.Client{
|
|
||||||
// Timeout: 30 * time.Second,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// resp, err := client.Do(httpReq)
|
|
||||||
// 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
|
|
||||||
//}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
//}
|
|
||||||
|
|
||||||
// UpdateBookCatIdByISBNHandler 更新图书字段
|
// UpdateBookCatIdByISBNHandler 更新图书字段
|
||||||
func (svc *BookService) UpdateBookCatIdByISBNHandler(request *request.BookUpdateRequest) (*UpdateBookResult, error) {
|
func (svc *BookService) UpdateBookCatIdByISBNHandler(request *request.BookUpdateRequest) (*UpdateBookResult, error) {
|
||||||
// 先确认 ISBN 是否存在
|
// 先确认 ISBN 是否存在
|
||||||
@ -496,30 +354,13 @@ func (svc *BookService) UpdateBookCatIdByISBNHandler(request *request.BookUpdate
|
|||||||
return nil, fmt.Errorf("没有有效的更新字段")
|
return nil, fmt.Errorf("没有有效的更新字段")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建更新脚本,只更新传入的字段,保留现有字段
|
|
||||||
var scriptParts []string
|
|
||||||
params := make(map[string]interface{})
|
|
||||||
|
|
||||||
// 转换为 map 以便访问
|
|
||||||
newCatId, ok := catIdValue.(map[string]interface{})
|
|
||||||
if ok {
|
|
||||||
for key, value := range newCatId {
|
|
||||||
scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.cat_id.%s = params.%s;", key, key))
|
|
||||||
params[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(scriptParts) == 0 {
|
|
||||||
return nil, fmt.Errorf("没有有效的 cat_id 字段")
|
|
||||||
}
|
|
||||||
|
|
||||||
script := strings.Join(scriptParts, " ")
|
|
||||||
|
|
||||||
body := map[string]interface{}{
|
body := map[string]interface{}{
|
||||||
"script": map[string]interface{}{
|
"script": map[string]interface{}{
|
||||||
"source": script,
|
"source": "ctx._source.cat_id = params.cat_id;",
|
||||||
"lang": "painless",
|
"lang": "painless",
|
||||||
"params": params,
|
"params": map[string]interface{}{
|
||||||
|
"cat_id": catIdValue,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"query": map[string]interface{}{
|
"query": map[string]interface{}{
|
||||||
"term": map[string]interface{}{
|
"term": map[string]interface{}{
|
||||||
@ -743,10 +584,7 @@ func (svc *BookService) addBookToES(ctx context.Context, req *es.ESBook) (*es.ES
|
|||||||
// 处理出版时间,转换为时间戳
|
// 处理出版时间,转换为时间戳
|
||||||
publicationTimeTimestamp := req.PublicationTime
|
publicationTimeTimestamp := req.PublicationTime
|
||||||
if req.PublicationTime != "" && req.PublicationTime != "0" {
|
if req.PublicationTime != "" && req.PublicationTime != "0" {
|
||||||
publicationTimeIn64, err := strconv.ParseInt(req.PublicationTime, 10, 64)
|
publicationTimeTimestamp = strconv.FormatInt(util.ParsePublicationTime(publicationTimeTimestamp), 10)
|
||||||
if err == nil {
|
|
||||||
publicationTimeTimestamp = strconv.FormatInt(publicationTimeIn64+5364000000, 10)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 准备数据映射(使用 Go 字段名)
|
// 准备数据映射(使用 Go 字段名)
|
||||||
dataMap := make(map[string]interface{})
|
dataMap := make(map[string]interface{})
|
||||||
@ -795,6 +633,7 @@ func (svc *BookService) addBookToES(ctx context.Context, req *es.ESBook) (*es.ES
|
|||||||
if req.Other != nil {
|
if req.Other != nil {
|
||||||
dataMap["Other"] = req.Other
|
dataMap["Other"] = req.Other
|
||||||
}
|
}
|
||||||
|
fmt.Println("dataMap:", dataMap)
|
||||||
|
|
||||||
// 使用配置构建 ES 文档(自动转换字段名)
|
// 使用配置构建 ES 文档(自动转换字段名)
|
||||||
doc := es.GetESFieldConfig().BuildESDocument(dataMap)
|
doc := es.GetESFieldConfig().BuildESDocument(dataMap)
|
||||||
@ -887,7 +726,7 @@ func (svc *BookService) SyncRedisByISBN(isbn string, act string) error {
|
|||||||
if book.PublicationTime != "" && book.PublicationTime != "0" {
|
if book.PublicationTime != "" && book.PublicationTime != "0" {
|
||||||
publicationTimeIn64, err := strconv.ParseInt(book.PublicationTime, 10, 64)
|
publicationTimeIn64, err := strconv.ParseInt(book.PublicationTime, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
redisBookInfo.PublicationDate = time.Unix(publicationTimeIn64-5364000000, 0).Format("2006-01")
|
redisBookInfo.PublicationDate = time.Unix(publicationTimeIn64, 0).Format("2006-01")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if book.BindingLayout != "" {
|
if book.BindingLayout != "" {
|
||||||
@ -1062,199 +901,6 @@ func (svc *BookService) indexDocumentToES(ctx context.Context, doc map[string]in
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isOneValue 判断 interface{} 类型的值是否为 1
|
|
||||||
func isOneValue(v interface{}) bool {
|
|
||||||
switch val := v.(type) {
|
|
||||||
case int:
|
|
||||||
return val == 1
|
|
||||||
case int8:
|
|
||||||
return val == 1
|
|
||||||
case int16:
|
|
||||||
return val == 1
|
|
||||||
case int32:
|
|
||||||
return val == 1
|
|
||||||
case int64:
|
|
||||||
return val == 1
|
|
||||||
case float32:
|
|
||||||
return val == 1.0
|
|
||||||
case float64:
|
|
||||||
return val == 1.0
|
|
||||||
case string:
|
|
||||||
return val == "1"
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isZeroValue 判断 interface{} 类型的值是否为 0
|
|
||||||
func isZeroValue(v interface{}) bool {
|
|
||||||
switch val := v.(type) {
|
|
||||||
case int:
|
|
||||||
return val == 0
|
|
||||||
case int8:
|
|
||||||
return val == 0
|
|
||||||
case int16:
|
|
||||||
return val == 0
|
|
||||||
case int32:
|
|
||||||
return val == 0
|
|
||||||
case int64:
|
|
||||||
return val == 0
|
|
||||||
case float32:
|
|
||||||
return val == 0.0
|
|
||||||
case float64:
|
|
||||||
return val == 0.0
|
|
||||||
case string:
|
|
||||||
return val == "0"
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// searchBookByISBNInIndex 在指定索引中按 ISBN 查询文档
|
|
||||||
func (svc *BookService) searchBookByISBNInIndex(isbn string, index string) (*es.ESBook, error) {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] 开始查询 | ISBN=%s | index=%s", isbn, index)
|
|
||||||
|
|
||||||
query := map[string]interface{}{
|
|
||||||
"query": map[string]interface{}{
|
|
||||||
"term": map[string]interface{}{
|
|
||||||
"isbn": isbn,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"_source": true,
|
|
||||||
"size": 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := json.Marshal(query)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] 构建查询 JSON 失败:%v", err)
|
|
||||||
return nil, fmt.Errorf("构建查询 JSON 失败:%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := svc.esClient.Client.Search(
|
|
||||||
svc.esClient.Client.Search.WithIndex(index),
|
|
||||||
svc.esClient.Client.Search.WithBody(bytes.NewReader(body)),
|
|
||||||
svc.esClient.Client.Search.WithTrackTotalHits(true),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] ES 查询失败:%v", err)
|
|
||||||
return nil, fmt.Errorf("ES 查询失败:%v", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.IsError() {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] ES 返回错误:%s", res.String())
|
|
||||||
return nil, fmt.Errorf("ES 返回错误:%s", res.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
var parsed esHitsWrapper
|
|
||||||
|
|
||||||
if err := json.NewDecoder(res.Body).Decode(&parsed); err != nil {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] 解析 ES 响应失败:%v", err)
|
|
||||||
return nil, fmt.Errorf("解析 ES 响应失败:%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(parsed.Hits.Hits) == 0 {
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] 未找到 ISBN=%s 对应文档", isbn)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
book := parsed.Hits.Hits[0].Source
|
|
||||||
log.Printf("[SearchBookByISBNInIndex] 查询到文档: %+v", book)
|
|
||||||
|
|
||||||
return &book, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// indexDocumentToIndex 将文档写入指定索引(幂等:存在则覆盖,不存在则创建)
|
|
||||||
func (svc *BookService) indexDocumentToIndex(ctx context.Context, doc map[string]interface{}, id string, index string) error {
|
|
||||||
jsonData, _ := json.Marshal(doc)
|
|
||||||
|
|
||||||
esReq := esapi.IndexRequest{
|
|
||||||
Index: index,
|
|
||||||
DocumentID: id,
|
|
||||||
Body: bytes.NewReader(jsonData),
|
|
||||||
Refresh: "true",
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := esReq.Do(ctx, svc.esClient.Client.Transport)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("写入索引 %s 失败:%w", index, err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.IsError() {
|
|
||||||
return fmt.Errorf("写入索引 %s 错误:%s", index, res.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[IndexDocumentToIndex] 成功 | index=%s | id=%s", index, id)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// syncBookToV3Index 将 v2 索引中的文档同步到 v3 索引
|
|
||||||
// 先检查 v3 中是否已存在同 ISBN 文档,存在则覆盖更新,不存在则新增
|
|
||||||
func (svc *BookService) syncBookToV3Index(isbn string) error {
|
|
||||||
// 1. 从 v2 索引查询完整文档
|
|
||||||
book, err := svc.SearchBookByISBN(isbn)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("查询v2索引失败: %w", err)
|
|
||||||
}
|
|
||||||
if book == nil {
|
|
||||||
return fmt.Errorf("v2索引中未找到ISBN=%s的文档", isbn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 构建文档,追加 v3 专有字段
|
|
||||||
doc := svc.buildBookMapForSerialization(book)
|
|
||||||
doc["fid"] = 0
|
|
||||||
|
|
||||||
// 3. 检查 v3 中是否已存在
|
|
||||||
existing, err := svc.searchBookByISBNInIndex(isbn, es.ESIndexV3)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("查询v3索引失败: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
if existing != nil {
|
|
||||||
log.Printf("[SyncToV3] ISBN=%s 在v3中已存在,执行覆盖更新", isbn)
|
|
||||||
} else {
|
|
||||||
log.Printf("[SyncToV3] ISBN=%s 在v3中不存在,执行新增", isbn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 写入 v3 索引(IndexRequest 是幂等的:存在则覆盖,不存在则创建)
|
|
||||||
return svc.indexDocumentToIndex(ctx, doc, isbn, es.ESIndexV3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteBookFromV3Index 从 v3 索引中删除指定 ISBN 的文档
|
|
||||||
func (svc *BookService) deleteBookFromV3Index(isbn string) error {
|
|
||||||
// 先检查 v3 中是否存在
|
|
||||||
existing, err := svc.searchBookByISBNInIndex(isbn, es.ESIndexV3)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("查询v3索引失败: %w", err)
|
|
||||||
}
|
|
||||||
if existing == nil {
|
|
||||||
log.Printf("[DeleteFromV3] ISBN=%s 在v3中不存在,无需删除", isbn)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
req := esapi.DeleteRequest{
|
|
||||||
Index: es.ESIndexV3,
|
|
||||||
DocumentID: isbn,
|
|
||||||
Refresh: "true",
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := req.Do(ctx, svc.esClient.Client.Transport)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("从v3索引删除失败: %w", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.IsError() {
|
|
||||||
return fmt.Errorf("从v3索引删除错误: %s", res.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[DeleteFromV3] 成功删除 ISBN=%s 从v3索引", isbn)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLastID 获取最后一条 ID
|
// GetLastID 获取最后一条 ID
|
||||||
func (svc *BookService) GetLastID() (int, error) {
|
func (svc *BookService) GetLastID() (int, error) {
|
||||||
query := `{
|
query := `{
|
||||||
@ -1416,6 +1062,7 @@ func (svc *BookService) buildIsFilterCondition(builder *ESQueryBuilder, isFilter
|
|||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddQuery(&QueryCondition{
|
builder.AddQuery(&QueryCondition{
|
||||||
Field: "is_filter",
|
Field: "is_filter",
|
||||||
Type: "wildcard",
|
Type: "wildcard",
|
||||||
@ -1513,7 +1160,6 @@ func (svc *BookService) buildBuyCountsCondition(builder *ESQueryBuilder, buyCoun
|
|||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
minVal, _ := strconv.Atoi(parts[0])
|
minVal, _ := strconv.Atoi(parts[0])
|
||||||
maxVal, _ := strconv.Atoi(parts[1])
|
maxVal, _ := strconv.Atoi(parts[1])
|
||||||
// 普通范围查询,不包含 null 值
|
|
||||||
builder.AddQuery(&QueryCondition{
|
builder.AddQuery(&QueryCondition{
|
||||||
Field: saleField,
|
Field: saleField,
|
||||||
Type: "range",
|
Type: "range",
|
||||||
@ -1541,7 +1187,6 @@ func (svc *BookService) buildTotalSaleRangeCondition(builder *ESQueryBuilder, to
|
|||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
minVal, _ := strconv.Atoi(parts[0])
|
minVal, _ := strconv.Atoi(parts[0])
|
||||||
maxVal, _ := strconv.Atoi(parts[1])
|
maxVal, _ := strconv.Atoi(parts[1])
|
||||||
// 普通范围查询,不包含 null 值
|
|
||||||
builder.AddQuery(&QueryCondition{
|
builder.AddQuery(&QueryCondition{
|
||||||
Field: "total_sale",
|
Field: "total_sale",
|
||||||
Type: "range",
|
Type: "range",
|
||||||
@ -1565,8 +1210,6 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req
|
|||||||
"ThisYearSale": request.ThisYearSale,
|
"ThisYearSale": request.ThisYearSale,
|
||||||
"LastYearSale": request.LastYearSale,
|
"LastYearSale": request.LastYearSale,
|
||||||
"PublicationTime": request.PublicationTime,
|
"PublicationTime": request.PublicationTime,
|
||||||
"PageCount": request.PageCount,
|
|
||||||
"WordCount": request.WordCount,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esFields := map[string]string{
|
esFields := map[string]string{
|
||||||
@ -1581,8 +1224,6 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req
|
|||||||
"ThisYearSale": "this_year_sale",
|
"ThisYearSale": "this_year_sale",
|
||||||
"LastYearSale": "last_year_sale",
|
"LastYearSale": "last_year_sale",
|
||||||
"PublicationTime": "publication_time",
|
"PublicationTime": "publication_time",
|
||||||
"PageCount": "page_count",
|
|
||||||
"WordCount": "word_count",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for fieldName, value := range fields {
|
for fieldName, value := range fields {
|
||||||
@ -1591,20 +1232,50 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req
|
|||||||
}
|
}
|
||||||
esField := esFields[fieldName]
|
esField := esFields[fieldName]
|
||||||
parts := strings.Split(value, ",")
|
parts := strings.Split(value, ",")
|
||||||
|
fmt.Println("ppp", fieldName, parts)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
minVal, _ := strconv.Atoi(parts[0])
|
minVal, _ := strconv.Atoi(parts[0])
|
||||||
maxVal, _ := strconv.Atoi(parts[1])
|
maxVal, _ := strconv.Atoi(parts[1])
|
||||||
if fieldName == "PublicationTime" {
|
// 如果查询范围包含 0(0-999999),需要同时匹配 null 值
|
||||||
minVal += 5364000000
|
if minVal == 0 {
|
||||||
maxVal += 5364000000
|
// 使用 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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// 普通范围查询,不包含 null 值
|
//builder.AddQuery(&QueryCondition{
|
||||||
builder.AddQuery(&QueryCondition{
|
// Field: esField,
|
||||||
Field: esField,
|
// Type: "range",
|
||||||
Type: "range",
|
// GTE: minVal,
|
||||||
GTE: minVal,
|
// LTE: maxVal,
|
||||||
LTE: maxVal,
|
//})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1687,74 +1358,6 @@ func (svc *BookService) buildDefaultPrefixConditions(builder *ESQueryBuilder, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildKongfzCategoryCondition 构建孔夫子分类查询条件
|
|
||||||
func (svc *BookService) buildKongfzCategoryCondition(builder *ESQueryBuilder, kongfzCategories string, kongfzInclude int8) {
|
|
||||||
if kongfzCategories == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[DEBUG] kongfz_categories=%s, kongfz_include=%s", kongfzCategories, kongfzInclude)
|
|
||||||
|
|
||||||
// 分割多个分类ID
|
|
||||||
categories := strings.Split(kongfzCategories, ",")
|
|
||||||
if len(categories) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤空值
|
|
||||||
var validCategories []string
|
|
||||||
for _, catID := range categories {
|
|
||||||
catID = strings.TrimSpace(catID)
|
|
||||||
if catID != "" {
|
|
||||||
validCategories = append(validCategories, catID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(validCategories) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据 kongfzInclude 参数决定查询逻辑
|
|
||||||
if kongfzInclude == 2 {
|
|
||||||
// 否:查询不包含这些分类的数据(must_not)
|
|
||||||
var mustNotQueries []map[string]interface{}
|
|
||||||
for _, catID := range validCategories {
|
|
||||||
mustNotQueries = append(mustNotQueries, map[string]interface{}{
|
|
||||||
"prefix": map[string]interface{}{
|
|
||||||
"cat_id.kong_fu_zi_cat_id": catID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mustNotQueries) > 0 {
|
|
||||||
builder.AddBoolQuery("must_not", mustNotQueries)
|
|
||||||
log.Printf("[DEBUG] Added %d kongfz category exclude queries (must_not)", len(mustNotQueries))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 是:查询包含这些分类的数据(should + minimum_should_match=1)
|
|
||||||
var shouldQueries []map[string]interface{}
|
|
||||||
for _, catID := range validCategories {
|
|
||||||
shouldQueries = append(shouldQueries, map[string]interface{}{
|
|
||||||
"prefix": map[string]interface{}{
|
|
||||||
"cat_id.kong_fu_zi_cat_id": catID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(shouldQueries) > 0 {
|
|
||||||
// 将 should 条件包装成内层 bool 对象,作为 must 条件添加
|
|
||||||
innerBoolQuery := map[string]interface{}{
|
|
||||||
"bool": map[string]interface{}{
|
|
||||||
"should": shouldQueries,
|
|
||||||
"minimum_should_match": 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
builder.AddBoolQuery("must", []map[string]interface{}{innerBoolQuery})
|
|
||||||
log.Printf("[DEBUG] Added kongfz category include query as nested bool in must (should match at least 1)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewESQueryBuilder 创建 ES 查询构建器
|
// NewESQueryBuilder 创建 ES 查询构建器
|
||||||
func NewESQueryBuilder() *ESQueryBuilder {
|
func NewESQueryBuilder() *ESQueryBuilder {
|
||||||
return &ESQueryBuilder{
|
return &ESQueryBuilder{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user