迅速了解GO+ElasticSearch

news/2025/10/6 18:04:19/文章来源:https://www.cnblogs.com/yxysuanfa/p/19127785

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

简单介绍

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 main
import (
"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 main
import ("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.Post
res, 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.mzph.cn/news/929576.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学生管理系统面向对象分析报告

学生管理系统面向对象分析报告 目录1. 案例中哪里体现出了封装性及其好处? 2. 案例中的setter/getter模式与封装性? 3. 案例中某些类的toString()方法? 4. 案例中几个常用方法解析。 5. 案例中的面向对象设计 5.1 尝…

荷兰青少年通过Telegram被招募,涉嫌参与俄罗斯支持的黑客活动

两名17岁荷兰青少年通过Telegram被招募,涉嫌为亲俄黑客从事间谍活动。他们使用Wi-Fi嗅探器在欧盟机构总部和使馆周边进行网络测绘,目前一人被拘留,一人被软禁。案件凸显国家支持黑客利用未成年人作为"可抛弃代…

网站推广策划方案毕业设计免费建立网站有必要吗

一个master可以拥有多个slave,一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构 比如,将ip为192.168.1.10的机器作为主服务器,将ip为192.168.1.11的机器作为从服务器 说明:ip可以换为…

网站开发部门工资入什么科目营销一体化营销平台

org.springframework.util.StringUtils 1、字符串判断工具 // 判断字符串是否为 null,或 ""。注意,包含空白符的字符串为非空 boolean isEmpty(Object str) // 判断字符串是否是以指定内容结束。忽略大小写 boolean endsWithIgnoreCase…

Moscow International Workshops 2017. Day 4. Lviv NU Contest, GP of Ukraine

Preface 国庆本以为空的一批结果忙的飞起,好不容易抽时间凑到三个人,结果被 Div2 小登们按在地上摩擦。B. Card Game 签到,暴力枚举约数即可 #include<cstdio> #include<iostream> #include<map>…

网站开发有哪些技术wordpress新建音乐界面

转载自 ClassLoader 详解及用途 ClassLoader主要对类的请求提供服务&#xff0c;当JVM需要某类时&#xff0c;它根据名称向ClassLoader要求这个类&#xff0c;然后由ClassLoader返回这个类的class对象。 1.1 几个相关概念ClassLoader负责载入系统的所有Resources&#xff08;…

提供手机自适应网站土木工程网官网登录

Hadoop 1、 Hadoop的介绍 Hadoop最早起源于Nutch。Nutch的设计目标是构建一个大型的全网搜索引擎&#xff0c;包括网页抓取、索引、查询等功能&#xff0c;但随着抓取网页数量的增加&#xff0c;遇到了严重的可扩展性问题——如何解决数十亿网页的存储和索引问题。2003年、20…

云原生架构的演进与落地:重塑企业 IT 的核心能力 - 实践

云原生架构的演进与落地:重塑企业 IT 的核心能力 - 实践2025-10-06 17:49 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important;…

小代码使用npm包的方法

小代码使用npm包的方法pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &quo…

用手机域名做网站有多少张家口网站建设工作室

以下是电力行业中分布式能源管理(Distributed Energy Management System, DEMS)的实现方案,涵盖系统架构、关键技术、核心功能及实施路径,结合典型场景与代码示例: 一、系统架构设计 采用云-边-端三层架构,实现分布式能源的高效协同管理: 1. 终端层(感知层) 设备组…

网站做支付宝接口网页设计基础试题

Java Learning Path&#xff08;三&#xff09;过程篇   每个人的学习方法是不同的&#xff0c;一个人的方法不见得适合另一个人&#xff0c;我只能是谈自己的学习方法。因为我学习Java是完全自学的&#xff0c;从来没有问过别人&#xff0c;所以学习的过程基本上完全是自己…

张家港做网站优化排名新乡网站设计公司

摘要&#xff1a;当前,多核技术的不断发展和日渐成熟,使得处理器的性能得到巨大提升.但是对于存储设备来说,无论是速度还是容量都无法跟上这种步伐.随着处理器和其它子系统发展差距的日益加大,超级计算机的效率问题逐渐成为人们讨论和研究的热点,大部分的实际应用在超级计算机上…

day18 课程(模块 )

day18 课程(模块 &)课程: 18.1 了解模块------------------------------------------------ 执行后18.2 导入模块之方法一------------------------------------------------ 执行后18.3 导入模块之方法二-----…

Kubernetes(K8s)核心架构解析与实用命令大全 - 教程

Kubernetes(K8s)核心架构解析与实用命令大全 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&qu…

mzoj 2025/10/6

T1 考试时写的 \(O(n^4)\) 的,差点四了( 可以直接用 Floyd 找哪些可以由其他路径拼起来,剩下的是必须的。 rep(k,1,n) rep(i,1,n) rep(j,1,n)if(mp[i][j]==mp[i][k]+mp[k][j]&&mp[i][j]&&mp[i][k]&…

在 Windows 系统下配置 VSCode + CMake + Ninja 进行 C++ 或 Qt 创建

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

全源最短路 Johnson算法

洛谷p5905 #include<bits/stdc++.h> using namespace std; #define endl \n typedef long long LL; typedef pair<int,int> PII; const int N=3e3+10,INF=1e9; vector<PII> edges[N]; int dist[N],n…

UNION 与 UNION ALL 的区别 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

大学生做爰网站弄一个关于作文的网站怎么做

每日总结 20240221 花自飘零水自流。一种相思&#xff0c;两处闲愁。 —— 李清照「一剪梅红藕香残玉簟秋」 1. stat 在Linux中&#xff0c;stat 是一个用于显示文件或文件系统状态的命令行工具。它提供了关于文件的详细信息&#xff0c;包括文件类型、权限、大小、所有者、修…