[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-17":3},{"id":4,"title":5,"title_en":6,"abstract":7,"abstract_en":8,"content":9,"content_en":10,"category":11,"banner_id":12,"banner_path":13,"tags":14,"is_recommend":17,"prev_article":18,"next_article":22,"created_at":26},17,"Go + Elasticsearch 实现智能搜索功能","Go + Elasticsearch enables intelligent search","🎯 项目背景\n\n> 在现代内容平台中，搜索功能是用户获取信息的核心入口。传统的数据库 LIKE 查询在面对海量数据时性能急剧下降，而全文搜索引擎 Elasticsearch 能够提供毫秒级的搜索响应。本文将详细介绍如何使用 Go + Elasticsearch 构建一个功能完整的智能搜索系统。\n\n## ✨ 系统特性\n#### 🚀 高性能搜索\n- 全文检索：支持标题、内容、摘要的多字段搜索\n- 权重排序：标题权重 3x，内容权重 2x，摘要权重 1x\n- 高亮显示：搜索关键词自动高亮标记\n- 毫秒响应：平均响应时间 \u003C 50ms\n#### 🎯 智能推荐\n- 标签相似度：基于 Jaccard 系数计算文章相似性\n- 用户行为：点赞、收藏行为影响推荐权重\n- 时间衰减：新文章获得更高推荐权重\n- 缓存优化：Redis 缓存推荐结果，提升性能\n#### 🔄 数据同步\n- 实时同步：文章 CRUD 操作自动同步到 ES\n- 批量操作：支持批量删除和更新\n- 错误重试：网络异常自动重试机制\n- 定时全量：定时任务保证数据一致性\n\n## 🏗️ 系统架构\n#### 核心组件\n\n\n```mermaid\ngraph LR\n    A[Web API] --> B[Service]\n    B --> C[Elasticsearch]\n    A --> D[MySQL]\n    B --> E[Redis]\n    C --> F[定时任务]\n```\n\n#### 数据流转\n1.。写入流程：API → MySQL → ES 同步\n2.。搜索流程：API → ES 查询 → 结果处理\n3.。"," In modern content platforms, the search function is the core entrance for users to obtain information. While traditional database LIKE queries degrade dramatically when faced with massive amounts of data, Elasticsearch, a full-text search engine, provides millisecond search responses. This article will detail how to use Go + Elasticsearch to build a fully functional intelligent search system.","🎯 项目背景\n\n> 在现代内容平台中，搜索功能是用户获取信息的核心入口。传统的数据库 LIKE 查询在面对海量数据时性能急剧下降，而全文搜索引擎 Elasticsearch 能够提供毫秒级的搜索响应。本文将详细介绍如何使用 Go + Elasticsearch 构建一个功能完整的智能搜索系统。\n\n## ✨ 系统特性\n#### 🚀 高性能搜索\n- 全文检索：支持标题、内容、摘要的多字段搜索\n- 权重排序：标题权重 3x，内容权重 2x，摘要权重 1x\n- 高亮显示：搜索关键词自动高亮标记\n- 毫秒响应：平均响应时间 \u003C 50ms\n#### 🎯 智能推荐\n- 标签相似度：基于 Jaccard 系数计算文章相似性\n- 用户行为：点赞、收藏行为影响推荐权重\n- 时间衰减：新文章获得更高推荐权重\n- 缓存优化：Redis 缓存推荐结果，提升性能\n#### 🔄 数据同步\n- 实时同步：文章 CRUD 操作自动同步到 ES\n- 批量操作：支持批量删除和更新\n- 错误重试：网络异常自动重试机制\n- 定时全量：定时任务保证数据一致性\n\n## 🏗️ 系统架构\n#### 核心组件\n\n\n```mermaid\ngraph TD\n    A[Web API] --> B[Service]\n    B --> C[Elasticsearch]\n    A --> D[MySQL]\n    B --> E[Redis]\n    C --> F[定时任务]\n```\n\n#### 数据流转\n1. 写入流程：API → MySQL → ES 同步\n2. 搜索流程：API → ES 查询 → 结果处理\n3. 推荐流程：API → 相似度计算 → Redis 缓存\n\n#### 💡 核心实现\n###### 1. 智能搜索查询构建\n\n\n```Go\nfunc BuildSearchQuery(keyword, sortField, sortOrder, from, size string, tags []string, category string) *bytes.Buffer {\n    var queryBody map[string]interface{}\n    \n    if keyword == \"\" {\n        \u002F\u002F 全量查询\n        queryBody = map[string]interface{}{\n            \"query\": map[string]interface{}{\n                \"match_all\": map[string]interface{}{},\n            },\n        }\n    } else {\n        \u002F\u002F 多字段权重搜索\n        queryBody = map[string]interface{}{\n            \"query\": map[string]interface{}{\n                \"multi_match\": map[string]interface{}{\n                    \"query\":  keyword,\n                    \"fields\": []string{\"title^3\", \"content^2\", \"abstract\"},\n                    \"type\":   \"best_fields\",\n                },\n            },\n        }\n    }\n\n    \u002F\u002F 构建完整查询\n    query := map[string]interface{}{\n        \"query\": queryBody[\"query\"],\n        \"highlight\": map[string]interface{}{\n            \"pre_tags\":  []string{\"\u003Cem class='highlight'>\"},\n            \"post_tags\": []string{\"\u003C\u002Fem>\"},\n            \"fields\": map[string]interface{}{\n                \"title\":   map[string]interface{}{},\n                \"content\": map[string]interface{}{},\n            },\n        },\n        \"from\": from,\n        \"size\": size,\n    }\n\n    \u002F\u002F 添加过滤条件\n    if category != \"\" || len(tags) > 0 {\n        filters := []map[string]interface{}{}\n        \n        if category != \"\" {\n            filters = append(filters, map[string]interface{}{\n                \"term\": map[string]interface{}{\"category\": category},\n            })\n        }\n        \n        if len(tags) > 0 {\n            filters = append(filters, map[string]interface{}{\n                \"terms\": map[string]interface{}{\"tags\": tags},\n            })\n        }\n\n        query[\"query\"] = map[string]interface{}{\n            \"bool\": map[string]interface{}{\n                \"must\":   queryBody[\"query\"],\n                \"filter\": filters,\n            },\n        }\n    }\n\n    var buf bytes.Buffer\n    json.NewEncoder(&buf).Encode(query)\n    return &buf\n}\n```\n\n##### 2. 数据同步\n\n```Go\nfunc SyncToES(article models.ArticleModel) error {\n    if !global.Config.Elasticsearch.Enable {\n        return nil\n    }\n\n    \u002F\u002F 构造文档结构\n    doc := map[string]any{\n        \"title\":          article.Title,\n        \"content\":        article.Content,\n        \"abstract\":       article.Abstract,\n        \"tags\":           article.Tags,\n        \"category\":       article.Category,\n        \"created_at\":     article.CreatedAt.Format(\"2006-01-02 15:04:05\"),\n        \"digg_count\":     article.DiggCount,\n        \"look_count\":     article.LookCount,\n        \"collects_count\": article.CollectsCount,\n        \"comment_count\":  article.CommentCount,\n    }\n\n    docData, err := json.Marshal(doc)\n    if err != nil {\n        return err\n    }\n\n    req := esapi.IndexRequest{\n        Index:      \"articles\",\n        DocumentID: fmt.Sprintf(\"%d\", article.ID),\n        Body:       strings.NewReader(string(docData)),\n        Refresh:    \"wait_for\", \u002F\u002F 立即可搜索\n    }\n\n    \u002F\u002F 带重试的执行\n    \u002F\u002F 这里最好补充熔断机制，如果服务器宕机和超载，重试对服务器是雪上加霜\n    return retry.DoWithRetry(3, 1*time.Second, func() error {\n        res, err := req.Do(context.Background(), global.Elasticsearch)\n        if err != nil {\n            return err\n        }\n        defer res.Body.Close()\n\n        if res.IsError() {\n            body, _ := io.ReadAll(res.Body)\n            return fmt.Errorf(\"ES操作失败: %s | %s\", res.Status(), string(body))\n        }\n        return nil\n    })\n}\n```\n\n##### 3. 智能推荐算法\n\n```Go\nfunc GetRecommendations(articleID uint, userID uint, limit int) ([]ArticleSimilarity, error) {\n    \u002F\u002F 缓存检查\n    cacheKey := fmt.Sprintf(\"article_recommend:%d:%d:%d\", articleID, userID, limit)\n    if val, err := global.Redis.Get(context.Background(), cacheKey).Result(); err == nil {\n        var cachedData []ArticleSimilarity\n        if err := json.Unmarshal([]byte(val), &cachedData); err == nil {\n            return cachedData, nil\n        }\n    }\n\n    var currentArticle models.ArticleModel\n    if err := global.DB.First(&currentArticle, articleID).Error; err != nil {\n        return nil, err\n    }\n\n    var allArticles []models.ArticleModel\n    global.DB.Where(\"id != ?\", articleID).Find(&allArticles)\n\n    recommendations := make([]ArticleSimilarity, 0, len(allArticles))\n\n    for _, article := range allArticles {\n        \u002F\u002F 基础相似度（Jaccard系数）\n        score := calculateTagSimilarity(currentArticle.Tags, article.Tags)\n\n        \u002F\u002F 用户行为加权\n        if userID > 0 {\n            \u002F\u002F 点赞行为加权\n            if global.Redis.SIsMember(context.Background(), \n                fmt.Sprintf(\"article_digg_users:%d\", article.ID), userID).Val() {\n                score *= 1.3\n            }\n\n            \u002F\u002F 收藏行为加权\n            var collectExists int64\n            global.DB.Model(&models.UserCollectModel{}).\n                Where(\"user_id = ? AND article_id = ?\", userID, article.ID).\n                Count(&collectExists)\n            if collectExists > 0 {\n                score *= 1.5\n            }\n        }\n\n        \u002F\u002F 时间衰减因子\n        daysOld := time.Since(article.CreatedAt).Hours() \u002F 24\n        timeFactor := math.Exp(-0.1 * daysOld)\n        score *= 1 + 0.5*timeFactor\n\n        recommendations = append(recommendations, ArticleSimilarity{\n            ArticleID: article.ID,\n            Score:     score,\n        })\n    }\n\n    \u002F\u002F 按分数排序\n    sort.Slice(recommendations, func(i, j int) bool {\n        return recommendations[i].Score > recommendations[j].Score\n    })\n\n    if limit > len(recommendations) {\n        limit = len(recommendations)\n    }\n\n    result := recommendations[:limit]\n\n    \u002F\u002F 缓存结果\n    if data, err := json.Marshal(result); err == nil {\n        global.Redis.Set(context.Background(), cacheKey, data, 30*time.Minute)\n    }\n\n    return result, nil\n}\n\n\u002F\u002F Jaccard 相似度计算\nfunc calculateTagSimilarity(currentTags, targetTags []string) float64 {\n    tagSet := make(map[string]bool)\n    for _, tag := range currentTags {\n        tagSet[tag] = true\n    }\n\n    commons := 0\n    for _, tag := range targetTags {\n        if tagSet[tag] {\n            commons++\n        }\n    }\n\n    \u002F\u002F Jaccard 系数 = 交集 \u002F 并集\n    return float64(commons) \u002F float64(len(currentTags)+len(targetTags)-commons)\n}\n```\n##### 4. 搜索结果解析\n\n```Go\ntype SearchResult struct {\n    Total int\n    Hits  []SearchHit\n}\n\ntype SearchHit struct {\n    ID        string                 `json:\"id\"`\n    Source    map[string]interface{} `json:\"_source\"`\n    Highlight map[string][]string    `json:\"highlight\"`\n}\n\nfunc ParseSearchResponse(body io.Reader) (*SearchResult, error) {\n    var response struct {\n        Hits struct {\n            Total struct {\n                Value int `json:\"value\"`\n            } `json:\"total\"`\n            Hits []struct {\n                ID        string                 `json:\"_id\"`\n                Source    map[string]interface{} `json:\"_source\"`\n                Highlight map[string][]string    `json:\"highlight\"`\n            } `json:\"hits\"`\n        } `json:\"hits\"`\n    }\n\n    if err := json.NewDecoder(body).Decode(&response); err != nil {\n        return nil, err\n    }\n\n    result := &SearchResult{\n        Total: response.Hits.Total.Value,\n        Hits:  make([]SearchHit, len(response.Hits.Hits)),\n    }\n\n    for i, hit := range response.Hits.Hits {\n        result.Hits[i] = SearchHit{\n            ID:        hit.ID,\n            Source:    hit.Source,\n            Highlight: hit.Highlight,\n        }\n    }\n\n    return result, nil\n}\n```\n## 📊 性能优化\n\n#### 1. 搜索性能\n- 索引优化：合理设置分片和副本数量\n- 查询缓存：ES 内置查询结果缓存\n- 分页优化：使用 from\u002Fsize 进行高效分页\n- \n#### 2. 推荐性能\n- Redis 缓存：推荐结果缓存 30 分钟\n- 异步计算：后台定时更新推荐数据\n- 批量处理：批量计算相似度减少数据库查询\n- \n#### 3. 同步性能\n- 批量操作：支持批量索引和删除\n- 异步同步：写入 MySQL 后异步同步 ES\n- 错误重试：网络异常自动重试机制\n\n## 🛡️ 可靠性保障\n\n#### 1. 数据一致性\n\n```Go\n\u002F\u002F 定时全量同步任务\nfunc FullSyncToES() {\n    var articles []models.ArticleModel\n    global.DB.Find(&articles)\n\n    for _, article := range articles {\n        if err := SyncToES(article); err != nil {\n            global.Log.Error(\"全量同步失败\", \n                zap.Uint(\"id\", article.ID), zap.Error(err))\n        }\n    }\n}\n\n```\n#### 2. 错误处理\n\n\n```Go\n\u002F\u002F 重试机制\nfunc retry.DoWithRetry(maxRetries int, delay time.Duration, fn func() error) error {\n    for i := 0; i \u003C maxRetries; i++ {\n        if err := fn(); err == nil {\n            return nil\n        }\n        if i \u003C maxRetries-1 {\n            time.Sleep(delay)\n        }\n    }\n    return fmt.Errorf(\"重试 %d 次后仍然失败\", maxRetries)\n}\n```\n\n#### 3. 监控告警\n- 搜索延迟监控：记录搜索响应时间\n- 同步失败告警：ES 同步失败自动告警\n- 索引健康检查：定期检查 ES 集群状态\n  \n## 🚀 使用示例\n#### 基础搜索\n\n```Go\n\u002F\u002F 关键词搜索\nquery := BuildSearchQuery(\"Go语言\", \"created_at\", \"desc\", \"0\", \"10\", nil, \"\")\n\u002F\u002F 执行搜索...\n```\n\n#### 高级搜索\n\n```Go\n\u002F\u002F 带标签和分类的搜索\ntags := []string{\"后端\", \"微服务\"}\nquery := BuildSearchQuery(\"分布式\", \"digg_count\", \"desc\", \"0\", \"20\", tags, \"技术\")\n```\n\n#### 智能推荐\n\n```Go\n\u002F\u002F 获取相关文章推荐\nrecommendations, err := GetRecommendations(articleID, userID, 5)\n```\n\n> 技术栈：Go + Elasticsearch + Redis + MySQL\n> 适用场景：内容平台、电商搜索、知识库\n> 核心算法：TF-IDF、Jaccard 相似度、时间衰减","🎯 Project background\n\n> In modern content platforms, the search function is the core entrance for users to obtain information. While traditional database LIKE queries degrade dramatically when faced with massive amounts of data, Elasticsearch, a full-text search engine, provides millisecond search responses. This article will detail how to use Go + Elasticsearch to build a fully functional intelligent search system.\n\n## ✨ System Characteristics\n#### 🚀 High-performance search\n- Full-text search: Supports multi-field search for title, content, and abstract\n- Weight Sorting: Title weight 3x, Content weight 2x, Summary weight 1x\n- Highlighting: Automatically highlight keywords for search keywords\n- Millisecond Response: Average response time \u003C 50ms\n#### 🎯 Smart Recommendation\n- Tag Similarity: Calculates article similarity based on the Jaccard coefficient\n- User behavior: Likes and favorites affect the weight of recommendations\n- Time Decay: New articles receive higher recommendation weight\n- Cache Optimization: Redis caches recommended results for improved performance\n#### 🔄 Data synchronization\n- Real-time synchronization: Article CRUD operations are automatically synced to ES\n- Batch Operations: Supports batch deletion and updates\n- Error Retry: Automatic retry mechanism for network exceptions\n- Scheduled Full Volume: Scheduled tasks ensure data consistency\n\n## 🏗️ System Architecture\n#### Core Components\n\n\n```mermaid\ngraph TD\n    A[Web API] --> B[Service]\n    B --> C[Elasticsearch]\n    A --> D[MySQL]\n    B --> E[Redis]\n    C --> F [Timed Mission]\n```\n\n#### Data Flow\n1. Write Flow: API → MySQL → ES synchronization\n2. Search Flow: API → ES query → result processing\n3. Recommendation Process: API → Similarity Calculation → Redis Cache\n\n#### 💡 Core implementation\n###### 1. Intelligent search query building\n\n\n```Go\nfunc BuildSearchQuery(keyword, sortField, sortOrder, from, size string, tags []string, category string) *bytes. Buffer {\n    var queryBody map[string]interface{}\n    \n    if keyword == \"\" {\n        Full query\n        queryBody = map[string]interface{}{\n            \"query\": map[string]interface{}{\n                \"match_all\": map[string]interface{}{},\n            },\n        }\n    } else {\n        Multi-field weight search\n        queryBody = map[string]interface{}{\n            \"query\": map[string]interface{}{\n                \"multi_match\": map[string]interface{}{\n                    \"query\":  keyword,\n                    \"fields\": []string{\"title^3\", \"content^2\", \"abstract\"},\n                    \"type\":   \"best_fields\",\n                },\n            },\n        }\n    }\n\n    Build a full query\n    query := map[string]interface{}{\n        \"query\": queryBody[\"query\"],\n        \"highlight\": map[string]interface{}{\n            \"pre_tags\":  []string{\"\u003Cem class='highlight'>\"},\n            \"post_tags\": []string{\"\u003C\u002Fem>\"},\n            \"fields\": map[string]interface{}{\n                \"title\":   map[string]interface{}{},\n                \"content\": map[string]interface{}{},\n            },\n        },\n        \"from\": from,\n        \"size\": size,\n    }\n\n    Add filters\n    if category != \"\" || len(tags) > 0 {\n        filters := []map[string]interface{}{}\n        \n        if category != \"\" {\n            filters = append(filters, map[string]interface{}{\n                \"term\": map[string]interface{}{\"category\": category},\n            })\n        }\n        \n        if len(tags) > 0 {\n            filters = append(filters, map[string]interface{}{\n                \"terms\": map[string]interface{}{\"tags\": tags},\n            })\n        }\n\n        query[\"query\"] = map[string]interface{}{\n            \"bool\": map[string]interface{}{\n                \"must\":   queryBody[\"query\"],\n                \"filter\": filters,\n            },\n        }\n    }\n\n    var buf bytes. Buffer\n    json. NewEncoder(&buf). Encode(query)\n    return &buf\n}\n```\n\n##### 2. Data synchronization\n\n```Go\nfunc SyncToES(article models. ArticleModel) error {\n    if !global. Config.Elasticsearch.Enable {\n        return nil\n    }\n\n    Structure the document\n    doc := map[string]any{\n        \"title\":          article. Title,\n        \"content\":        article. Content,\n        \"abstract\":       article. Abstract,\n        \"tags\":           article. Tags,\n        \"category\":       article. Category,\n        \"created_at\":     article. CreatedAt.Format(\"2006-01-02 15:04:05\"),\n        \"digg_count\":     article. DiggCount,\n        \"look_count\":     article. LookCount,\n        \"collects_count\": article. CollectsCount,\n        \"comment_count\":  article. CommentCount,\n    }\n\n    docData, err := json. Marshal(doc)\n    if err != nil {\n        return err\n    }\n\n    req := esapi. IndexRequest{\n        Index:      \"articles\",\n        DocumentID: fmt. Sprintf(\"%d\", article.ID),\n        Body:       strings. NewReader(string(docData)),\n        Refresh: \"wait_for\", \u002F\u002F Immediately searchable\n    }\n\n    Execution with retries\n    It is better to add a circuit breaker mechanism here, if the server is down and overloaded, retrying will make the server worse\n    return retry. DoWithRetry(3, 1*time. Second, func() error {\n        res, err := req. Do(context. Background(), global. Elasticsearch)\n        if err != nil {\n            return err\n        }\n        defer res. Body.Close()\n\n        if res. IsError() {\n            body, _ := io. ReadAll(res. Body)\n            return fmt. Errorf(\"ES operation failed: %s | %s\", res. Status(), string(body))\n        }\n        return nil\n    })\n}\n```\n\n##### 3. Intelligent recommendation algorithm\n\n```Go\nfunc GetRecommendations(articleID uint, userID uint, limit int) ([]ArticleSimilarity, error) {\n    Cache check\n    cacheKey := fmt. Sprintf(\"article_recommend:%d:%d:%d\", articleID, userID, limit)\n    if val, err := global. Redis.Get(context. Background(), cacheKey). Result(); err == nil {\n        var cachedData []ArticleSimilarity\n        if err := json. Unmarshal([]byte(val), &cachedData); err == nil {\n            return cachedData, nil\n        }\n    }\n\n    var currentArticle models. ArticleModel\n    if err := global. DB. First(&currentArticle, articleID). Error; err != nil {\n        return nil, err\n    }\n\n    var allArticles []models. ArticleModel\n    global. DB. Where(\"id != ?\", articleID). Find(&allArticles)\n\n    recommendations := make([]ArticleSimilarity, 0, len(allArticles))\n\n    for _, article := range allArticles {\n        Base similarity (Jaccard coefficient)\n        score := calculateTagSimilarity(currentArticle.Tags, article. Tags)\n\n        User behavior weighting\n        if userID > 0 {\n            The act of likes is weighted\n            if global. Redis.SIsMember(context. Background(), \n                fmt. Sprintf(\"article_digg_users:%d\", article.ID), userID). Val() {\n                score *= 1.3\n            }\n\n            Collection behavior is weighted\n            var collectExists int64\n            global. DB. Model(&models. UserCollectModel{}).\n                Where(\"user_id = ? AND article_id = ?\", userID, article.ID).\n                Count(&collectExists)\n            if collectExists > 0 {\n                score *= 1.5\n            }\n        }\n\n        Time decay factor\n        daysOld := time. Since(article. CreatedAt). Hours() \u002F 24\n        timeFactor := math. Exp(-0.1 * daysOld)\n        score *= 1 + 0.5*timeFactor\n\n        recommendations = append(recommendations, ArticleSimilarity{\n            ArticleID: article.ID,\n            Score:     score,\n        })\n    }\n\n    Sort by score\n    sort. Slice(recommendations, func(i, j int) bool {\n        return recommendations[i]. Score > recommendations[j]. Score\n    })\n\n    if limit > len(recommendations) {\n        limit = len(recommendations)\n    }\n\n    result := recommendations[:limit]\n\n    Cache results\n    if data, err := json. Marshal(result); err == nil {\n        global. Redis.Set(context. Background(), cacheKey, data, 30*time. Minute)\n    }\n\n    return result, nil\n}\n\nJaccard similarity calculation\nfunc calculateTagSimilarity(currentTags, targetTags []string) float64 {\n    tagSet := make(map[string]bool)\n    for _, tag := range currentTags {\n        tagSet[tag] = true\n    }\n\n    commons := 0\n    for _, tag := range targetTags {\n        if tagSet[tag] {\n            commons++\n        }\n    }\n\n    Jaccard coefficient = intersection \u002F union\n    return float64(commons) \u002F float64(len(currentTags)+len(targetTags)-commons)\n}\n```\n##### 4. Analysis of search results\n\n```Go\ntype SearchResult struct {\n    Total int\n    Hits  []SearchHit\n}\n\ntype SearchHit struct {\n    ID        string                 `json:\"id\"`\n    Source    map[string]interface{} `json:\"_source\"`\n    Highlight map[string][]string    `json:\"highlight\"`\n}\n\nfunc ParseSearchResponse(body io. Reader) (*SearchResult, error) {\n    var response struct {\n        Hits struct {\n            Total struct {\n                Value int `json:\"value\"`\n            } `json:\"total\"`\n            Hits []struct {\n                ID        string                 `json:\"_id\"`\n                Source    map[string]interface{} `json:\"_source\"`\n                Highlight map[string][]string    `json:\"highlight\"`\n            } `json:\"hits\"`\n        } `json:\"hits\"`\n    }\n\n    if err := json. NewDecoder(body). Decode(&response); err != nil {\n        return nil, err\n    }\n\n    result := &SearchResult{\n        Total: response. Hits.Total.Value,\n        Hits:  make([]SearchHit, len(response. Hits.Hits)),\n    }\n\n    for i, hit := range response. Hits.Hits {\n        result. Hits[i] = SearchHit{\n            ID:        hit.ID,\n            Source:    hit. Source,\n            Highlight: hit. Highlight,\n        }\n    }\n\n    return result, nil\n}\n```\n## 📊 Performance Optimization\n\n#### 1. Search performance\n- Index optimization: Set the number of shards and replicas reasonably\n- Query caching: ES has built-in query result caching\n- Pagination Optimization: Use from\u002Fsize for efficient pagination\n- \n#### 2. Recommended performance\n- Redis Cache: Recommended results cache for 30 minutes\n- Asynchronous Calculation: The background updates the recommendation data regularly\n- Batch Processing: Batch calculates similarity to reduce database queries\n- \n#### 3. Synchronized performance\n- Batch Operations: Supports batch indexing and deletion\n- Asynchronous Synchronization: Asynchronously synchronizes ES after writing to MySQL\n- Error Retry: Automatic retry mechanism for network exceptions\n\n## 🛡️ Reliability guarantee\n\n#### 1. Data consistency\n\n```Go\nSynchronize tasks in full at regular internship\nfunc FullSyncToES() {\n    var articles []models. ArticleModel\n    global. DB. Find(&articles)\n\n    for _, article := range articles {\n        if err := SyncToES(article); err != nil {\n            global. Log.Error(\"Full sync failed\", \n                zap. Uint(\"id\", article.ID), zap. Error(err))\n        }\n    }\n}\n\n```\n#### 2. Error handling\n\n\n```Go\nRetry mechanism\nfunc retry. DoWithRetry(maxRetries int, delay time. Duration, fn func() error) error {\n    for i := 0; i \u003C maxRetries; i++ {\n        if err := fn(); err == nil {\n            return nil\n        }\n        if i \u003C maxRetries-1 {\n            time. Sleep(delay)\n        }\n    }\n    return fmt. Errorf(\"Still failing after %d retry\", maxRetries)\n}\n```\n\n#### 3. Monitoring alarms\n- Search Latency Monitoring: Record search response times\n- Synchronization failure alarm: An automatic ES synchronization failure alarm\n- Index Health Checks: Regularly check the status of your ES cluster\n  \n## 🚀 Usage Examples\n#### Basic search\n\n```Go\nKeyword search\nquery := BuildSearchQuery(\"Go\", \"created_at\", \"desc\", \"0\", \"10\", nil, \"\")\nPerform a search...\n```\n\n#### Advanced search\n\n```Go\nSearch with tags and categories\ntags := []string{\"backend\", \"microservices\"}\nquery := BuildSearchQuery(\"distributed\", \"digg_count\", \"desc\", \"0\", \"20\", tags, \"technical\")\n```\n\n#### Smart Recommendation\n\n```Go\nGet related article recommendations\nrecommendations, err := GetRecommendations(articleID, userID, 5)\n```\n\n> Tech stack: Go + Elasticsearch + Redis + MySQL\n> Applicable scenarios: content platform, e-commerce search, knowledge base\n> Core algorithms: TF-IDF, Jaccard similarity, time decay","Go",0,"https:\u002F\u002Fblog4-1316398321.cos.ap-nanjing.myqcloud.com\u002Fblog5\u002F20250707081116__freecompress-【哲风壁纸】暗黑御姐风-酷酷的少女.png",[15,16],"GO","ES",false,{"id":19,"title":20,"title_en":21},16,"Go 实现高性能敏感词过滤系统","Go implements high-performance sensitive word filtering system",{"id":23,"title":24,"title_en":25},18,"Vue3项目中的Vite构建优化实践","Vite build optimization practices in Vue3 projects","2025-07-29T18:30:09+08:00"]