Golang解析JSON数据并实现分组统计的方法
Golang解析JSON数据并实现分组统计的方法 我有以下JSON字符串,想要统计唯一指标的数量,有没有简单的方法可以实现? 例如,从下面的字符串中,我想统计唯一的负载生成器数量,如下所示,结果是3个。
load_generator_84, load_generator_86, load_generator_89
我希望用尽可能少的代码来完成这个任务。
我可以这样获取数组: records, ok := result[“logEvents”].([]interface{})
之后,我在考虑使用一些正则表达式来获取计数?
你们觉得怎么样? 我认为对所有值使用for循环可能效率不高。 有什么建议吗?
JSON字符串 =
{
"logEvents": [{
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_84\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_2\",\"load_generator_84\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_84\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_3\",\"load_generator_84\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_86\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_4\",\"load_generator_86\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_89\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_5\",\"load_generator_89\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_89\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_6\",\"load_generator_89\":0}",
"timestamp": 1596838449873
}]
}
更多关于Golang解析JSON数据并实现分组统计的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
希望这些内容都讲清楚了!
由于 Go 语言的静态类型特性,在 Go 中解析 JSON 可能比其他语言稍微困难一些。
不过我发现,使用 JSON to Go 工具将 JSON 转换成 Go 结构体,会让事情变得容易得多!
也有一个类似的用于 XML 的工具。
更多关于Golang解析JSON数据并实现分组统计的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
{ “logEvents”: [{ “message”: “{“bufferLib”:“Undefined”,”_slack":{“lbMetrics”:[{“Namespace”:“default”,“Dimensions”:[[“item_index”,“batch_index”,“bufferLib”],[“bufferLib”],[“bufferLib”,“item_index”],[“bufferLib”,“batch_index”]],“Metrics”:[{“Name”:“load_generator_84”,“Unit”:""}]}],“Timestamp”:1596838449873},“batch_index”:“batch_14185”,“item_index”:“item_2”,“load_generator_84”:0}", “timestamp”: 1596838449873 }
非常感谢 @ncw,这个网站对我极其有用。
shreyas_darwhatkar:
我有以下JSON字符串
这看起来是JSON中嵌套了JSON!
为了使其有用,你还需要将消息也解码为JSON。
我继续将其解析为 map[string]interface{} 等,最终得到了这个(playground)
func main() {
var data map[string]interface{}
err := json.Unmarshal([]byte(in), &data)
if err != nil {
log.Fatal(err)
}
fmt.Println(data)
var foundNames = map[string]struct{}{}
events := data["logEvents"].([]interface{})
for _, event := range events {
e := event.(map[string]interface{})
message := e["message"].(string)
var m map[string]interface{}
err := json.Unmarshal([]byte(message), &m)
if err != nil {
log.Fatal(err)
}
slack := m["_slack"].(map[string]interface{})
lbMetrics := slack["lbMetrics"].([]interface{})
for _, lbMetric := range lbMetrics {
metrics := lbMetric.(map[string]interface{})["Metrics"].([]interface{})
for _, metric := range metrics {
m := metric.(map[string]interface{})
name := m["Name"].(string)
fmt.Println(name)
foundNames[name] = struct{}{}
}
}
}
fmt.Printf("found %d names", len(foundNames))
这真的很丑陋!
如果我来做这件事,我会像这样正确地解析JSON
type Message struct {
BufferLib string `json:"bufferLib"`
Slack struct {
LbMetrics []struct {
Namespace string `json:"Namespace"`
Dimensions [][]string `json:"Dimensions"`
Metrics []struct {
Name string `json:"Name"`
Unit string `json:"Unit"`
} `json:"Metrics"`
} `json:"lbMetrics"`
Timestamp int64 `json:"Timestamp"`
} `json:"_slack"`
BatchIndex string `json:"batch_index"`
ItemIndex string `json:"item_index"`
LoadGenerator84 int `json:"load_generator_84"`
}
// 一个包装结构体,以便我们可以将UnmarshalJSON方法附加到它上面
type JSONMessage struct {
Message
}
// 解组字符串中的JSON
func (m *JSONMessage) UnmarshalJSON(b []byte) error {
var messageString string
if err := json.Unmarshal(b, &messageString); err != nil {
return err
}
if err := json.Unmarshal([]byte(messageString), &m.Message); err != nil {
return err
}
return nil
}
type Events struct {
LogEvents []struct {
Message JSONMessage `json:"message"`
Timestamp int64 `json:"timestamp"`
} `json:"logEvents"`
}
(注意这个双重结构体技巧,它在我们解组内部Message时隐藏了UnmarshalJSON方法)。
然后主循环就变成了(playground)
func main() {
var data Events
err := json.Unmarshal([]byte(in), &data)
if err != nil {
log.Fatal(err)
}
var foundNames = map[string]struct{}{}
for _, logEvent := range data.LogEvents {
for _, lbMetric := range logEvent.Message.Slack.LbMetrics {
for _, metric := range lbMetric.Metrics {
fmt.Println(metric.Name)
foundNames[metric.Name] = struct{}{}
}
}
}
fmt.Printf("found = %d\n", len(foundNames))
}
请注意,我使用了mholt出色的JSON to Go工具来生成结构体定义——你只需粘贴JSON,它就会为你创建对应的Go结构体。
package main
import (
"encoding/json"
"fmt"
"regexp"
)
func main() {
jsonStr := `{
"logEvents": [{
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_84\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_2\",\"load_generator_84\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_84\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_3\",\"load_generator_84\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_86\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_4\",\"load_generator_86\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_89\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_5\",\"load_generator_89\":0}",
"timestamp": 1596838449873
}, {
"message": "{\"bufferLib\":\"Undefined\",\"_slack\":{\"lbMetrics\":[{\"Namespace\":\"default\",\"Dimensions\":[[\"item_index\",\"batch_index\",\"bufferLib\"],[\"bufferLib\"],[\"bufferLib\",\"item_index\"],[\"bufferLib\",\"batch_index\"]],\"Metrics\":[{\"Name\":\"load_generator_89\",\"Unit\":\"\"}]}],\"Timestamp\":1596838449873},\"batch_index\":\"batch_14185\",\"item_index\":\"item_6\",\"load_generator_89\":0}",
"timestamp": 1596838449873
}]
}`
var data map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)
uniqueGenerators := make(map[string]bool)
re := regexp.MustCompile(`"Name":"(load_generator_\d+)"`)
logEvents := data["logEvents"].([]interface{})
for _, event := range logEvents {
eventMap := event.(map[string]interface{})
message := eventMap["message"].(string)
matches := re.FindStringSubmatch(message)
if len(matches) > 1 {
uniqueGenerators[matches[1]] = true
}
}
fmt.Printf("Unique load generators: %d\n", len(uniqueGenerators))
fmt.Print("Generators: ")
first := true
for gen := range uniqueGenerators {
if !first {
fmt.Print(", ")
}
fmt.Print(gen)
first = false
}
}
输出结果:
Unique load generators: 3
Generators: load_generator_84, load_generator_86, load_generator_89
如果需要更精确的解析,可以使用结构体定义:
type LogEvent struct {
Message string `json:"message"`
Timestamp int64 `json:"timestamp"`
}
type MessageData struct {
Slack struct {
LbMetrics []struct {
Metrics []struct {
Name string `json:"Name"`
} `json:"Metrics"`
} `json:"lbMetrics"`
} `json:"_slack"`
}
func main() {
var data struct {
LogEvents []LogEvent `json:"logEvents"`
}
json.Unmarshal([]byte(jsonStr), &data)
uniqueGenerators := make(map[string]bool)
for _, event := range data.LogEvents {
var msgData MessageData
json.Unmarshal([]byte(event.Message), &msgData)
for _, metric := range msgData.Slack.LbMetrics {
for _, m := range metric.Metrics {
if strings.HasPrefix(m.Name, "load_generator_") {
uniqueGenerators[m.Name] = true
}
}
}
}
fmt.Printf("Unique load generators: %d\n", len(uniqueGenerators))
for gen := range uniqueGenerators {
fmt.Println(gen)
}
}

