Go操作Elasticsearch是否有类似SQL的Scan()方法,如何解析结果到结构体
问题原因&修复方案
1. EOF错误根因
- 你先调用了
ioutil.ReadAll(response.Body)把HTTP响应流完全读取耗尽,后续再调用json.NewDecoder(response.Body).Decode时,响应流已经是空的,直接返回EOF错误 - 部分Elasticsearch集群默认不支持GET请求携带请求体,会直接截断请求返回空响应,也会触发EOF
2. 解析ES结果到结构体的实现
ES的查询返回结果不是直接返回文档内容,外层有固定的封装结构,你需要先定义匹配ES返回格式的嵌套结构体,再提取_source字段对应的值到你的Student结构体。
3. 修正后的完整代码
首先定义结构体:
// 你原有的Student结构体,字段json标签要和ES文档字段对应 type Student struct { ID int `json:"roll_no"` Name string `json:"name"` School string `json:"school"` } // 匹配ES返回结构的嵌套结构体 type ESQueryResponse struct { Hits struct { Hits []struct { Source Student `json:"_source"` } `json:"hits"` } `json:"hits"` }
然后修正retrieve方法:
func retrieve(url string, b []byte) (Student, error) { // 改GET为POST,兼容所有ES版本的请求体查询 request, err := http.NewRequest("POST", url, bytes.NewBuffer(b)) if err != nil { return Student{}, err } request.Header.Set("Content-Type", "application/json; charset=UTF-8") client := &http.Client{} response, err := client.Do(request) if err != nil { return Student{}, err } defer response.Body.Close() // 直接用响应流反序列化,不要提前读空body var esResp ESQueryResponse err = json.NewDecoder(response.Body).Decode(&esResp) if err != nil { return Student{}, err } // 匹配到数据则返回第一个结果 if len(esResp.Hits.Hits) > 0 { s := esResp.Hits.Hits[0].Source fmt.Printf("Student: %v", s) return s, nil } return Student{}, fmt.Errorf("no matched student found") }
额外优化建议
- 如果你是精确匹配
roll_no字段,建议把match查询改为term查询,避免分词导致的匹配误差,查询语句改为:str = fmt.Sprintf(`{"query": { "term": { "roll_no": %d } } }`, roll_no) - 业务逻辑中不要直接
panic,尽量把错误返回给上层调用方处理,避免服务直接崩溃
内容的提问来源于stack exchange,提问作者ord_bear
相关产品推荐
相关产品推荐

