字段兼容
This commit is contained in:
parent
48b4d89510
commit
d1e2366a4d
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/elastic/go-elasticsearch/v8/esapi"
|
"github.com/elastic/go-elasticsearch/v8/esapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ESIndex = "books-from-mysql-v2"
|
const ESIndex = "books-from-mysql-v3"
|
||||||
|
|
||||||
// ESBookResponse 用于返回给Java客户端的格式,ID为简单的int64
|
// ESBookResponse 用于返回给Java客户端的格式,ID为简单的int64
|
||||||
type ESBookResponse struct {
|
type ESBookResponse struct {
|
||||||
|
|||||||
346
service/book.go
346
service/book.go
@ -15,6 +15,8 @@ import (
|
|||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -117,8 +119,8 @@ func (svc *BookService) SearchBookBaseInfo(request *request.BookSearchRequest) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ========== 构建查询条件 ==========
|
// ========== 构建查询条件 ==========
|
||||||
svc.buildISuitCondition(queryBuilder, request.IsSuit)
|
//svc.buildISuitCondition(queryBuilder, request.IsSuit)
|
||||||
svc.buildIsReturnCondition(queryBuilder, request.IsReturn)
|
//svc.buildIsReturnCondition(queryBuilder, request.IsReturn)
|
||||||
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)
|
||||||
@ -268,11 +270,51 @@ 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 是否已传递,如果没传则自动检测
|
||||||
if _, exists := request.Data["is_suit"]; !exists {
|
if isSuitValue, exists := request.Data["is_suit"]; exists {
|
||||||
|
// 定义一个辅助函数来检查值是否为 1
|
||||||
|
isOne := func(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果手动传递了 is_suit,检查是否为 1
|
||||||
|
if isOne(isSuitValue) {
|
||||||
|
params["is_filter"] = "100100"
|
||||||
|
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,自动检测并设置
|
// 未传递 is_suit,自动检测并设置
|
||||||
params["is_suit"] = map[bool]int{true: 1, false: 0}[es.CheckBookSuit(book.BookName.Value)]
|
isSuitValue := map[bool]int{true: 1, false: 0}[es.CheckBookSuit(book.BookName.Value)]
|
||||||
|
params["is_suit"] = isSuitValue
|
||||||
scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_suit = params.is_suit;"))
|
scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_suit = params.is_suit;"))
|
||||||
|
|
||||||
|
// 如果 is_suit 为 1,同时更新 is_filter 为 100100
|
||||||
|
if isSuitValue == 1 {
|
||||||
|
params["is_filter"] = "100100"
|
||||||
|
scriptParts = append(scriptParts, fmt.Sprintf("ctx._source.is_filter = params.is_filter;"))
|
||||||
|
log.Printf("[UpdateBookFieldsByISBN] 自动检测到 is_suit=1,设置 is_filter=100100 | ISBN=%s", request.ISBN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for field, value := range request.Data {
|
for field, value := range request.Data {
|
||||||
@ -300,6 +342,12 @@ 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)
|
payload, _ := json.Marshal(body)
|
||||||
res, err := svc.esClient.Client.UpdateByQuery(
|
res, err := svc.esClient.Client.UpdateByQuery(
|
||||||
[]string{es.ESIndex},
|
[]string{es.ESIndex},
|
||||||
@ -330,7 +378,7 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
|||||||
|
|
||||||
// 同步 Redis
|
// 同步 Redis
|
||||||
_ = svc.SyncRedisByISBN(request.ISBN, "update")
|
_ = svc.SyncRedisByISBN(request.ISBN, "update")
|
||||||
|
//svc.AddFilterSet(request.ISBN)
|
||||||
return &UpdateBookResult{
|
return &UpdateBookResult{
|
||||||
ISBN: request.ISBN,
|
ISBN: request.ISBN,
|
||||||
Updated: parsed.Updated,
|
Updated: parsed.Updated,
|
||||||
@ -338,6 +386,113 @@ 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 是否存在
|
||||||
@ -1010,11 +1165,45 @@ func (svc *BookService) buildISuitCondition(builder *ESQueryBuilder, isSuit stri
|
|||||||
}
|
}
|
||||||
log.Printf("[DEBUG] is_suit val=%q", isSuit)
|
log.Printf("[DEBUG] is_suit val=%q", isSuit)
|
||||||
if num, err := strconv.Atoi(isSuit); err == nil {
|
if num, err := strconv.Atoi(isSuit); err == nil {
|
||||||
builder.AddQuery(&QueryCondition{
|
if num == 0 {
|
||||||
Field: "is_suit",
|
valueQuery := map[string]interface{}{
|
||||||
Value: num,
|
"term": map[string]interface{}{
|
||||||
Type: "term",
|
"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",
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[ERROR] is_suit Atoi error: %v", err)
|
log.Printf("[ERROR] is_suit Atoi error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1027,11 +1216,45 @@ func (svc *BookService) buildIsReturnCondition(builder *ESQueryBuilder, isReturn
|
|||||||
}
|
}
|
||||||
log.Printf("[DEBUG] is_return val=%q", isReturn)
|
log.Printf("[DEBUG] is_return val=%q", isReturn)
|
||||||
if num, err := strconv.Atoi(isReturn); err == nil {
|
if num, err := strconv.Atoi(isReturn); err == nil {
|
||||||
builder.AddQuery(&QueryCondition{
|
if num == 0 {
|
||||||
Field: "is_return",
|
valueQuery := map[string]interface{}{
|
||||||
Value: num,
|
"term": map[string]interface{}{
|
||||||
Type: "term",
|
"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",
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[ERROR] is_return Atoi error: %v", err)
|
log.Printf("[ERROR] is_return Atoi error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1063,11 +1286,48 @@ func (svc *BookService) buildIsFilterCondition(builder *ESQueryBuilder, isFilter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddQuery(&QueryCondition{
|
if isFilter == "2" {
|
||||||
Field: "is_filter",
|
wildcardQuery := map[string]interface{}{
|
||||||
Type: "wildcard",
|
"wildcard": map[string]interface{}{
|
||||||
Pattern: pattern,
|
"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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildCategoryTypeCondition 构建 categoryType 查询条件
|
// buildCategoryTypeCondition 构建 categoryType 查询条件
|
||||||
@ -1187,12 +1447,40 @@ 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])
|
||||||
builder.AddQuery(&QueryCondition{
|
// 如果查询范围包含 0(0-999999),需要同时匹配 null 值
|
||||||
Field: "total_sale",
|
if minVal == 0 {
|
||||||
Type: "range",
|
// 使用 bool should 查询:匹配范围内值 OR 字段为 null/不存在
|
||||||
GTE: minVal,
|
rangeQuery := map[string]interface{}{
|
||||||
LTE: maxVal,
|
"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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1270,12 +1558,6 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req
|
|||||||
LTE: maxVal,
|
LTE: maxVal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//builder.AddQuery(&QueryCondition{
|
|
||||||
// Field: esField,
|
|
||||||
// Type: "range",
|
|
||||||
// GTE: minVal,
|
|
||||||
// LTE: maxVal,
|
|
||||||
//})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user