🌌 Star Wars Day Graph Challenge: The Force of Connections Coming May the 4th!

To celebrate 48 years since A New Hope and 20 years since Revenge of the Sith, we're challenging you to build your own Star Wars universe — in graph form — using Neo4j and your best Cypher skills.

:date: Timeline

  • :green_circle: Submissions Open: Sunday, May 4 @ 00:00 CET
  • :red_circle: Submissions Close: Thursday, May 8 @ 23:59 CET
  • :trophy: Winner Announced by: Friday, May 9 @ 23:59 CET

:puzzle_piece: Challenge Rules

  • Use Neo4j (AuraDB Free, Sandbox, or local install)

  • Your graph must include:

    • :white_check_mark: Exactly 20 nodes
    • :link: Maximum 48 relationships
    • :technologist:Cypher code no longer than 66 lines
  • Submit by replying to this thread once it is open on May the 4th with:

    • A graph screenshot
    • Your Cypher
    • A short 1 paragraph description of your graph concept (making this too lengthy will cause a great disturbance in the force)

:trophy: Judging & Prizes

A panel of Neo4j Jedi Council members (myself, @jason.koo and @alison1) will evaluate submissions based on five Force-sensitive criteria:

  1. Galactic Creativity :sparkles: 20 Points
    Star Wars-themed originality, clever references, and depth of lore

  2. Graph Modeling Mastery :puzzle_piece: 20 Points
    Smart use of nodes and relationships to convey structure and meaning

  3. Cypher Craftsmanship :technologist: 20 Points
    Clean, expressive Cypher — all within the 66-line limit

  4. Storytelling Through Structure :open_book: 20 Points
    Does your graph tell a story or reveal a deeper truth in the galaxy?

  5. Visual Impact :framed_picture: 20 Points
    Great use of Neo4j Tools to bring your idea to life

Top submission receives:

  • :brain: The honorary “May the 4th” community badge
  • :rocket: Spotlight in the Neo4j Community
  • :dizzy: Eternal bragging rights with Neo4j Galactic T-Shirt

:warning: Disclaimer

This is a fan-created challenge for educational and creative purposes. It is not affiliated with, endorsed by, or sponsored by Lucasfilm Ltd., Disney, or any of their subsidiaries. “Star Wars” and all related characters and elements are trademarks of Lucasfilm Ltd.

3 Likes

This topic was automatically opened after 2 days.

Here's a graph that models some of the occurrences of the phrase "...have a bad feeling.." (or similar variants) occurs in the movies. One "..good feeling.." phrase is also throw in since it is in the same vein. There are many more occurrences but just picked these to fit in the graph. (There is some dispute about whether BB-8 really beeped this sentiment)

Cypher for the one "good feeling" in my graph:
MATCH (c:Character)-[r:SAYS_GOOD_FEELING_IN]-(m) return c.name as Character, m.title as Movie, r.context as Context, r.phrase as Phrase

Enjoy!
(:crossed_swords::May)-[:THE]->(:star::Force)-[:BE_WITH]->(:person_beard::You)

Cypher to build the graph:

CREATE (ep1:Movie {title: "Star Wars: Episode I - The Phantom Menace", year: 1999})

CREATE (ep2:Movie {title: "Star Wars: Episode II - Attack of the Clones", year: 2002})

CREATE (ep3:Movie {title: "Star Wars: Episode III - Revenge of the Sith", year: 2005})

CREATE (ep4:Movie {title: "Star Wars: Episode IV - A New Hope", year: 1977})

CREATE (ep5:Movie {title: "Star Wars: Episode V - The Empire Strikes Back", year: 1980})

CREATE (ep6:Movie {title: "Star Wars: Episode VI - Return of the Jedi", year: 1983})

CREATE (ep7:Movie {title: "Star Wars: The Force Awakens", year: 2015})

CREATE (ep8:Movie {title: "Star Wars: The Last Jedi", year: 2017})

CREATE (ep9:Movie {title: "Star Wars: The Rise of Skywalker", year: 2019})

CREATE (rogue:Movie {title: "Rogue One: A Star Wars Story", year: 2016})

CREATE (solo:Movie {title: "Solo: A Star Wars Story", year: 2018})

CREATE (obiwan:Character {name: "Obi-Wan Kenobi"})

CREATE (anakin:Character {name: "Anakin Skywalker"})

CREATE (luke:Character {name: "Luke Skywalker"})

CREATE (han:Character {name: "Han Solo"})

CREATE (leia:Character {name: "Princess Leia"})

CREATE (c3po:Character {name: "C-3PO"})

CREATE (k2so:Character {name: "K-2SO"})

CREATE (bb8:Character {name: "BB-8"})

CREATE (lando:Character {name: "Lando Calrissian"})

CREATE (obiwan)-[:APPEARS_IN]->(ep1)

CREATE (obiwan)-[:APPEARS_IN]->(ep2)

CREATE (obiwan)-[:APPEARS_IN]->(ep3)

CREATE (obiwan)-[:APPEARS_IN]->(ep4)

CREATE (anakin)-[:APPEARS_IN]->(ep2)

CREATE (anakin)-[:APPEARS_IN]->(ep3)

CREATE (luke)-[:APPEARS_IN]->(ep4)

CREATE (han)-[:APPEARS_IN]->(ep4)

CREATE (han)-[:APPEARS_IN]->(ep5)

CREATE (han)-[:APPEARS_IN]->(ep6)

CREATE (han)-[:APPEARS_IN]->(ep7)

CREATE (han)-[:APPEARS_IN]->(solo)

CREATE (leia)-[:APPEARS_IN]->(ep5)

CREATE (leia)-[:APPEARS_IN]->(ep8)

CREATE (c3po)-[:APPEARS_IN]->(ep6)

CREATE (k2so)-[:APPEARS_IN]->(rogue)

CREATE (bb8)-[:APPEARS_IN]->(ep8)

CREATE (lando)-[:APPEARS_IN]->(ep9)

//Bad feelings plus one good feeling

CREATE (obiwan)-[:SAYS_BAD_FEELING_IN {phrase: "I have a bad feeling about this", context: "Entering Trade Federation ship (first occurence in chronologial order)"}]->(ep1)

CREATE (anakin)-[:SAYS_BAD_FEELING_IN {phrase: "I've got a bad feeling about this", context: "Captured in Geonosian arena as monsters approach"}]->(ep2)

CREATE (obiwan)-[:SAYS_BAD_FEELING_IN {phrase: "Oh, I have a bad feeling about this", context: "Blast doors closing during rescue mission"}]->(ep3)

CREATE (han)-[:SAYS_GOOD_FEELING_IN {phrase: "I've got a really good feeling about this", context: "Taking control of Millennium Falcon for first time"}]->(solo)

CREATE (luke)-[:SAYS_BAD_FEELING_IN {phrase: "I have a very bad feeling about this", context: "First appearance of phrase, approaching Death Star"}]->(ep4)

CREATE (han)-[:SAYS_BAD_FEELING_IN {phrase: "I've got a bad feeling about this", context: "Trapped in Death Star trash compactor"}]->(ep4)

CREATE (leia)-[:SAYS_BAD_FEELING_IN {phrase: "I have a bad feeling about it", context: "Inside the space slug in what they think is a cave"}]->(ep5)

CREATE (c3po)-[:SAYS_BAD_FEELING_IN {phrase: "I have a bad feeling about this", context: "Entering Jabba's palace"}]->(ep6)

CREATE (han)-[:SAYS_BAD_FEELING_IN {phrase: "I have a really bad feeling about this", context: "When captured by Ewoks on Endor"}]->(ep6)

CREATE (han)-[:SAYS_BAD_FEELING_IN {phrase: "I got a bad feeling about this", context: "Realizing rathtars are on the freighter"}]->(ep7)

CREATE (bb8)-[:SAYS_BAD_FEELING_IN {phrase: "*Beeps in droid*", context: "During opening space attack, confirmed by Leia and Poe (uncertain about this)"}]->(ep8)

CREATE (k2so)-[:SAYS_BAD_FEELING_IN {phrase: "I have a bad feeling about...", context: "Cut off while infiltrating Imperial base on Scarif"}]->(rogue)

CREATE (lando)-[:SAYS_BAD_FEELING_IN {phrase: "I got a bad feeling about this", context: "Watching First Order troops on Pasaana"}]->(ep9)

CREATE (obiwan)-[:MENTORS]->(anakin)

CREATE (obiwan)-[:MENTORS]->(luke)

CREATE (han)-[:PARTNERS_WITH]->(leia)

CREATE (han)-[:PARTNERS_WITH]->(lando)

CREATE (luke)-[:SIBLINGS_WITH]->(leia)

;
3 Likes

This graph is built using data from the Star Wars API, and JavaScript to transform the data into a Cypher query. One function loops through the first 3 films and builds a list of all planets and species mentioned. And a second function converts that data into a Cypher query.

Cypher Query:

UNWIND $films AS filmObj
WITH filmObj

MERGE (f:Film {episode_id: filmObj.episode_id, title: filmObj.title})

WITH filmObj, f

CALL {
  WITH filmObj, f
  UNWIND filmObj.planets AS pname
  WITH f, pname
  WHERE pname IN $planets
  MERGE (p:Planet {name: pname})
  MERGE (p)-[:FEATURED_IN]->(f)
  RETURN COUNT(*) AS planetCount
}

CALL {
  WITH filmObj, f
  UNWIND filmObj.species AS spname
  WITH f, spname
  WHERE spname IN $species
  MERGE (s:Species {name: spname})
  MERGE (s)-[:FEATURED_IN]->(f)
  RETURN COUNT(*) AS speciesCount
}

RETURN f

If you're interested in the JavaScript used to fetch and transform the API data, I wrote a quick guide here.

3 Likes




2 Likes

MERGE (anakin:Character {name:'Anakin Skywalker', alias:'Darth Vader', role:'Jedi Knight', status:'Turned', lightsaber:'Blue/Red'})
MERGE (obiwan:Character {name:'Obi-Wan Kenobi', role:'Jedi Master', status:'Alive', lightsaber:'Blue'})
MERGE (yoda:Character {name:'Yoda', role:'Grand Master', species:'Yoda’s species', status:'Alive'})
MERGE (palpatine:Character {name:'Palpatine', alias:'Darth Sidious', role:'Supreme Chancellor', affiliation:'Sith', status:'Alive'})
MERGE (padme:Character {name:'Padmé Amidala', role:'Senator', status:'Deceased', cause:'Childbirth'})
MERGE (grievous:Character {name:'General Grievous', species:'Kaleesh cyborg', role:'Military Leader', status:'Deceased'})
MERGE (dooku:Character {name:'Count Dooku', alias:'Darth Tyranus', role:'Sith Lord', status:'Deceased'})
MERGE (mace:Character {name:'Mace Windu', role:'Jedi Master', status:'Deceased', lightsaber:'Purple'})
MERGE (coruscant:Planet {name:'Coruscant', type:'City Planet', region:'Core Worlds'})
MERGE (mustafar:Planet {name:'Mustafar', type:'Lava Planet', region:'Outer Rim'})
MERGE (utapau:Planet {name:'Utapau', type:'Sinkhole Planet', region:'Outer Rim'})
MERGE (naboo:Planet {name:'Naboo', type:'Terrestrial', region:'Mid Rim'})
MERGE (jedi:Faction {name:'Jedi Order', alignment:'Light'})
MERGE (sith:Faction {name:'Sith', alignment:'Dark'})
MERGE (republic:Faction {name:'Galactic Republic', government:'Democracy'})
MERGE (separatists:Faction {name:'Separatist Alliance', goal:'Independence'})
MERGE (interceptor:Starship {name:'Jedi Interceptor', class:'Delta-7B', pilot:'Anakin'})
MERGE (invisible:Starship {name:'Invisible Hand', class:'Providence-class', commander:'Grievous'})
MERGE (order66:Event {name:'Order 66', type:'Clone Protocol', outcome:'Purge of Jedi'})
MERGE (duel:Event {name:'Duel on Mustafar', outcome:'Anakin defeated', date:'19 BBY'})
MERGE (anakin)-[:MEMBER_OF {start:'22 BBY'}]->(jedi)
MERGE (obiwan)-[:MEMBER_OF]->(jedi)
MERGE (yoda)-[:MEMBER_OF]->(jedi)
MERGE (mace)-[:MEMBER_OF]->(jedi)
MERGE (palpatine)-[:LEADS {title:'Dark Lord'}]->(sith)
MERGE (dooku)-[:MEMBER_OF]->(sith)
MERGE (grievous)-[:MEMBER_OF]->(separatists)
MERGE (padme)-[:MEMBER_OF]->(republic)
MERGE (anakin)-[:FROM]->(coruscant)
MERGE (padme)-[:FROM]->(naboo)
MERGE (palpatine)-[:FROM]->(naboo)
MERGE (grievous)-[:FROM]->(utapau)
MERGE (anakin)-[:FOUGHT_IN {scene:'Climactic Battle'}]->(duel)
MERGE (obiwan)-[:FOUGHT_IN]->(duel)
MERGE (dooku)-[:DIED_IN {method:'Beheaded'}]->(duel)
MERGE (palpatine)-[:INITIATED {code:'Execute Order 66'}]->(order66)
MERGE (mace)-[:DIED_IN {scene:'Palpatine’s Office'}]->(order66)
MERGE (yoda)-[:SURVIVED]->(order66)
MERGE (obiwan)-[:SURVIVED]->(order66)
MERGE (padme)-[:DIED_IN {cause:'Heartbreak'}]->(order66)
MERGE (grievous)-[:FOUGHT_IN]->(order66)
MERGE (duel)-[:HAPPENED_ON]->(mustafar)
MERGE (order66)-[:HAPPENED_ON]->(coruscant)
MERGE (interceptor)-[:USED_BY]->(anakin)
MERGE (invisible)-[:USED_BY]->(grievous)
MERGE (yoda)-[:MASTER_OF]->(obiwan)
MERGE (obiwan)-[:MASTER_OF]->(anakin)
MERGE (jedi)-[:ENEMY_OF]->(sith)
MERGE (republic)-[:ENEMY_OF]->(separatists)
MERGE (palpatine)-[:CHANCELLOR_OF {term:'32–19 BBY'}]->(republic)
MERGE (grievous)-[:COMMANDER_OF]->(separatists)
MERGE (anakin)-[:APPRENTICE_TO {secret:'true'}]->(palpatine)
MERGE (padme)-[:LOVES]->(anakin)
MERGE (anakin)-[:LOVES]->(padme)
MERGE (yoda)-[:FOUGHT]->(palpatine)
MERGE (anakin)-[:TURNED_ON]->(mace)
MERGE (palpatine)-[:MANIPULATED {tactic:'Fear of loss'}]->(anakin)
MERGE (mace)-[:CONFRONTED]->(palpatine)
MERGE (duel)-[:CHANGED {result:'Anakin becomes Vader'}]->(anakin)
MERGE (duel)-[:BURNED {injury:'Severe'}]->(anakin)
MERGE (grievous)-[:DEFEATED_BY {weapon:'Blaster'}]->(obiwan)
MERGE (dooku)-[:DEFEATED_BY {weapon:'Lightsaber'}]->(anakin)
MERGE (interceptor)-[:DEPLOYED_IN]->(coruscant)
MERGE (invisible)-[:CRASHED_ON]->(coruscant)
MERGE (yoda)-[:WARNED {about:'Palpatine'}]->(mace)
MERGE (obiwan)-[:FRIEND_OF]->(padme)

The graph represents the key characters, events, and factions from Revenge of the Sith in a visually hierarchical structure. At the center, Anakin Skywalker (Darth Vader) serves as the pivotal node, surrounded by key figures like Obi-Wan Kenobi, Palpatine (Darth Sidious), and major events such as the Duel on Mustafar and Order 66. The Jedi Order and Sith factions are placed around these central nodes, with Jedi Masters like Yoda and Mace Windu, and Sith Lords such as Count Dooku and General Grievous, extending outward. Important planets like Coruscant and Mustafar, as well as relationships like Padmé’s connection to Anakin, are also featured in the graph. Dotted relationships illustrate the influence, affiliations, and significant moments in the storyline.

2 Likes

**Love that idea @aldrinm — tracking iconic Star Wars phrases through the films is such a fun fan challenge. Even better when it’s visualized in a graph! ** There are so many lines that echo across trilogies and generations. Any other favorite quotes?

1 Like

Really cool to see SWAPI used like this — love how you transformed it into a Cypher graph!

For anyone wondering, there’s a GraphQL version of the Star Wars API out there too. I haven’t used it myself, but it’s a neat concept — wraps SWAPI data in a GraphQL schema. Repo here: GitHub - graphql/swapi-graphql: A GraphQL schema and server wrapping SWAPI.

Any thoughts or experience with it, @greenflux? Looks like you know your way around this stuff.

Anyone else experimented with the GraphQL version or tried integrating it into a graph database?

1 Like

@nawar_alwesh - Ah yes! I remember when we all though Return of the Jedi was going to be the cinematic end. Good times!

Last week, I took my youngest three kids to see Revenge of the Sith for its 20th anniversary! They've seen it before, but there’s just something magical about watching it on the big screen. It was nostalgic and special in so many ways.

Thanks for bringing it to life in graph form — love seeing this critical installment of the Star Wars saga through a new lens like this!

I hope we see a few more submissions in the next day or two — though honestly, the judges already have their work cut out for them with these entries!

Here’s a small sample from my overabundant Star Wars LEGO collection. :grinning_face_with_smiling_eyes: We built the Star Wars sign this week — such a fun build to do with two people, since the bags are separated. One person can work on “Star” while the other builds “Wars.”

1 Like

Thanks @Ari_Neo4j ! I didn't know there was a GraphQL version of the SWAPI. I'll have to give it a try. That would definitely simplify the JavaScript to map over the data and create a Cypher.

Simplify - but not as cool IMHO :slight_smile:.

Description:

This graph tells the epic saga of the Skywalker Lightsaber. The legendary relic was forged by Anakin, lost in battle, passed through generations, and finally laid to rest by Rey. The graph maps key battles, locations, and transitions of ownership that define the saber’s journey. Designed in a star pattern, it visually mirrors the lightsaber’s central role in galactic history.

Visual:

Cypher:

MERGE (anakin:Person {name:"Anakin Skywalker"})
MERGE (obiwan:Person {name:"Obi-Wan Kenobi"})
MERGE (luke:Person {name:"Luke Skywalker"})
MERGE (rey:Person {name:"Rey"})
MERGE (maz:Person {name:"Maz Kanata"})
MERGE (kylo:Person {name:"Kylo Ren"})
MERGE (smuggler:Person {name:"Smuggler's Moon Broker"})
MERGE (ugnaughts:Group {name:"Ugnaughts"})
MERGE (saber:Item {name:"Skywalker Lightsaber", color:"Blue", crystal:"Kyber Crystal"})
MERGE (tatooine:Location {name:"Tatooine"})
MERGE (bespin:Location {name:"Bespin"})
MERGE (takodana:Location {name:"Takodana"})
MERGE (mustafar:Location {name:"Mustafar"})
MERGE (temple:Location {name:"Jedi Temple"})
MERGE (clone:Event {name:"Clone Wars"})
MERGE (mustafarBattle:Event {name:"Battle of Mustafar"})
MERGE (duel:Event {name:"Cloud City Duel"})
MERGE (starkiller:Event {name:"Battle of Starkiller Base"})
MERGE (exegol:Event {name:"Battle of Exegol"})
MERGE (burial:Event {name:"Saber Burial"})
MERGE (anakin)-[:CONSTRUCTED]->(saber)
MERGE (anakin)-[:USED_DURING]->(clone)
MERGE (anakin)-[:USED_DURING]->(mustafarBattle)
MERGE (anakin)-[:LOST_TO]->(obiwan)
MERGE (obiwan)-[:RECOVERED_FROM]->(mustafar)
MERGE (obiwan)-[:GAVE_TO]->(luke)
MERGE (luke)-[:USED_DURING]->(duel)
MERGE (luke)-[:LOST_AT]->(bespin)
MERGE (ugnaughts)-[:FOUND_AT]->(bespin)
MERGE (ugnaughts)-[:GAVE_TO]->(smuggler)
MERGE (smuggler)-[:GAVE_TO]->(maz)
MERGE (maz)-[:STORED_AT]->(takodana)
MERGE (maz)-[:GAVE_TO]->(rey)
MERGE (rey)-[:FOUND_AT]->(takodana)
MERGE (rey)-[:USED_DURING]->(starkiller)
MERGE (rey)-[:USED_DURING]->(exegol)
MERGE (rey)-[:USED_AGAINST]->(kylo)
MERGE (rey)-[:PERFORMED]->(burial)
MERGE (rey)-[:BURIED_AT]->(tatooine)
MERGE (rey)-[:BROUGHT_TO]->(tatooine)
MERGE (burial)-[:TOOK_PLACE_AT]->(tatooine)
MERGE (mustafarBattle)-[:TOOK_PLACE_AT]->(mustafar)
MERGE (duel)-[:TOOK_PLACE_AT]->(bespin)
MERGE (starkiller)-[:PRECEDED]->(exegol)
MERGE (exegol)-[:TOOK_PLACE_AT]->(tatooine) // metaphorical convergence
MERGE (saber)-[:CALLED_TO]->(rey)
MERGE (saber)-[:USED_DURING]->(clone)
MERGE (saber)-[:USED_DURING]->(duel)
MERGE (saber)-[:USED_DURING]->(mustafarBattle)
MERGE (saber)-[:USED_DURING]->(starkiller)
MERGE (saber)-[:USED_DURING]->(exegol)
MERGE (saber)-[:STORED_AT]->(takodana)
MERGE (saber)-[:BURIED_AT]->(tatooine)
MERGE (luke)-[:CALLED_TO]->(rey)
MERGE (anakin)-[:STORED_AT]->(temple)
MERGE (temple)-[:ACTIVE_DURING]->(clone)
1 Like