倾听 10 年:使用 Splunk 分析我的音乐数据





0/5 (0投票)
使用 Splunk 分析我的音乐数据
我使用音乐服务 Last.fm 已经十年了,用来追踪我的听歌行为。我一直喜欢获取关于我听的音乐的基本统计数据,更不用说“兼容性”功能,它会告诉你你和朋友有哪些共同的音乐收听习惯。
我不仅在过去的十年里追踪了我的听歌行为,我还一直在记录我参加过的所有音乐会,并且我的音乐主要保存在 iTunes 中。我有三个不同的音乐数据来源,涵盖了我生命中超过 15 年的数据,现在我可以将它们 Splunk 化了。
开始吧!
获取数据...
Last.fm 有一个 API,无需身份验证即可拉取给定用户的最近曲目,这使得使用 user.getRecentTracks 端点轻松获取数据。我用 Splunk Add-on Builder 构建了一个附加组件;经过多次迭代,它终于能完全满足我的需求。它构建起来很简单,但如果你想了解我的附加组件的配置细节,请联系我。
根据你的数据量,我建议你使用脚本回填数据。我使用了 lastexport.py 脚本 和 NPM 模块 来完成这项工作,但你也可以自己编写。设置回填数据的字段提取和源类型相对简单。如果你回填数据,请确保 props.conf 中的 MAX_DAYS_AGO 设置长于默认值。我为这个源类型设置了 10 年的数据,所以我将其设置得很远。
我还在“搜索和报告”应用中设置了一个 `lastfm` 宏,以指定不同的 Last.fm 源类型,这样在搜索时,我可以使用该宏,而不必考虑指定包含我的 Last.fm 数据的单个源类型。
在获取 Last.fm 数据后,我想添加我的 iTunes 数据和我的音乐会数据。自从我开始参加音乐会以来,我就一直在记录我的音乐会数据,所以我使用 Lookup File Editor 应用上传数据并以有用的方式格式化。我决定将这些数据添加为查找表而不是事件,这样我就可以轻松更新。
iTunes 数据可以在 library.xml 文件中访问,但该文件不是标准 XML,因此直接将其放入 Splunk 平台没有意义。相反,我再次依赖 Github 上的开源脚本,使用 iTunes_csv 脚本将 XML 数据转换为 CSV。这意味着我只能使用该开发人员脚本中指定的字段,而不是 XML 中所有可用的字段。如果你使用该脚本,请注意将数据输出到文件,因为它不会自动执行此操作。
现在我有了所有三个我想开始使用的数据源的数据,是时候开始搜索了!
搜索和仪表板
我首先编写搜索来验证我的附加组件是否正常工作。我想确保在我听歌时数据确实正在流式传输。我创建了一个表格并按时间排序,这样我就可以立即看到基本数据。
`lastfm` | table track_name artist _time | sort _time
然后我想找出我过去一天的艺术家分布。
`lastfm` | timechart count by artist useother=f
现在是时候雄心勃勃了。根据听歌次数,2017 年我的前 20 位艺术家是谁?
`lastfm` | timechart count(artist) by artist useother=f usenull=f| sort -count(artist) limit=20
通过堆叠我的面积图,我还可以一目了然地看到我对这 20 位顶级艺术家的总体听歌次数也随着时间的推移而增加。
然而,此搜索的下钻行为默认情况下并不美观。它完美地限制了时间范围,但显示了原始事件,其中包含冗余的字段信息,例如各种字段的 mbid (MusicBrainz Identifier) 以及源和源类型。我希望它更好,所以我构建了一个动态下钻。
最新版本的 Splunk 平台包含基于 UI 的下钻编辑,因此我可以指定自己的搜索。但是,我想指定下钻令牌——我目前无法在 UI 中做到这一点——所以我参考了仪表板和可视化手册中关于 仪表板中的令牌用法 的文档。我确定了要引用哪个令牌来显示有关艺术家的数据,并发现了要用于最早和最晚时间来指定面板时间范围的令牌。
<drilldown> <set token="artist">$click.name2$</set> <link target="_blank">search?q=`lastfm` artist="$artist$" | stats count(track_name) by artist track_name album | sort -count(track_name)&earliest=$earliest$&latest=$latest$</link> </drilldown>
我已经感到很有成就感了,但我想设置另一个搜索,以显示我搬到加利福尼亚后听过的排名前 20 的歌曲。这有点像我的音乐聆听“加利福尼亚时代”。
index=music | stats count(track_name) by track_name,artist | sort -count(track_name) limit=20
然而,我最初选择以条形图显示该信息……结果很糟糕。你几乎无法阅读它,它无法清晰地传达信息,甚至没有空间列出我正在听的艺术家或曲目名称。是时候进行新的可视化了。进入:Trellis。
简单地切换到按艺术家拆分的 Trellis 布局的柱状图,我就快完成了。它默认为共享比例,切掉了 Y 轴,所以我将 Y 轴最小值指定为 0,然后我又可以继续操作了。
音乐会数据分析
我想继续下去,开始查看另一个数据源:音乐会数据。我有这个音乐会数据的查找表,我想对其进行跨时间分析。然而,由于这是一个查找表,我不能简单地这样写搜索
| inputlookup concerthistoryparse.csv | timechart span=1mon count
当然,我有一个日期字段,但 timechart 不知道它是一个时间字段,也不知道它是什么格式。因为 timechart 需要一个 _time 字段才能随时间执行统计分析,所以我必须将查找表中的日期字段转换为 _time 字段。幸运的是,我可以使用 convert 搜索命令来做到这一点。
| inputlookup concerts.csv | convert timeformat="%B %d %Y" mktime(date) AS _time | timechart span=1mon count
如果我使用 strftime 指定时间格式,那么我就可以将查找表中的日期字段转换为 timechart 识别的 _time 字段。
但是等等,我这个面板也想要下钻。我希望它能显示我在图表中点击的那个月里参加过的 بالضبط 五场音乐会。
<drilldown> <set token="clicktime">$click.value$</set> <link target="_blank">search?q=| inputlookup concerthistoryparse.csv | convert timeformat="%B %d %Y" mktime(date) AS _time | eval month = strftime(_time,"%m"), year = strftime(_time,"%Y"), clickmonth = strftime($clicktime$,"%m"), clickyear = strftime($clicktime$,"%Y") | where month=clickmonth and year=clickyear | table date, opener1,opener2, headliner, venue, city, state</link> </drilldown>
我有一个非常多事的十一月,所以让我们打开那个月的下钻,看看我们得到了什么。
让我们制作更多有趣的视觉化效果,比如一张分区设色地图,因为我有这些音乐会的位置数据!
Splunk 平台随附的用于 geom 命令的 geo_us_states 查找表要求 featureId 为完整的州名,所以我确保我的音乐会查找表数据已准备好以这种格式工作,然后开始编写我的搜索。我可以在搜索中指定要从查找表用作包含州信息的 featureId 字段。
| inputlookup concerthistoryparse.csv | stats count(state) by state | geom geo_us_states featureIdField="state"
我将分区设色地图格式化,使其聚焦于美国,并用可区分的颜色显示只有少量演出的州。通过堪萨斯城的经纬度和 4 倍的缩放级别,我进行了一些可视化方面的调整。我还尝试了可用的颜色和瓷砖,以找到适合我想要的外观。
更多音乐数据分析!
那几乎是我能想到的所有有趣的视觉化。我设置了一些单值指标,以获取我数据的一些良好统计数据。我想要一个音乐会出席趋势指标,以及我参加过的音乐会总数;我还想查看 iTunes 歌曲总数以及我从未听过的 iTunes 歌曲数量。显示我的 iTunes 音乐库中最常见播放次数的饼图很清楚地表明:我几乎 30% 的 iTunes 音乐库歌曲从未听过。更糟糕的是,我只有另外 24% 的音乐库歌曲只听过一次。
我还想弄清楚我的发现和听歌多样性随着时间的推移情况如何。
`lastfm` | timechart span=3mon dc(artist)
大学期间在广播电台工作意味着我接触了大量新音乐——这在其他环境中很难复制。然而,从我的数据分析来看,我再次表现不错。也许并不令人惊讶,我听过的歌曲的去重计数和艺术家的去重计数在趋势线上并没有太大差异。我如今听的艺术家的多样性与 2010 年和 2011 年我在广播电台工作时相似,但歌曲的去重计数要低得多,这很可能表明我一直忙于工作等事情。
我采取了更多步骤来分析我的音乐会数据,找出我见过不止一次的艺术家以及访问次数最多的场馆列表。
为了使最常访问的场馆列表更有趣,我添加了一个快速下钻,可以在 Google 地图中搜索场馆名称。
<drilldown> <set token="venue_name">$click.value$</set> <link target="_blank">https://www.google.com/maps/search/$venue_name$</link> </drilldown>
机器学习分析
我使用助手来检测数值异常值和类别异常值,尝试获取有趣且易于理解的异常值。我最终使用助手来检测类别异常值;我从一个基本搜索开始,以识别数据中的曲目收听异常值。
`lastfm` | stats count(track_name) by artist,track_name
使用 count(track_name)
作为异常值字段,我能够获得有趣且易于理解的异常值。我打开搜索中的“数据和异常值”表,以找出还能看到什么可能解释这些为何是异常值。
我清理了表格,并添加了一些额外的字段,使其更美观,并将其限制为仅显示异常值。
`lastfm` | stats count(track_name) by track_name, artist | anomalydetection "count(track_name)" action=annotate | eval isOutlier = if(probable_cause != "", "1", "0") | where isOutlier=1 | table artist, track_name, "count(track_name)"
我把它放在一个仪表板上,旁边是一个显示热门歌曲收听的面板,然后将这两个面板连接到同一个时间输入,这样我就可以比较 MLTK 所说的收听异常值与同一时期热门收听情况。
潮人状态:高数据完整性
最后,我想将此带到让这篇博客文章得以诞生的仪表板面板。我和我的兄弟互相推荐音乐,但作为一名终身广播听众和永远不承认自己是潮人的人,我感到有必要捍卫我的潮人可信度,以对抗一个曾经听汉森的兄弟的推荐。有什么比用一个显示艺术家最早曲目收听的仪表板更好的方式来做到这一点呢?
`lastfm` | search artist="VHS Collection" |stats earliest(_time) AS earliestlisten by artist track_name | fieldformat earliestlisten = strftime(earliestlisten, " %m/%d/%Y %H:%M:%S") |sort earliestlisten
这次我选择使用 fieldformat 命令而不是 convert 命令,这样我就可以保留 _time 字段的格式并按时间顺序排序。如果在这种情况下使用 convert 命令,字段的格式也会转换为字符串,因此在转换字段后,你将无法再按时间顺序排序。
因为我希望能够在仪表板本身上执行这类搜索,所以我再次连接了一个输入令牌。使用仪表板编辑器,我添加了一个输入文本框,并——再次使用 仪表板中的令牌用法 文档——我为艺术家设置了一个令牌,然后将该令牌添加到仪表板面板标题和搜索中。
`lastfm` | search artist=$artist$ |stats earliest(_time) AS earliestlisten by artist track_name | fieldformat earliestlisten = strftime(earliestlisten, "%m/%d/%Y %H:%M:%S") |sort earliestlisten
通过几个仪表板,我现在可以超越我兄弟的音乐推荐,判断我的 iTunes 音乐库中歌曲的缺失,评估我参加音乐会最多的州,并识别我的音乐收听习惯中的异常值。
2017 年回顾
为了结束 2017 年,我想知道我这一年发现了哪些乐队。一个相对简单的搜索后,我整理出了我发现的艺术家,听过 10 次以上的艺术家,以及我听过的这些艺术家的曲目。
`lastfm` | stats values(artist) earliest(_time) as earliestlisten count(artist) as artistcount values(track_name) as tracks by artist | fieldformat earliestlisten = strftime(earliestlisten, "%Y") | where artistcount > 10 | where earliestlisten>1483228800 | table artist,tracks,artistcount| sort -artistcount
下一步?
- 在此分析中添加和分析明显缺乏的数据:Spotify 数据。有了 Spotify 数据,我可以追踪将歌曲保存到 Spotify 音乐库后,它出现在我的 iTunes 音乐库中的模式,并将其与听歌次数相关联,甚至可以利用歌曲功能 API 并在此级别进行数据分析。
- 如果我能获得 API 密钥,SoundCloud 数据分析也会是下一步,但他们目前不提供。
- MusicBrainz 数据也拥有丰富的元数据可供分析。毕竟,如果我不知道歌曲或专辑发行日期与我第一次听歌之间的延迟时间,或者无法根据我听的艺术家的原籍国制作热力图,我就不能成为真正的潮人。
仍然有大量数据需要分析。如果您有兴趣帮助我,或者只是想打个招呼,请在 Twitter (@smorewithface) 或 Splunk 用户组 Slack 频道 (@smoir) 上联系。
特别感谢 Robin Pille 帮助我构建了第一个 LastFM 附加组件,Elias Haddad 和 Andrea Longdon 在 Splunk 附加组件构建器方面的工作,Luke Murphey 编写了查找文件编辑器,David Hazekamp 和 Yann Kherian 帮助编写搜索,Duane Waddle (@duckfez) 和 Cary Petterborg (@cp-regex-guru) 帮助尝试提取 library.xml 数据,以及 Michael Uschmann 和 Micah Kemp 帮助我解决了后续迭代的 Last.fm 附加组件中的时间戳和字段提取问题。