代码拉取完成,页面将自动刷新
package dsl
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strconv"
"strings"
"unicode"
"gitee.com/linqwen/momo/utils"
// "github.com/mitchellh/mapstructure"
)
type IDSLDao interface {
BulkCreate(indexName string, docs []map[string]interface{}) error
BulkDelete(indexName string, ids []string) error
Create(indexName string, doc interface{}) error
Search(indexName string, query interface{}) ([]byte, error)
Update(indexName, id string, update interface{}) error
Delete(indexName, id string) error
// PageByDTO(indexName string, dto map[string]string, pageNum, pageSize int) (*ESResponse, int, error)
PageByDTO(queryDto interface{}, queryPage *QueryPage) (*ESResponse, int, error)
}
type QueryPage struct {
Current int `json:"current" form:"current"`
Size int `json:"size" form:"size"`
Ascs []string `json:"ascs" form:"ascs"`
Descs []string `json:"descs" form:"descs"`
}
// ZincClient 代表与ZincSearch交互的客户端
type ZincClient struct {
Host string
Username string
Password string
}
// NewZincClient 创建一个新的ZincSearch客户端实例
func NewZincClient(host, username, password string) *ZincClient {
return &ZincClient{
Host: host,
Username: username,
Password: password,
}
}
// sendRequest 是发送HTTP请求的辅助函数,用于执行CRUD操作
func (zc *ZincClient) sendRequest(method, path string, body []byte) ([]byte, error) {
url := zc.Host + path
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return nil, err
}
if zc.Username != "" && zc.Password != "" {
auth := fmt.Sprintf("%s:%s", zc.Username, zc.Password)
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
// 修改后的 BulkCreateDocuments 方法直接接受 []map[string]interface{}
func (zc *ZincClient) BulkCreate(indexName string, docs []map[string]interface{}) error {
var actions []interface{}
for _, doc := range docs {
action := map[string]interface{}{
"create": map[string]interface{}{
"_index": indexName,
},
"doc": doc,
}
actions = append(actions, action)
actions = append(actions, "") // 分隔符
}
body, err := json.Marshal(actions)
if err != nil {
return err
}
_, err = zc.sendRequest("POST", "/api/_bulk", body)
return err
}
// BulkDeleteDocuments 批量删除指定索引中的文档
func (zc *ZincClient) BulkDelete(indexName string, ids []string) error {
var actions []map[string]interface{}
for _, id := range ids {
action := map[string]interface{}{
"delete": map[string]interface{}{
"_index": indexName,
"_id": id,
},
}
actions = append(actions, action)
// 分隔符,用于区分每个操作
actions = append(actions, nil)
}
body, err := json.Marshal(actions)
if err != nil {
return err
}
_, err = zc.sendRequest("POST", "/api/_bulk", body)
return err
}
// CreateDocument 向指定索引添加文档
func (zc *ZincClient) Create(indexName string, doc interface{}) error {
body, err := json.Marshal(doc)
if err != nil {
return err
}
_, err = zc.sendRequest("POST", "/api/"+indexName+"/_doc", body)
return err
}
// CreateDocument 向指定索引添加文档
func (zc *ZincClient) CreateWithId(indexName string, doc interface{}, id int64) error {
body, err := json.Marshal(doc)
if err != nil {
return err
}
_, err = zc.sendRequest("PUT", "/api/"+indexName+"/_doc/"+strconv.FormatInt(id, 10), body)
return err
}
// SearchDocuments 在指定索引中搜索文档
func (zc *ZincClient) Search(indexName string, query interface{}) ([]byte, error) {
body, err := json.Marshal(query)
if err != nil {
return nil, err
}
return zc.sendRequest("POST", "/api/"+indexName+"/_search", body)
}
// UpdateDocument 更新指定索引中的文档
func (zc *ZincClient) Update(indexName, id string, update interface{}) error {
body, err := json.Marshal(update)
if err != nil {
return err
}
_, err = zc.sendRequest("POST", "/api/"+indexName+"/_update/"+id+"", body)
return err
}
// DeleteDocument 删除指定索引中的文档
func (zc *ZincClient) Delete(indexName, id string) error {
_, err := zc.sendRequest("DELETE", "/api/"+indexName+"/_doc/"+id, nil)
return err
}
type TotalHits struct {
Value int `json:"value"`
Relation string `json:"relation,omitempty"` // 可选,用于区分是否确切计数(如"eq"表示等于)
}
type ESResponse struct {
Hits Hits `json:"hits"`
}
type Hits struct {
Total TotalHits `json:"total"`
MaxScore float64 `json:"max_score"`
Hits []HitElement `json:"hits"`
}
type HitElement struct {
Index string `json:"_index"`
Id string `json:"_id"`
Score float64 `json:"_score"`
Source map[string]interface{} `json:"_source"`
}
func (zc *ZincClient) PageByDTO(indexName string, dto any, queryPage QueryPage) (*ESResponse, int, error) {
url := fmt.Sprintf("%s/es/%s/_search", zc.Host, indexName)
// dtoMap := make(map[string]interface{})
// mapstructure.Decode(dto, &dtoMap)
dtoMap, _ := utils.StructUtil.StructToMapWithColumn(dto)
body, err := zc.buildQueryBody(dtoMap, queryPage)
if err != nil {
return nil, 0, fmt.Errorf("failed to buildQueryBody: %v", err)
}
fmt.Println("dsl", string(body))
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
return nil, 0, fmt.Errorf("failed to create request: %v", err)
}
if zc.Username != "" && zc.Password != "" {
req.SetBasicAuth(zc.Username, zc.Password)
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, 0, fmt.Errorf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
respBody, err := ioutil.ReadAll(resp.Body)
var esResponse ESResponse
err = json.Unmarshal(respBody, &esResponse)
if err != nil {
return nil, 0, fmt.Errorf("failed to unmarshal response body: %v", err)
}
return &esResponse, esResponse.Hits.Total.Value, nil
}
// 构建符合需求的查询体
func (zc *ZincClient) buildQueryBody(dto map[string]any, page QueryPage) ([]byte, error) {
esQuery := make(map[string]interface{})
sort := make([]interface{}, 0)
for _, asc := range page.Ascs {
sort = append(sort, map[string]interface{}{
asc: map[string]interface{}{
"order": "asc",
},
})
}
for _, desc := range page.Descs {
sort = append(sort, map[string]interface{}{
desc: map[string]interface{}{
"order": "desc",
},
})
}
if len(sort) == 0 {
sort = append(sort, map[string]interface{}{
"@timestamp": map[string]interface{}{
"order": "desc",
},
})
}
esQuery["sort"] = sort
esQuery["from"] = (page.Current - 1) * page.Size
esQuery["size"] = page.Size
esQuery["max_results"] = page.Size
must := make([]interface{}, 0)
if len(dto) > 0 {
// 处理不同类型的查询条件
for k, v := range dto {
if gte, ok := strings.CutSuffix(k, "_gte"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(gte): map[string]interface{}{
"gte": v,
},
},
}
must = append(must, q)
}
} else if gt, ok := strings.CutSuffix(k, "_gt"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(gt): map[string]interface{}{
"gt": v,
},
},
}
must = append(must, q)
}
} else if lte, ok := strings.CutSuffix(k, "_lte"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(lte): map[string]interface{}{
"lte": v,
},
},
}
must = append(must, q)
}
} else if lt, ok := strings.CutSuffix(k, "_lt"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(lt): map[string]interface{}{
"lt": v,
},
},
}
must = append(must, q)
}
} else if datelt, ok := strings.CutSuffix(k, "_datelt"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(datelt): map[string]interface{}{
"lt": v,
"format": "2006-01-02T15:04:05Z07:00",
},
},
}
must = append(must, q)
}
} else if datelte, ok := strings.CutSuffix(k, "_datelte"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(datelte): map[string]interface{}{
"lte": v,
"format": "2006-01-02T15:04:05Z07:00",
},
},
}
must = append(must, q)
}
} else if dategt, ok := strings.CutSuffix(k, "_dategt"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(dategt): map[string]interface{}{
"gt": v,
"format": "2006-01-02T15:04:05Z07:00",
},
},
}
must = append(must, q)
}
} else if dategte, ok := strings.CutSuffix(k, "_dategte"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"range": map[string]interface{}{
CamelToSnake(dategte): map[string]interface{}{
"gte": v,
"format": "2006-01-02T15:04:05Z07:00",
},
},
}
must = append(must, q)
}
} else if like, ok := strings.CutSuffix(k, "_like"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
s := v.(string)
q := map[string]interface{}{
"wildcard": map[string]interface{}{
CamelToSnake(like): "*" + s + "*",
},
}
must = append(must, q)
}
} else if likeleft, ok := strings.CutSuffix(k, "_likeleft"); ok {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"prefix": map[string]interface{}{
CamelToSnake(likeleft): v,
},
}
must = append(must, q)
}
} else {
if !isEmptyValue(reflect.ValueOf(v)) {
q := map[string]interface{}{
"match_phrase": map[string]interface{}{
CamelToSnake(k): map[string]interface{}{
"query": v,
},
},
}
must = append(must, q)
}
}
}
}
if len(must) > 0 {
esQuery["query"] = map[string]interface{}{
"bool": map[string]interface{}{
"must": must,
},
}
} else {
esQuery["query"] = map[string]interface{}{
"match_all": map[string]interface{}{},
}
}
body, err := json.MarshalIndent(esQuery, "", " ")
if err != nil {
return nil, fmt.Errorf("Failed to marshal query body: %v", err)
}
return body, nil
}
var ZincClientObj = NewZincClient("http://192.168.1.200:4080", "admin", "admin")
// CamelToSnake 将驼峰命名转换为下划线命名
func CamelToSnake(s string) string {
var result strings.Builder
for i, r := range s {
if unicode.IsUpper(r) && i > 0 {
result.WriteRune('_')
}
result.WriteRune(unicode.ToLower(r))
}
return result.String()
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Ptr, reflect.Array, reflect.Slice, reflect.Map:
return v.IsNil()
case reflect.String:
return v.String() == ""
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Struct:
return false // Assuming non-zero-value structs are considered non-empty
default:
return false
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。