tijdloze.rocks MusicBrainz dataset
收藏tijdloze.rocks MusicBrainz 数据集生成
背景
tijdloze.rocks 网站提供了比利时广播电台 Studio Brussel 的年度“最佳歌曲”列表 De Tijdloze 的完整图表和统计数据。该列表最初包含 100 首歌曲,但近年来已增长到超过 2000 首歌曲。为了尽可能自动化地添加新歌曲到数据库中,需要从 MusicBrainz 数据库中获取更多关于每首歌曲的信息,包括:
- 歌曲首次出现的专辑,包括发行年份
- 艺术家的国籍
- 歌曲的 Spotify 标识符
MusicBrainz 数据库结构
MusicBrainz 数据库中最相关的数据类型包括艺术家、发行组、发行、录音和作品。例如:
- 艺术家 Nirvana 有一个发行组 Nevermind。
- 在 tijdloze.rocks 数据库中,MusicBrainz 的发行组对应于专辑。然而,在 MusicBrainz 数据库中,一个发行组可以有许多不同的发行,每个发行都有自己的曲目列表、格式、发行日期等。
- 歌曲 Smells Like Teen Spirit 在 MusicBrainz 数据库中是一个作品。通常,一个作品有许多不同的录音(早期演示版本、专辑版本、现场录音、不同艺术家的封面)。通常,一个录音可以被识别为该作品的“规范录音”,即当你请求播放该歌曲时,你期望在电台播放的录音(例如 Smell Like Teen Spirit)。
tijdloze.rocks MusicBrainz 数据集生成
数据集生成过程如下:
- 遍历所有来自比利时或与他们链接的 URL 超过 8 个的艺术家(其他艺术家被忽略,因为他们在任何 Tijdloze 图表中出现的可能性非常小)。
- 遍历所有归功于该艺术家的官方发行组,并确定哪些录音将此发行组视为其“规范”发行组,考虑以下因素:
- 一首歌可能作为单曲发行,发行年份比相应专辑早一年。然而,我们仍然认为这首歌首次出现在专辑上,而不是作为独立单曲发行(当发行日期差异超过一年时)。
- 同样,合辑专辑的优先级低于录音室专辑,尽管一首歌确实可能首次在合辑专辑上发行(例如 Nothing Really Ends)。
- 当 MusicBrainz 数据库中存在两个发行组(单曲和相应专辑)之间的“单曲来自”关系时,这是一个强烈的指示,表明这是正确的“规范”关系。然而,一些相关歌曲从未作为单曲发行,即使那些作为单曲发行的歌曲,“单曲来自”关系也不总是存在于 MusicBrainz 数据库中。
- 对于遇到的每个录音,导出已识别的规范发行组的 ID,以及其他相关数据,包括一个分数(基于该录音出现的发行数量),该分数稍后可用于识别与给定查询最相关的录音。
在使用数据集进行查询时,例如在 tijdloze.rocks API 中,应考虑以下因素:
- 艺术家和歌曲在拼写错误或使用替代名称时也应被找到。
- 只应考虑更相关的匹配录音,忽略例如现场录音(除非查询明确指出我们正在寻找现场录音)或不太知名的录音(例如早期演示版本),使用数据集中包含的分数进行识别。当多个录音足够相关时,应返回具有最早发行日期的录音。
数据集生成步骤
复制 MusicBrainz 数据库
按照 musicbrainz-docker 仓库中的说明创建 MusicBrainz 数据库的副本。
创建数据库导出模式
在数据库中创建一个新的 musicbrainz_export 模式,并执行以下 SQL 文件中的命令:
- sql/0_set_default_schema.sql
- sql/1_area_id_country_id.sql
- sql/2_export_tables.sql
- sql/3_artist_data.sql
- sql/4_artist_alias_data.sql
运行脚本以计算歌曲和专辑
运行 Python 脚本填充 mb_album 和 mb_song 表:
- 创建虚拟环境并安装 Python 依赖项
- 执行
main.py脚本
填充 mb_song_alias 表
执行 sql/5_song_alias_data.sql 中的命令填充 mb_song_alias 表。
导出新的表
使用 pg_dump 命令导出 musicbrainz_export 模式中的表。
查询创建 tijdlozedb.csv 数据集
执行以下 SQL 查询创建 tijdlozedb.csv 数据集:
postgresql SELECT song.id, song.title, album.id as "album_id", album.title as "album_title", album.release_year, album.musicbrainz_id, artist.id as "artist_id", IFNULL(CONCAT(artist.name_prefix, " ", artist.name), artist.name) as "artist_name", artist.country_id as "artist_country_id", artist.musicbrainz_id as "artist_musicbrainz_id", artist2.id as "artist2_id", IFNULL(CONCAT(artist2.name_prefix, " ", artist2.name), artist2.name) as "artist2_name", artist2.country_id as "artist2_country_id", artist2.musicbrainz_id as "artist2_musicbrainz_id" FROM song JOIN album ON album.id = song.album_id JOIN artist ON artist.id = song.artist_id LEFT JOIN artist AS artist2 ON artist2.id = song.second_artist_id




