Merge

Solution · Music

Building a Music Industry Knowledge Graph with Merge

The music industry is a web of relationships: artists sign to labels, release albums, perform at venues, and collaborate across borders. Data about these entities lives in dozens of systems — Spotify, Apple Music, Ticketmaster, Bandcamp, TIDAL — each with its own naming conventions, IDs, and quirks.

"The Weeknd" on Spotify is "The Weeknd" on Apple Music, but "JAY Z" on TIDAL is "Jay-Z" everywhere else. "Coachella" is shorthand for "Coachella Valley Music and Arts Festival." These inconsistencies fragment your data and make it impossible to answer simple questions like "Which artists on Universal Music have performed at Wembley?"

In this guide, we'll build a music industry knowledge graph using Merge that resolves these duplicates automatically, connects entities through relationships, and gives you a single source of truth.

Empty dashboard before we begin

What We're Building

A knowledge graph with four entity types and four relationship types:

  • Artist → signed_to → Label
  • Album → created_by → Artist
  • Album → released_on → Label
  • Artist → performed_at → Venue

We'll ingest data from multiple sources (Spotify, Apple Music, Ticketmaster, StubHub, TIDAL, Bandcamp), let Merge's resolution engine deduplicate records, and end up with clean golden entities connected by traversable relationships.

Step 1: Define Entity Schemas

Each schema tells Merge how to compare incoming records. Attributes are typed as key (primary matching signal), supporting (boosts confidence), or deterministic (exact ID match = instant merge).

Artist Schema

curl -X POST https://merge-ai.app/v1/schemas \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "attributes": [
      {"name": "name", "type": "key", "match_strategy": "fuzzy", "weight": 0.5},
      {"name": "genre", "type": "supporting", "match_strategy": "exact", "weight": 0.2},
      {"name": "origin", "type": "supporting", "match_strategy": "fuzzy", "weight": 0.2},
      {"name": "active_since", "type": "supporting", "match_strategy": "exact", "weight": 0.1},
      {"name": "external_id", "type": "deterministic", "match_strategy": "exact", "weight": 1.0}
    ],
    "resolution": {"auto_merge_threshold": 0.9, "review_threshold": 0.7}
  }'

Album Schema

curl -X POST https://merge-ai.app/v1/schemas \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Album",
    "attributes": [
      {"name": "title", "type": "key", "match_strategy": "fuzzy", "weight": 0.5},
      {"name": "release_year", "type": "supporting", "match_strategy": "exact", "weight": 0.3},
      {"name": "genre", "type": "supporting", "match_strategy": "exact", "weight": 0.1},
      {"name": "external_id", "type": "deterministic", "match_strategy": "exact", "weight": 1.0}
    ],
    "resolution": {"auto_merge_threshold": 0.9, "review_threshold": 0.7}
  }'

Label Schema

curl -X POST https://merge-ai.app/v1/schemas \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Label",
    "attributes": [
      {"name": "name", "type": "key", "match_strategy": "fuzzy", "weight": 0.5},
      {"name": "parent_company", "type": "supporting", "match_strategy": "fuzzy", "weight": 0.2},
      {"name": "headquarters", "type": "supporting", "match_strategy": "fuzzy", "weight": 0.2},
      {"name": "external_id", "type": "deterministic", "match_strategy": "exact", "weight": 1.0}
    ],
    "resolution": {"auto_merge_threshold": 0.9, "review_threshold": 0.7}
  }'

Venue Schema

curl -X POST https://merge-ai.app/v1/schemas \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Venue",
    "attributes": [
      {"name": "name", "type": "key", "match_strategy": "fuzzy", "weight": 0.5},
      {"name": "city", "type": "supporting", "match_strategy": "fuzzy", "weight": 0.3},
      {"name": "capacity", "type": "supporting", "match_strategy": "exact", "weight": 0.1},
      {"name": "venue_type", "type": "supporting", "match_strategy": "exact", "weight": 0.1},
      {"name": "external_id", "type": "deterministic", "match_strategy": "exact", "weight": 1.0}
    ],
    "resolution": {"auto_merge_threshold": 0.9, "review_threshold": 0.7}
  }'

Schemas configured in Merge

Resolution Thresholds

The two thresholds control the decision pipeline:

Confidence Score Decision
≥ 0.9 Auto-merge — records are combined without human review
0.7 – 0.89 Review — flagged for human decision
< 0.7 Create — treated as a new entity

Step 2: Define Relationships

Relationships connect entity types and enable graph traversal:

# Artist → Label
curl -X POST https://merge-ai.app/v1/relationships \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "signed_to", "from_entity_type": "Artist", "to_entity_type": "Label"}'

# Album → Label
curl -X POST https://merge-ai.app/v1/relationships \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "released_on", "from_entity_type": "Album", "to_entity_type": "Label"}'

# Album → Artist
curl -X POST https://merge-ai.app/v1/relationships \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "created_by", "from_entity_type": "Album", "to_entity_type": "Artist"}'

# Artist → Venue
curl -X POST https://merge-ai.app/v1/relationships \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "performed_at", "from_entity_type": "Artist", "to_entity_type": "Venue"}'

Step 3: Ingest Base Data

Labels

curl -X POST https://merge-ai.app/v1/entities/batch \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Label",
    "records": [
      {"source": "spotify", "attributes": {"name": "Sony Music Entertainment", "parent_company": "Sony Group", "headquarters": "New York"}},
      {"source": "spotify", "attributes": {"name": "Universal Music Group", "parent_company": "Vivendi", "headquarters": "Santa Monica"}},
      {"source": "spotify", "attributes": {"name": "Warner Music Group", "parent_company": "Access Industries", "headquarters": "New York"}},
      {"source": "spotify", "attributes": {"name": "XO Records", "parent_company": "Republic Records", "headquarters": "Toronto"}},
      {"source": "spotify", "attributes": {"name": "Def Jam Recordings", "parent_company": "Universal Music Group", "headquarters": "New York"}},
      {"source": "spotify", "attributes": {"name": "Parlophone Records", "parent_company": "Warner Music Group", "headquarters": "London"}},
      {"source": "spotify", "attributes": {"name": "Interscope Records", "parent_company": "Universal Music Group", "headquarters": "Santa Monica"}},
      {"source": "spotify", "attributes": {"name": "Roc Nation", "parent_company": "Independent", "headquarters": "New York"}}
    ]
  }'

Venues

curl -X POST https://merge-ai.app/v1/entities/batch \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Venue",
    "records": [
      {"source": "ticketmaster", "attributes": {"name": "Madison Square Garden", "city": "New York", "capacity": "20789", "venue_type": "arena"}},
      {"source": "ticketmaster", "attributes": {"name": "Wembley Stadium", "city": "London", "capacity": "90000", "venue_type": "stadium"}},
      {"source": "ticketmaster", "attributes": {"name": "Coachella Valley Music and Arts Festival", "city": "Indio", "capacity": "125000", "venue_type": "festival"}},
      {"source": "ticketmaster", "attributes": {"name": "Tokyo Dome", "city": "Tokyo", "capacity": "55000", "venue_type": "arena"}},
      {"source": "ticketmaster", "attributes": {"name": "Glastonbury Festival", "city": "Somerset", "capacity": "210000", "venue_type": "festival"}},
      {"source": "ticketmaster", "attributes": {"name": "The Forum", "city": "Los Angeles", "capacity": "17505", "venue_type": "arena"}}
    ]
  }'

Artists (with relationships)

When you ingest an entity, you can attach relationships inline by referencing existing entity IDs:

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "source_system": "spotify",
    "attributes": {
      "name": "The Weeknd",
      "genre": "R&B",
      "origin": "Toronto",
      "active_since": "2010",
      "external_id": "spotify:artist:weeknd"
    },
    "relationships": [
      {"relationship_type": "signed_to", "to_entity_id": "ent_xo_records_id"},
      {"relationship_type": "performed_at", "to_entity_id": "ent_the_forum_id"}
    ]
  }'

We ingested all eight artists this way: The Weeknd, Radiohead, Jay-Z, Billie Eilish, Kendrick Lamar, Taylor Swift, Coldplay, and Drake — each linked to their label and a venue they've performed at.

Albums (with relationships)

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Album",
    "source_system": "spotify",
    "attributes": {
      "title": "After Hours",
      "release_year": "2020",
      "genre": "R&B"
    },
    "relationships": [
      {"relationship_type": "created_by", "to_entity_id": "ent_the_weeknd_id"},
      {"relationship_type": "released_on", "to_entity_id": "ent_xo_records_id"}
    ]
  }'

All eight albums (After Hours, OK Computer, 4:44, DAMN., 1989, Take Care, The Blueprint, Kid A) were ingested with created_by and released_on relationships.

Entities ingested

Step 4: Test Entity Resolution

Now the interesting part. We'll ingest duplicate and near-duplicate records from different sources and see how Merge handles them.

Test 1: Deterministic Match (External ID)

The Weeknd arrives from Apple Music with the same external_id:

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "source_system": "apple_music",
    "attributes": {
      "name": "The Weeknd",
      "genre": "R&B",
      "origin": "Toronto",
      "active_since": "2010",
      "external_id": "spotify:artist:weeknd"
    }
  }'

Result: AUTO-MERGE — The deterministic external_id attribute matched exactly. No fuzzy logic needed.

Test 2: Fuzzy Name Match (Case + Punctuation)

TIDAL formats the name as "JAY Z" (no hyphen, all caps):

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "source_system": "tidal",
    "attributes": {
      "name": "JAY Z",
      "genre": "Hip-Hop",
      "origin": "New York",
      "active_since": "1986"
    }
  }'

Result: AUTO-MERGE — Fuzzy name matching handled the case difference and missing hyphen. Supporting attributes (genre, origin, active_since) all matched, pushing confidence above 0.9.

Test 3: Partial Name Match (Labels)

Apple Music lists "Sony Music" instead of "Sony Music Entertainment":

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Label",
    "source_system": "apple_music",
    "attributes": {
      "name": "Sony Music",
      "parent_company": "Sony Group",
      "headquarters": "New York"
    }
  }'

Result: AUTO-MERGE — "Sony Music" is a substring of "Sony Music Entertainment", and supporting attributes (parent_company, headquarters) matched, giving high confidence.

Test 4: Misspelling (Gorillas vs Gorillaz)

A Bandcamp source has "Gorillas" (a typo). Then the correct "Gorillaz" arrives from Spotify:

# First: misspelled version creates a new entity
curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "source_system": "bandcamp",
    "attributes": {"name": "Gorillas", "genre": "Alternative Rock", "origin": "London", "active_since": "1998"}
  }'

# Second: correct spelling triggers review
curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Artist",
    "source_system": "spotify",
    "attributes": {"name": "Gorillaz", "genre": "Alternative Rock", "origin": "London", "active_since": "1998"}
  }'

Result: REVIEW (confidence 0.72) — The name similarity was 0.95 (one character difference), and all supporting attributes matched. But the confidence landed between the review threshold (0.7) and auto-merge threshold (0.9), so it was flagged for human review.

Test 5: Abbreviation (MSG)

StubHub uses "MSG" for Madison Square Garden:

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Venue",
    "source_system": "stubhub",
    "attributes": {"name": "MSG", "city": "New York", "capacity": "20789", "venue_type": "arena"}
  }'

Result: AUTO-MERGE — Merge recognized the acronym match combined with identical city, capacity, and venue_type values.

Test 6: Short Name (Coachella)

StubHub just calls it "Coachella":

curl -X POST https://merge-ai.app/v1/entities \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entity_type": "Venue",
    "source_system": "stubhub",
    "attributes": {"name": "Coachella", "city": "Indio", "capacity": "125000", "venue_type": "festival"}
  }'

Result: AUTO-MERGE — "Coachella" matched against "Coachella Valley Music and Arts Festival" through substring/fuzzy matching, and supporting attributes (city, capacity, venue_type) provided strong confirmation.

Resolution Results Summary

Test Input Matched To Decision Signal
1 The Weeknd (Apple Music) The Weeknd AUTO-MERGE Deterministic external_id
2 JAY Z (TIDAL) Jay-Z AUTO-MERGE Fuzzy name + supporting attrs
3 Sony Music (Apple Music) Sony Music Entertainment AUTO-MERGE Partial name + parent_company + HQ
4 Gorillas (Bandcamp) CREATE No existing match
4b Gorillaz (Spotify) Gorillas REVIEW (0.72) High name_sim (0.95) + attrs match
5 MSG (StubHub) Madison Square Garden AUTO-MERGE Acronym + city + capacity + type
6 Coachella (StubHub) Coachella Valley Music... AUTO-MERGE Substring + city + capacity + type

Step 5: Review Queue

When Merge isn't confident enough to auto-merge but sees a likely match, it creates a review. The Gorillaz/Gorillas case landed here with a confidence score of 0.72.

Review pending for Gorillaz vs Gorillas

The review shows the comparison details: name similarity of 0.95, matching genre, origin, and active_since. A human reviewer can accept (merge) or reject (keep separate).

# Accept the merge
curl -X POST https://merge-ai.app/v1/reviews/REVIEW_ID/accept \
  -H "X-API-Key: YOUR_API_KEY"

After accepting, "Gorillaz" and "Gorillas" become one golden entity with two source records.

Step 6: Traverse the Knowledge Graph

Once entities are resolved and connected, you can traverse the graph:

# Get The Weeknd's 2-hop graph
curl https://merge-ai.app/v1/entities/ent_weeknd_id/graph?hops=2 \
  -H "X-API-Key: YOUR_API_KEY"

This returns the full neighborhood: The Weeknd → signed_to → XO Records, After Hours → created_by → The Weeknd, After Hours → released_on → XO Records, The Weeknd → performed_at → The Forum.

Merged entity with relationships

Step 7: Search Across Sources

Merge provides fuzzy search across all resolved entities:

curl "https://merge-ai.app/v1/entities/search?q=weeknd&entity_type=Artist" \
  -H "X-API-Key: YOUR_API_KEY"

Even though records came from Spotify, Apple Music, and other sources with slightly different formatting, search returns the single golden entity.

Search results

Final State

After ingestion and resolution, our knowledge graph contains:

  • 31 source records from 5 different systems
  • 6 automatic merges where Merge confidently deduplicated
  • 1 human review accepted (Gorillaz/Gorillas)
  • 4 entity types with traversable relationships

Final dashboard showing resolution activity

Tips for Music Industry Entity Resolution

1. Use external IDs as deterministic attributes. Spotify artist IDs, ISRCs for tracks, UPC codes for albums — these eliminate ambiguity when available.

2. Tune your thresholds per entity type. Venues benefit from a lower review threshold because abbreviations are common (MSG, O2, etc.). Artists might need a higher bar to avoid merging "Gorillaz" with "Gorillas" automatically.

3. Supporting attributes are powerful. A name match alone might be ambiguous, but "Jay-Z" + "Hip-Hop" + "New York" + "1986" together leave no doubt.

4. Design for multiple sources from day one. Include source_system in your ingestion to track provenance. When two sources disagree on an attribute value, Merge keeps both source records and picks the most confident.

5. Leverage the graph for data quality. If an album's created_by edge points to a merged artist, all source attributions automatically resolve. No manual cleanup needed.

6. Start with batch, scale with webhooks. Use /v1/entities/batch for initial loads, then set up webhooks for real-time ingestion from streaming platforms and ticketing systems.

Conclusion

Entity resolution in the music industry isn't just about deduplication — it's about building a connected graph where every artist, album, label, and venue has a single identity regardless of which system reported it. Merge handles the messy reality of inconsistent naming, abbreviations, typos, and missing data, giving you a clean knowledge graph you can query with confidence.

The combination of deterministic matching (for exact IDs), fuzzy matching (for name variants), and human review (for edge cases) means you get automation where it's safe and human oversight where it matters.

Get started at merge-ai.app.

Start free All solutions