그래프 데이터베이스 기본 개념
그래프 데이터베이스 기본 개념
그래프 데이터베이스를 처음 마주하면 "노드"와 "관계"라는 말이 낯설 수 있어요. 이 페이지는 Neo4j가 쓰는 property graph 모델의 핵심 뼈대, 즉 노드·라벨·관계·프로퍼티·경로가 각각 무엇이고 어떻게 얽히는지를 하나씩 풀어 드릴게요. 이 개념만 잡아두면 뒤에 나오는 Cypher 쿼리도 훨씬 자연스럽게 읽힐 거예요.
그래프 데이터 구조
Neo4j는 데이터를 표 대신 그래프로 저장해요. 그래프는 서로 다른 노드(discrete object) 여러 개와, 그 노드들을 잇는 관계로 구성되지요. property graph 모델이 지키는 규칙을 정리하면 이렇게 돼요.
- 노드는 도메인의 개체(객체) 하나를 나타내요.
- 노드는 라벨을 0개 이상 가질 수 있고, 이 라벨로 노드가 무엇인지 분류해요.
- 관계는 출발 노드(source) 와 도착 노드(target) 를 연결해요.
- 관계는 항상 방향이 하나뿐이에요.
- 관계는 타입(type) 을 반드시 하나 가져야 해요.
- 노드와 관계 모두 프로퍼티(key-value 쌍) 로 자기만의 특징을 담아요.
수학의 그래프 이론에서 노드는 vertex 또는 point, 관계는 edge·link·line 이라고도 불러요.
예시 그래프를 Cypher의 CREATE 절로 만들면 이렇게 생겼어요.
CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})-[:ACTED_IN {roles: ['Forrest']}]->(:Movie {title: 'Forrest Gump', released: 1994})<-[:DIRECTED]-(:Person {name: 'Robert Zemeckis', born: 1951})
노드
노드는 도메인의 개체 하나를 나타내는 단위예요. 가장 단순한 그래프는 관계가 하나도 없는 노드 하나뿐이죠. 예를 들어 라벨 Person·Actor, 프로퍼티 name: 'Tom Hanks', born: 1956을 가진 노드를 만들려면 이렇게 해요.
CREATE (:Person:Actor {name: 'Tom Hanks', born: 1956})
노드 라벨
라벨은 같은 종류의 노드끼리 그룹으로 묶어 도메인에 형태를 부여해요. 예를 들어 모든 사용자 노드에 User 라벨을 붙여 두면 "이름이 OO인 사용자" 같은 연산을 그 그룹 안에서만 수행할 수 있죠. 라벨은 실행 중에 추가·제거도 가능해서, 계좌의 Suspended(정지됨), 농산물의 Seasonal(제철) 같은 일시적 상태를 표시하는 데도 써요. 노드는 라벨을 0개부터 여러 개까지 가질 수 있어요.
관계
관계는 출발 노드와 도착 노드가 어떻게 연결되어 있는지를 나타내요. 노드가 자기 자신과 관계를 맺는 것도 가능해요. 관계의 특징은 이렇죠.
- 출발 노드와 도착 노드를 연결해요.
- 방향을 하나만 가져요.
- 관계의 종류를 정하는 타입을 반드시 하나 가져요.
- 상황을 더 자세히 설명하는 프로퍼티를 가질 수 있어요.
관계는 노드들을 구조로 엮어서, 그래프가 리스트·트리·맵·복합 개체처럼 보이게 만들고 그런 구조들이 다시 겹쳐 더 복잡하고 연결이 풍부한 형태를 이룰 수 있게 해요.
관계의 타입이 ACTED_IN이고 프로퍼티로 roles: ['Forrest'], performance: 5를 가진 관계는 이렇게 만들 수 있어요.
CREATE ()-[:ACTED_IN {roles: ['Forrest'], performance: 5}]->()
관계를 만들려면 먼저 출발·도착 노드를 만들거나 참조해야 한다는 점을 잊지 마세요. 관계는 항상 방향을 가지지만, 방향이 유용하지 않으면 무시하고 볼 수도 있어요. 그래서 데이터 모델상 꼭 필요하지 않다면 반대 방향으로 중복 관계를 만들 필요는 없어요.
프로퍼티
프로퍼티는 노드와 관계에 데이터를 저장하는 key-value 쌍이에요. 값에는 number·string·boolean 같은 여러 데이터 타입을 넣을 수 있고, 같은 타입의 목록(배열)도 담을 수 있어요.
CREATE (:Example {a: 1, b: 3.14})
CREATE (:Example {c: 'This is an example string', d: true, e: false})
CREATE (:Example {f: [1, 2, 3], g: [2.71, 3.14], h: ['abc', 'example'], i: [true, true, false]})
탐색과 경로
탐색(traversal) 은 "내 친구들이 좋아하는 음악 중에 내가 아직 안 가진 건?", "이 전원이 꺼지면 어떤 웹 서비스가 영향받지?" 같은 질문에 답하기 위해 그래프를 조회하는 방식이에요. 그래프를 탐색한다는 건 어떤 규칙에 따라 관계를 따라가며 노드를 방문하는 것이고, 보통 그래프의 일부만 방문하게 돼요.
Tom Hanks가 출연한 영화를 찾는다면, Tom Hanks 노드에서 출발해 그 노드에 연결된 ACTED_IN 관계를 따라가 Forrest Gump 영화 노드에 도달하면 돼요. 이 탐색 결과는 길이 1의 경로로 돌려받을 수 있어요. 가장 짧은 경로는 길이가 0이고, 노드 하나만 담고 있죠. 관계가 하나면 길이 1이 돼요.
스키마·인덱스·제약
Neo4j에서 스키마란 인덱스와 제약을 가리켜요. Neo4j는 흔히 schema optional 이라고 불리는데, 미리 스키마를 정의하지 않아도 노드·관계·프로퍼티 데이터를 만들 수 있기 때문이에요. 성능이나 모델링 이점이 필요한 시점에 인덱스와 제약을 도입하면 돼요.
- 인덱스는 성능 향상을 위해 사용해요.
- 제약(constraint) 은 데이터가 도메인 규칙을 지키도록 강제해요.
네이밍 규칙
노드 라벨·관계 타입·프로퍼티 키는 모두 대소문자를 구분해요. 예를 들어 프로퍼티 name과 Name은 서로 다른 것이죠. 추천되는 명명 규칙은 이래요.
| 그래프 요소 | 권장 스타일 | 예시 |
|---|---|---|
| 노드 라벨 | PascalCase | :VehicleOwner (이 아니라 :vehicle_owner) |
| 관계 타입 | Screaming snake case | :OWNS_VEHICLE (이 아니라 :ownsVehicle) |
| 프로퍼티 | camelCase | firstName (이 아니라 first_name) |