def load_movies_to_neo4j(movies_df: pd.DataFrame, connection: GraphDatabase) -> None: """Load movie data into Neo4j with progress tracking and error handling.""" logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # Query templates MOVIE_QUERY = """ MERGE (movie:Movie {title: $title}) SET movie.year = $year, movie.origin = $origin, movie.genre = $genre, movie.plot = $plot """ DIRECTOR_QUERY = """ MATCH (movie:Movie {title: $title}) MERGE (director:Director {name: $name}) MERGE (director)-[:DIRECTED]->(movie) """ ACTOR_QUERY = """ MATCH (movie:Movie {title: $title}) MERGE (actor:Actor {name: $name}) MERGE (actor)-[:ACTED_IN]->(movie) """ # Process each movie for _, row in tqdm(movies_df.iterrows(), total=len(movies_df), desc="Loading movies"): try: # Prepare movie parameters movie_params = { "title": clean_text(row["Title"]), "year": parse_number(row["Release Year"], int), "origin": clean_text(row["Origin/Ethnicity"]), "genre": clean_text(row["Genre"]), "plot": str(row["Plot"]).strip() } # Create movie node connection.execute_query(MOVIE_QUERY, parameters=movie_params) # Process directors for director in str(row["Director"]).split(" and "): director_params = { "name": clean_text(director), "title": movie_params["title"] } connection.execute_query(DIRECTOR_QUERY, parameters=director_params) # Process cast if pd.notna(row["Cast"]): for actor in row["Cast"].split(","): actor_params = { "name": clean_text(actor), "title": movie_params["title"] } connection.execute_query(ACTOR_QUERY, parameters=actor_params) except Exception as e: logger.error(f"Error loading {row['Title']}: {str(e)}") continue logger.info("Finished loading movies to Neo4j")