适配特定出行场景的Neo4j图数据库最优模型选型咨询
Hey Steve, great question—your scenario is a perfect fit for Neo4j, and we can model it in a way that makes all your target queries straightforward. Let’s walk through the best approach step by step.
We’ll cover two model options, each optimized for slightly different query patterns. Pick the one that aligns most with how you’ll use the data day-to-day.
Option 1: Compact Relationship-Based Model (Best for Individual/Person-Centric Queries)
This model keeps things lean, with just two node types and a single relationship that carries date information:
:Personnodes: Store a uniquepersonId(e.g.,1,2,3) and optional details like a name.:Citynodes: Store a uniquecityId(e.g.,1to5) and optional city names.[:WAS_IN]relationship: Connects aPersonto aCity, with adateproperty (use Neo4j’s nativeDatetype for easy date math, e.g.,date('2024-05-20')).
Example Data Insert
// Add people CREATE (:Person {personId: 1, name: "Person 1"}), (:Person {personId: 2, name: "Person 2"}), (:Person {personId: 3, name: "Person 3"}) // Add cities CREATE (:City {cityId: 1, name: "City A"}), (:City {cityId: 2, name: "City B"}), (:City {cityId: 3, name: "City C"}), (:City {cityId: 4, name: "City D"}), (:City {cityId: 5, name: "City E"}) // Log Person 1's location on 2024-05-20 in City 2 MATCH (p:Person {personId:1}), (c:City {cityId:2}) CREATE (p)-[:WAS_IN {date: date('2024-05-20')}]->(c)
Option 2: Date Node Model (Best for Date-Range/Batch Queries)
If you often need to analyze all activity on a specific date (e.g., "where was everyone on 2024-05-20?"), add a :Date node to group all daily locations:
:Datenodes: Store a uniquedateproperty (Neo4jDatetype).- Relationships:
(Person)-[:WAS_PRESENT_ON]->(Date): Links a person to a date they have a location for.(Date)-[:LOCATED_IN]->(City): Links the date to the person’s city that day.
Let’s use the Compact Relationship-Based Model for these examples (adjustments for the Date Node Model are noted where needed).
1. Find when Person 1 was in City 2
MATCH (p:Person {personId: 1})-[r:WAS_IN]->(c:City {cityId: 2}) RETURN p.personId AS person, c.cityId AS city, r.date AS day ORDER BY r.date
For Date Node Model:
MATCH (p:Person {personId:1})-[:WAS_PRESENT_ON]->(d:Date)-[:LOCATED_IN]->(c:City {cityId:2}) RETURN p.personId, c.cityId, d.date AS day ORDER BY d.date
2. Find when Person 2 was in City 1 and traveled to City 2 (consecutive days)
Assuming this means "Person 2 was in City 1 on day X, then moved to City 2 on day X+1":
MATCH (p:Person {personId:2})-[r1:WAS_IN]->(c1:City {cityId:1}), (p)-[r2:WAS_IN]->(c2:City {cityId:2}) WHERE r2.date = date(r1.date) + duration({days: 1}) RETURN r1.date AS day_in_city_1, r2.date AS day_in_city_2 ORDER BY r1.date
If you meant "Person 2 was in City 1 and traveled to City 2 on the same day" (unlikely given your daily location rule), you’d adjust the model to include a fromCity property on the :WAS_IN relationship.
3. Find when Person 3 did not travel (stayed in the same city as the previous day)
"Not traveling" here means staying in the same city as the prior day. We’ll also include the first recorded day (since there’s no prior location to travel from):
// Days where Person 3 stayed in the same city as the day before MATCH (p:Person {personId:3})-[r1:WAS_IN]->(c:City), (p)-[r2:WAS_IN]->(c) WHERE r2.date = date(r1.date) + duration({days: 1}) RETURN r2.date AS day_no_travel UNION // First recorded day (no prior travel possible) MATCH (p:Person {personId:3})-[r:WAS_IN]->(:City) WHERE NOT EXISTS { MATCH (p)-[:WAS_IN]->(:City) WHERE date(r.date) - duration({days:1}) = date(r.date) } RETURN r.date AS day_no_travel ORDER BY day_no_travel
- Indexing: Add indexes on
Person.personId,City.cityId, andWAS_IN.date(orDate.dateif using Option 2) to speed up queries. For example:CREATE INDEX person_id_index FOR (p:Person) ON (p.personId) CREATE INDEX was_in_date_index FOR ()-[r:WAS_IN]->() ON (r.date) - Edge Cases: If a person has no location record for a day, you might want to assume they stayed in the previous city—you’d need to handle that with additional logic (like filling in missing dates with the last known location).
内容的提问来源于stack exchange,提问作者Steve

