Resotrack (demo, code) uses Neo4j to suggest popular, relevant tracks from Resonate’s music catalog
Resonate is a relatively young, (almost all) open source music streaming platform with a catalog featuring mostly but not exclusively ambient and electronic music, as categorized by Tag
s at the album level.
While many users enjoy exploring in random mode, listeners interested in learning more about the seemingly endless subgenres within Resonate would benefit from having a simple recommendation tool to find the most popular tracks for each tag.
In an attempt to provide a solution to this discovery issue, Resotrack (demo, code) uses Neo4j to suggest popular, relevant tracks for each tag in Resonate’s music catalog.
Resonate – the ethical music streaming co-op
Resotrack also happens to be built using Django-Neomodel and deployed on Aura Free and Heroku. This example will present a brief overview of the project and provide simple examples of apoc.periodic.commit
and importing JSON Data from a REST API into Neo4j using apoc.load.json
.
The Resotrack Data Model
While the creators of the tracks can add their tracks to a variety of types of TrackGroups
(lp
, eps
, etc.) and add Tags
to these TrackGroups
, non-artists can add tracks to TrackGroups
of type playlist
, and have limited (or no) tagging capabilities.
As Resotrack users search and interact with the data, the system calculates a “Top Track” for each tag and presents the “Top Track” for a particular tag to the user.
Using Resotrack
In the example below, the user has searched for techno
and is presented with the top track for tags containing the string techno. In the image below, since ambienttechno
has techno
as a substring, we can see that Daibutsu is the TOP_TRACK
for the Tag
ambientechno
.
In the Django admin, the superuser can view the project’s R(esonate) Users
, Tags
, Track groups
, and Tracks
.
Connecting the Django-Neomodel App to Aura Free
If you haven’t already, clone the repo to your local machine:
git clone git@github.com:whatSocks/reso-tag-charts.git
GitHub – whatSocks/reso-tag-charts: Example Movie app for Neo4j and Django
Create or log in to your Aura account
Neo4j Aura – Fully Managed Cloud Solution
Tap Create a database then select Aura Free.
Follow the prompts to create the database and take note of the username (neo4j) and password.
Log in to the neo4j browser and verify the database exists with the “Open” button.
In your terminal, navigate to the project’s root directory and create the database environment variable:
export NEO4J_BOLT_URL=neo4j+s://neo4j:password@host-or-ip:port
Run migrations and create your superuser (for the admin, this is using an SQLite database)
./manage.py migrate
./manage.py createsuperuser
Run the server:
python manage.py runserver
Now you should be able to access https://localhost:8000 and view the empty app.
Load the Data
An empty database is no fun. We can use apoc.load.json
(Strava example) and apoc.periodic.commit
to load the data from the Resonate API.
Importing JSON Data from a REST API into Neo4j – Developer Guides
You can easily create a Listener account on Resonate and create your own playlists before you start. While not required, accounts are free and are helpful in understanding the lay of the data.
Create Constraints
CREATE CONSTRAINT ON (a:Ruser) ASSERT a.uuid IS UNIQUE;
CREATE CONSTRAINT ON (a:TrackGroup) ASSERT a.uuid IS UNIQUE;
CREATE CONSTRAINT ON (a:Track) ASSERT a.uuid IS UNIQUE;
Add the first page of Playlists (a type of TrackGroup)
WITH 'https://api.resonate.coop/v2/' AS uri
CALL apoc.load.json(uri + ‘trackgroups?type=playlist’) // in this example, grabbing listener-generated playlists
YIELD value
UNWIND value[“data”] as data
MERGE (u:RUser {uuid:toString(data['user']['id'])})
MERGE (t:TrackGroup {uuid:toString(data['id'])})
MERGE (u)-[:OWNS]->(t)
SET t.title = data['title']
SET t.type = data['type']
SET t.slug = data['slug']
SET t.tracks_imported = false
Add more TrackGroups
WITH 'https://api.resonate.coop/v2/' AS uri
CALL apoc.load.json(uri + ‘trackgroups’) // in this example, grabbing listener-generated playlists
YIELD value
UNWIND value[“data”] as data
MERGE (u:RUser {uuid:toString(data['user']['id'])})
MERGE (t:TrackGroup {uuid:toString(data['id'])})
MERGE (u)-[:OWNS]->(t)
SET t.title = data['title']
SET t.type = data['type”]
SET t.slug = data['slug]
SET t.tracks_imported = false
Add Tracks
CALL apoc.periodic.commit(
"MATCH (tg:TrackGroup)
WHERE NOT tg.tracks_imported
SET tg.tracks_imported = true
WITH tg limit $limit
WITH 'https://api.resonate.coop/v2/' AS uri, tg.uuid as tg_id
CALL apoc.load.json(uri + 'trackgroups/' + tg_id )
YIELD value
UNWIND value['data']['items'] as items
MERGE (u:RUser {uuid:toString(items['track']['creator_id'])})
MERGE (track:Track {uuid:toString(items['track']['id'])})
MERGE (t)-[:HAS_TRACK]->(track)
MERGE (track)<-[:CREATED]-(u)
SET track.title = items['track']['title']
SET track.tags_imported = false
RETURN count(*)",
{limit:10});
Add Tags
CALL apoc.periodic.commit(
"
MATCH (u:RUser)-[:CREATED]->(track:Track)
WHERE not u.uuid in ['7212','4315',’4414'] // bad data
AND NOT track.tags_imported
SET track.tags_imported = true
WITH u as artist, u.uuid as user_id, count(DISTINCT track) as tracks,'https://api.resonate.coop/v2/' as uri
ORDER BY tracks desc
LIMIT $limit
CALL apoc.load.json(uri + 'artists/' + user_id + '/releases') // grabbing all
YIELD value
UNWIND value['data'] as data
UNWIND data['tags'] as tags
MERGE (t:TrackGroup {uuid:toString(data['id'])})
MERGE (user:RUser {uuid:toString(user_id)})-[:OWNS]->(t)
MERGE (tag:Tag {name:toLower(tags)})
MERGE (tag)<-[:HAS_TAG]-(t)
SET tag.uuid=apoc.create.uuid()
SET t.title = data['title']
SET t.type = data['type']
RETURN count(*)
",
{limit:10});
Now you should be able to explore the data locally, with your data safe and sound in Aura.
Learn More
- apoc.periodic.commit – APOC Documentation
- Importing JSON Data from a REST API into Neo4j – Developer Guides
- Load JSON – APOC Documentation
- Resonate – the ethical music streaming co-op
- GitHub – whatSocks/reso-tag-charts: Example Movie app for Neo4j and Django
- Neo4j Aura – Neo4j Aura
- Getting Started with Neomodel
Resotrack: Exploring the Resonate API with Django-Neomodel on Aura was originally published in Neo4j Developer Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.