-
Notifications
You must be signed in to change notification settings - Fork 380
Expand file tree
/
Copy pathmxm_dataset_to_db.py
More file actions
executable file
·192 lines (169 loc) · 5.89 KB
/
Copy pathmxm_dataset_to_db.py
File metadata and controls
executable file
·192 lines (169 loc) · 5.89 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python
"""
Thierry Bertin-Mahieux (2011) Columbia University
tb2332@columbia.edu
This code puts the musiXmatch dataset (format: 2 text files)
into a SQLite database for ease of use.
This is part of the Million Song Dataset project from
LabROSA (Columbia University) and The Echo Nest.
http://labrosa.ee.columbia.edu/millionsong/
Copyright 2011, Thierry Bertin-Mahieux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
import sys
import sqlite3
def encode_string(s):
"""
Simple utility function to make sure a string is proper
to be used in a SQLite query
(different than posgtresql, no N to specify unicode)
EXAMPLE:
That's my boy! -> 'That''s my boy!'
"""
return "'" + s.replace("'", "''") + "'"
def die_with_usage():
""" HELP MENU """
print 'mxm_dataset_to_db.py'
print ' by T. Bertin-Mahieux (2011) Columbia University'
print ' tb2332@columbia.edu'
print 'This code puts the musiXmatch dataset into an SQLite database.'
print ''
print 'USAGE:'
print ' ./mxm_dataset_to_db.py <train> <test> <output.db>'
print 'PARAMS:'
print ' <train> - mXm dataset text train file'
print ' <test> - mXm dataset text test file'
print ' <output.db> - SQLite database to create'
sys.exit(0)
if __name__ == '__main__':
# help menu
if len(sys.argv) < 4:
die_with_usage()
# params
trainf = sys.argv[1]
testf = sys.argv[2]
outputf = sys.argv[3]
# sanity checks
if not os.path.isfile(trainf):
print 'ERROR: %s does not exist.' % trainf
sys.exit(0)
if not os.path.isfile(testf):
print 'ERROR: %s does not exist.' % testf
sys.exit(0)
if os.path.exists(outputf):
print 'ERROR: %s already exists.' % outputf
sys.exit(0)
# open output SQLite file
conn = sqlite3.connect(outputf)
# create tables -> words and lyrics
q = "CREATE TABLE words (word TEXT PRIMARY KEY)"
conn.execute(q)
q = "CREATE TABLE lyrics (track_id,"
q += " mxm_tid INT,"
q += " word TEXT,"
q += " count INT,"
q += " is_test INT,"
q += " FOREIGN KEY(word) REFERENCES words(word))"
conn.execute(q)
# get words, put them in the words table
f = open(trainf, 'r')
for line in f.xreadlines():
if line == '':
continue
if line[0] == '%':
topwords = line.strip()[1:].split(',')
f.close()
break
for w in topwords:
q = "INSERT INTO words VALUES("
q += encode_string(w) + ")"
conn.execute(q)
conn.commit()
# sanity check, make sure the words were entered according
# to popularity, most popular word should have ROWID 1
q = "SELECT ROWID, word FROM words ORDER BY ROWID"
res = conn.execute(q)
tmpwords = res.fetchall()
assert len(tmpwords) == len(topwords), 'Number of words issue.'
for k in range(len(tmpwords)):
assert tmpwords[k][0] == k + 1, 'ROWID issue.'
assert tmpwords[k][1].encode('utf-8') == topwords[k], 'ROWID issue.'
print "'words' table filled, checked."
# we put the train data in the dataset
f = open(trainf, 'r')
cnt_lines = 0
for line in f.xreadlines():
if line == '' or line.strip() == '':
continue
if line[0] in ('#', '%'):
continue
lineparts = line.strip().split(',')
tid = lineparts[0]
mxm_tid = lineparts[1]
for wordcnt in lineparts[2:]:
wordid, cnt = wordcnt.split(':')
q = "INSERT INTO lyrics"
q += " SELECT '" + tid + "', " + mxm_tid + ", "
q += " words.word, " + cnt + ", 0"
q += " FROM words WHERE words.ROWID=" + wordid
conn.execute(q)
# verbose
cnt_lines += 1
if cnt_lines % 15000 == 0:
print 'Done with %d train tracks.' % cnt_lines
conn.commit()
f.close()
conn.commit()
print 'Train lyrics added.'
# we put the test data in the dataset
# only difference from train: is_test is now 1
f = open(testf, 'r')
cnt_lines = 0
for line in f.xreadlines():
if line == '' or line.strip() == '':
continue
if line[0] in ('#', '%'):
continue
lineparts = line.strip().split(',')
tid = lineparts[0]
mxm_tid = lineparts[1]
for wordcnt in lineparts[2:]:
wordid, cnt = wordcnt.split(':')
q = "INSERT INTO lyrics"
q += " SELECT '" + tid + "', " + mxm_tid + ", "
q += " words.word, " + cnt + ", 1"
q += " FROM words WHERE words.ROWID=" + wordid
conn.execute(q)
# verbose
cnt_lines += 1
if cnt_lines % 15000 == 0:
print 'Done with %d test tracks.' % cnt_lines
conn.commit()
f.close()
conn.commit()
print 'Test lyrics added.'
# create indices
q = "CREATE INDEX idx_lyrics1 ON lyrics ('track_id')"
conn.execute(q)
q = "CREATE INDEX idx_lyrics2 ON lyrics ('mxm_tid')"
conn.execute(q)
q = "CREATE INDEX idx_lyrics3 ON lyrics ('word')"
conn.execute(q)
q = "CREATE INDEX idx_lyrics4 ON lyrics ('count')"
conn.execute(q)
q = "CREATE INDEX idx_lyrics5 ON lyrics ('is_test')"
conn.execute(q)
conn.commit()
print 'Indices created.'
# close output SQLite connection
conn.close()