当前位置: 首页 > news >正文

快速了解GO+ElasticSearch

更多个人笔记见:
注意点击“继续”,而不是“发现新项目”
github个人笔记仓库 https://github.com/ZHLOVEYY/IT_note
gitee 个人笔记仓库 https://gitee.com/harryhack/it_note
个人学习,学习过程中还会不断补充~ (后续会更新在github上)

文章目录

    • 简单介绍
    • 经典例子
        • 示范 demo 代码
        • 优化后的代码
        • 参考:es 返回格式示例:
        • 空指针问题

简单介绍

ES 是一个分布式搜索和分析引擎,用于高效全文搜索。
与 Mysql 存储后查询相比,ES支持用户快速搜索“包含某关键词的文章,以及实现“附近动态”或“热门话题”等复杂排序和过滤

经典例子

GO 相关包:go get -u github.com/elastic/go-elasticsearch/v8
docker 快速部署:docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.14.0

# 启用现有容器
docker start elasticsearch#如果希望重新部署:
# 首先停止容器(如果它在运行)
docker stop elasticsearch# 然后移除容器
docker rm elasticsearch# 查看容器
docker ps -a | grep elasticsearch

启动后你会发现,访问不行。这是因为 es 设置了密码和安全验证,那么我们在开发环境下可以这么启动:

docker run -d --name elasticsearch \-p 9200:9200 \-e "discovery.type=single-node" \-e "xpack.security.enabled=false" \elasticsearch:8.14.0

记得先用上面的指令暂停之前的容器并移除,重新 docker 启动

示范 demo 代码
package mainimport ("log""strings""github.com/elastic/go-elasticsearch/v8"
)func main() {cfg := elasticsearch.Config{Addresses: []string{"http://localhost:9200"},}es, err := elasticsearch.NewClient(cfg)if err != nil {log.Fatalf("Error creating Elasticsearch client: %v", err)}// 索引一个文档_, err = es.Index("posts", strings.NewReader(`{"title":"Test Post","content":"Hello world"}`))if err != nil {log.Fatalf("Error indexing document: %v", err)}// 搜索res, err := es.Search(es.Search.WithIndex("posts"),es.Search.WithQuery("hello"),)if err != nil {log.Fatalf("Error searching: %v", err)}defer res.Body.Close()log.Println(res.String())
}

发现看到的结果不太能看懂,进行进一步解析:

优化后的代码
package mainimport ("encoding/json""log""strings""github.com/elastic/go-elasticsearch/v8"
)func main() {cfg := elasticsearch.Config{Addresses: []string{"http://localhost:9200"},}es, err := elasticsearch.NewClient(cfg)if err != nil {log.Fatalf("Error creating Elasticsearch client: %v", err)}// 在搜索前刷新索引_, err = es.Indices.Refresh(es.Indices.Refresh.WithIndex("posts"))if err != nil {log.Fatalf("Error refreshing index: %v", err)}// 索引一个文档_, err = es.Index("posts", strings.NewReader(`{"title":"Test Post","content":"Hello world"}`))if err != nil {log.Fatalf("Error indexing document: %v", err)}// 搜索res, err := es.Search(es.Search.WithIndex("posts"),es.Search.WithBody(strings.NewReader(`{"query": {"match": {"content": "hello"}}}`)),)if err != nil {log.Fatalf("Error searching: %v", err)}defer res.Body.Close()// 解析搜索结果 (这个算是一个通用的模板)var r map[string]interface{}if err := json.NewDecoder(res.Body).Decode(&r); err != nil {log.Fatalf("Error parsing the response body: %s", err)}// 现在可以访问解析后的结果hits := r["hits"].(map[string]interface{})["hits"].([]interface{})for _, hit := range hits {source := hit.(map[string]interface{})["_source"]log.Printf("Found document: %v", source)}
}

这样就可以看到很好的输出结果。
不过记得如果不注释,每次执行程序都会新建一个索引的

参考:es 返回格式示例:
{"took": 10,                  // 查询耗时(毫秒)"timed_out": false,          // 是否超时"hits": {                    // 命中结果"total": {                 // 总匹配数"value": 2,              // 具体数量"relation": "eq"         // 计数关系(eq 表示精确值)},"max_score": 1.0,          // 最高相关性得分"hits": [                  // 文档数组{"_index": "my_index",  // 索引名"_id": "1",            // 文档ID"_score": 1.0,         // 当前文档得分"_source": {           // 原始文档数据   这是我们需要的!!"title": "Elasticsearch入门","content": "学习ES基础用法"}}]}
}
空指针问题

下面这个函数在解析 es 结果的时候会报空指针的错误,分析下原因

func SearchPosts(query string) ([]models.Post, error) {var posts []models.Postres, err := esClient.Search(esClient.Search.WithIndex("posts"),esClient.Search.WithQuery(`{"match": {"title": {"query": "`+query+`"}}}`), //查询针对的是文档的 title 字段,使用的是 match 查询,这是一种全文检索查询,用变量 query 的值作为搜索词)if err != nil {return nil, err}defer res.Body.Close()// 解析结果(简化处理,仅提取 hits)var result map[string]interface{}if err := json.NewDecoder(res.Body).Decode(&result); err != nil { //将结果放入 result 中return nil, err}hits := result["hits"].(map[string]interface{})["hits"].([]interface{})for _, hit := range hits {source := hit.(map[string]interface{})["_source"].(map[string]interface{})posts = append(posts, models.Post{Title:   source["title"].(string), //结构化输出,放入结构体,然后放入列表中Content: source["content"].(string),})}return posts, nil
}

这个函数存在空指针错误,原因如下:

  • 如果 ES 返回的响应中缺少 hits 字段(如查询语法错误或索引不存在),result["hits"].(map[string]interface{}) 会触发 panic
  • 即使 hits 存在,若搜索结果为空(hits.hits 为空数组),循环内的 hit(map[string]interface{}) 虽不会报错,但后续对 _source 的访问仍需校验
  • 进一步的,如果某文档无 titlecontent 字段,source["title"].(string) 会因类型断言失败或字段不存在而崩溃

结合前面的参照 es 的返回格式更好理解

所以可以采用逐层校验的方式:

hits, ok := result["hits"].(map[string]interface{})
if !ok {return nil, fmt.Errorf("invalid hits format in ES response")
}hitList, ok := hits["hits"].([]interface{})
if !ok {return nil, fmt.Errorf("invalid hits.hits format")
}for _, hit := range hitList {hitMap, ok := hit.(map[string]interface{})if !ok {continue // 跳过无效条目}source, ok := hitMap["_source"].(map[string]interface{})if !ok {continue}// 安全获取字段(支持缺省值)title, _ := source["title"].(string)    // 若字段不存在,title=""content, _ := source["content"].(string)posts = append(posts, models.Post{Title:   title,Content: content,})
}

这就是优化后对于数据的解析

我的博客中还有后续进阶的例子可以查看~

http://www.lqws.cn/news/91063.html

相关文章:

  • [Linux] MySQL源码编译安装
  • 工作自动化——工作自动提炼--智能编程——仙盟创梦IDE
  • 系统设计面试利器:The System Design Primer开源项目介绍
  • vue+cesium示例:地形开挖(附源码下载)
  • AI+3D 视觉重塑塑料袋拆垛新范式:迁移科技解锁工业自动化新高度
  • 【亲测有效】Mybatis-Plus中更新字段为null
  • PostgreSQL数据库备份
  • KEYSIGHT是德科技 E5063A 18G ENA系列网络分析仪
  • 数据库的操作
  • Oracle中的循环——FOR循环、WHILE循环和LOOP循环
  • 鸿蒙版Taro 搭建开发环境
  • 腾讯 ovCompose 开源,Kuikly 鸿蒙和 Compose DSL 开源,腾讯的“双”鸿蒙方案发布
  • Oracle 用户/权限/角色管理
  • Go基础|map入门
  • 【灵动Mini-F5265-OB】vscode+gcc工程创建、下载、调试
  • React从基础入门到高级实战:React 高级主题 - React 微前端实践:构建可扩展的大型应用
  • 如何监测光伏系统中的电能质量问题?分布式光伏电能质量解决方案
  • 【论文解读】ReAct:从思考脱离行动, 到行动反馈思考
  • 【Doris基础】Apache Doris中的Fragment概念详解
  • Vue3中使用Echarts图表步骤-demo
  • 通信算法之281:大疆DJI无人机ID-DJI DroneID开源工程-相关问题-协议信息问题
  • 20250603在荣品的PRO-RK3566开发板的Android13下的命令行查看RK3566的温度
  • 学习路之PHP--easyswoole使用视图和模板
  • 大语言模型评测体系全解析(上篇):基础框架与综合评测平台
  • 用户管理页面(解决toggleRowSelection在dialog用不了的隐患,包含el-table的plus版本的组件)
  • 剑指offer15_数值的整数次方
  • Elasticsearch | 如何将修改已有的索引字段类型并迁移数据
  • 云原生周刊:探索 Gateway API v1.3.0
  • 点击启动「高效模式」:大腾智能 CAD 重构研发设计生产力
  • Go 为何天生适合云原生?