-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
146 lines (120 loc) · 2.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"io"
"net/http"
_ "net/http/pprof"
"os"
"strconv"
// "runtime/trace"
)
const DataFile = "data/music-1000000.tsv"
const Port = 4000
const (
UserId = iota
ArtistId
Artist
Plays
)
type PlayCount struct {
ArtistId string
Artist string
Users []string
Plays int
}
func NewPlayCount(rec []string) *PlayCount {
elem := &PlayCount{
ArtistId: rec[ArtistId],
Artist: rec[Artist],
}
return elem
}
type MusicData map[string]*PlayCount
var musicData MusicData
// Reads tsv data file into records.
func readData(filename string) (records [][]string, err error) {
// Verify file can be opened.
fmt.Printf("Opening data file '%s'...\n", filename)
f, err := os.Open(filename)
if err != nil {
return records, err
}
defer f.Close()
// Read tsv file with inconsistent quotes
fmt.Println("Reading data...")
r := csv.NewReader(f)
r.Comma = '\t'
r.LazyQuotes = true
r.TrimLeadingSpace = true
var rec []string
for {
rec, err = r.Read()
//fmt.Printf("%7d %s\n", i, err)
if err == io.EOF {
return records, nil
}
if err == nil {
records = append(records, rec)
} else {
//fmt.Printf("Read error: %s - ignoring\n", err)
}
}
return records, err
}
// Parses tsv records into defined data format.
func parseData(records [][]string) MusicData {
data := make(MusicData)
for _, rec := range records {
plays, _ := strconv.Atoi(rec[Plays])
//fmt.Printf("%d: %5d %s %s %s\n", i, plays, rec[ArtistId], rec[UserId], rec[Artist])
elem, ok := data[rec[ArtistId]]
if !ok {
elem = NewPlayCount(rec)
}
elem.Plays += plays
elem.Users = append(elem.Users, rec[UserId])
data[rec[ArtistId]] = elem
}
return data
}
func handleGetOne(rw http.ResponseWriter, r *http.Request) {
var pc *PlayCount
for _, pc = range musicData {
fmt.Printf("%#v\n", pc)
break
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(200)
json.NewEncoder(rw).Encode(pc)
}
func main() {
/* Uncomment to enable tracing tool
// Create a file to hold tracing data.
// View output: go tool trace trace.out
tf, err := os.Create("trace.out")
if err != nil {
log.Fatal(err)
}
defer tf.Close()
// Start gathering the tracing data.
trace.Start(tf)
defer trace.Stop()
*/
records, err := readData(DataFile)
if err != nil {
fmt.Printf("Encountered error after %d records: %s", len(records), err)
}
fmt.Printf("Read %d records.\n", len(records))
fmt.Println("Parsing data...")
musicData = parseData(records)
fmt.Printf("Parsed %d artist play count records.\n", len(musicData))
for id, elem := range musicData {
fmt.Printf("%s: %5d %7d %s\n", id, len(elem.Users), elem.Plays, elem.Artist)
}
http.HandleFunc("/getone", handleGetOne)
// Uncomment to profile web server functionality.
// fmt.Printf("Listening on port %d...", Port)
// http.ListenAndServe(fmt.Sprintf(":%d", Port), nil)
}