字段兼容
This commit is contained in:
parent
48b4d89510
commit
d1e2366a4d
@ -25,7 +25,7 @@ import (
|
||||
"github.com/elastic/go-elasticsearch/v8/esapi"
|
||||
)
|
||||
|
||||
const ESIndex = "books-from-mysql-v2"
|
||||
const ESIndex = "books-from-mysql-v3"
|
||||
|
||||
// ESBookResponse 用于返回给Java客户端的格式,ID为简单的int64
|
||||
type ESBookResponse struct {
|
||||
|
||||
304
service/book.go
304
service/book.go
@ -15,6 +15,8 @@ import (
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -117,8 +119,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)
|
||||
@ -268,11 +270,51 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
||||
var scriptParts []string
|
||||
params := make(map[string]interface{})
|
||||
|
||||
//svc.AddFilterSet(request.ISBN)
|
||||
// 判断 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,自动检测并设置
|
||||
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;"))
|
||||
|
||||
// 如果 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 {
|
||||
@ -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)
|
||||
res, err := svc.esClient.Client.UpdateByQuery(
|
||||
[]string{es.ESIndex},
|
||||
@ -330,7 +378,7 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
||||
|
||||
// 同步 Redis
|
||||
_ = svc.SyncRedisByISBN(request.ISBN, "update")
|
||||
|
||||
//svc.AddFilterSet(request.ISBN)
|
||||
return &UpdateBookResult{
|
||||
ISBN: request.ISBN,
|
||||
Updated: parsed.Updated,
|
||||
@ -338,6 +386,113 @@ func (svc *BookService) UpdateBookFieldsByISBN(request *request.BookUpdateReques
|
||||
}, 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 更新图书字段
|
||||
func (svc *BookService) UpdateBookCatIdByISBNHandler(request *request.BookUpdateRequest) (*UpdateBookResult, error) {
|
||||
// 先确认 ISBN 是否存在
|
||||
@ -1010,11 +1165,45 @@ 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",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
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",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
log.Printf("[ERROR] is_return Atoi error: %v", err)
|
||||
}
|
||||
@ -1063,12 +1286,49 @@ func (svc *BookService) buildIsFilterCondition(builder *ESQueryBuilder, isFilter
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// buildCategoryTypeCondition 构建 categoryType 查询条件
|
||||
func (svc *BookService) buildCategoryTypeCondition(builder *ESQueryBuilder, categoryType string) {
|
||||
@ -1187,6 +1447,33 @@ 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",
|
||||
@ -1195,6 +1482,7 @@ func (svc *BookService) buildTotalSaleRangeCondition(builder *ESQueryBuilder, to
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buildNumericRangeConditions 构建数值范围查询条件
|
||||
func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, request *request.BookSearchRequest, saleField string) {
|
||||
@ -1270,12 +1558,6 @@ func (svc *BookService) buildNumericRangeConditions(builder *ESQueryBuilder, req
|
||||
LTE: maxVal,
|
||||
})
|
||||
}
|
||||
//builder.AddQuery(&QueryCondition{
|
||||
// Field: esField,
|
||||
// Type: "range",
|
||||
// GTE: minVal,
|
||||
// LTE: maxVal,
|
||||
//})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user