Neo4j를 사용하다 보면 종종 의존성 네트워크 모음을 다루게 되죠. 예를 들어, 회사 소유 구조나 어떤 회사가 다른 회사와 거래하는지 같은 데이터를 다룬다고 가정해 볼게요.
일반적으로 기업들은 전체 고객 기반에 걸쳐 엄청난 양의 데이터를 가지고 있어요. 하지만 특정 거래 파트너만 집중적으로 보고 싶을 때는 전체 네트워크가 필요하지 않죠. 이럴 땐 특정 하위 그래프만 "확대"해서 해당 거래 파트너에게 영향을 받는 부분만 확인하면 돼요.
이걸 좀 더 쉽게 이해하기 위해 간단한 예제 그래프 그림부터 시작해 볼까요? 아래는 소유권 구조를 나타낸 그림이에요.
- A사
- A 자회사
- B사
- B 자회사
그리고 그래프에서 볼 수 있듯이, 이 회사들은 모두 서로 거래하고 있답니다.
(직접 따라 해보고 싶다면 Neo4j Browser를 사용해보세요. 이 그래프를 생성하는 코드는 다음과 같아요):
CREATE (a:Company { name: 'A' })
CREATE (b:Company { name: 'B' })
CREATE (aSubsidiary:Company { name: 'A Subsidiary' })
CREATE (bSubsidiary:Company { name: 'B Subsidiary' })
CREATE (tiny:Company { name: 'Tiny Corp' })
CREATE (a)-[:OWNS]->(aSubsidiary)
CREATE (b)-[:OWNS]->(bSubsidiary)
CREATE (aSubsidiary)-[:OWNS]->(tiny)
CREATE (a)-[:TRADES_WITH { value: 1000 }]->(bSubsidiary)
CREATE (tiny)-[:TRADES_WITH { value: 10 }]->(b)
CREATE (tiny)-[:TRADES_WITH { value: 11 }]->(bSubsidiary)
CREATE (b)-[:TRADES_WITH { value: 5000 }]->(a)
CREATE (b)-[:TRADES_WITH { value: 7000 }]->(bSubsidiary);
수백만 개의 Node와 수천만 개의 Relationship으로 이루어진 데이터베이스에서 이 작은 그림은 정말 작은 부분에 불과해요.
여기서 우리가 하고 싶은 건 "A" 회사와 그 자회사들을 분석하는 것이기 때문에, 이 부분을 우리가 집중해야 할 관심 영역이라고 생각해 봅시다.
출발점
우리가 원하는 건 "A"를 중심으로 하는 분석용 하위 그래프에요.
간단한 Cypher 쿼리 하나로 이 그래프의 간단한 버전을 만들 수 있다는 걸 알고 계셨나요? 예를 들어, 네트워크를 통해 최대 3홉(hop)까지 연결된 모든 관련 경로를 찾는 거죠.
MATCH path=(startingPoint:Company { name: "A" })-[:OWNS|TRADES_WITH*..3]-(other:Company)
RETURN path;
첫 번째 기본 접근 방식에서는 Node, Label, 그리고 속성 자체를 변경해서 알고 싶은 내용을 식별할 수 있어요. 한번 계산해 볼까요?
- 특정 회사의 총 순거래량
- A에서 해당 회사까지의 거리
이런 정보들을 안다면, A 회사의 전체 그림에서 각 회사가 얼마나 중요한지 알 수 있겠죠.
이렇게 할 수 있어요:
/* Calculate the distance from A to trading members, and tag them all with a "scenario" */
WITH 'My Analysis of A Corp' as SCENARIO
MATCH p=shortestPath((startingPoint:Company { name: "A" })-[:OWNS|TRADES_WITH*..3]-(other:Company))
WHERE id(other) <> id(startingPoint)
SET
startingPoint.distanceFromA = 0,
startingPoint.scenario = SCENARIO,
other.distanceFromA = length(p),
other.scenario = SCENARIO;
/* Calculate the total trade volume for everyone in the scenario */
WITH 'My Analysis of A Corp' as SCENARIO
MATCH (c:Company { scenario: SCENARIO })
OPTIONAL MATCH (c)-[r:TRADES_WITH]-(other:Company)
WITH c, sum(r.value) as totalTradeVolume
SET c.totalTradeVolume = totalTradeVolume;
이런 간단한 속성들을 계산하면 이제 시나리오의 많은 "그래프 측면"이 포함된 깔끔한 표 형식 뷰를 얻을 수 있어요. 마치 테이블처럼요!
MATCH (c:Company { scenario: "My Analysis of A Corp" })
RETURN c.name as name, c.totalTradeVolume as tradeVolume, c.distanceFromA as distanceFromA
ORDER BY tradeVolume DESC;
분석 오버레이
이전 접근 방식은 꽤 괜찮죠? 그리고 이러한 속성을 그래프에 일반 속성으로 넣었기 때문에, BI Connector 같은 다른 도구를 사용해서 시각화하고 다른 기술과 함께 작업할 수도 있어요.
하지만 단순한 접근 방식에는 몇 가지 문제점이 있답니다.
- 속성이 "충돌"하지 않고는 여러 시나리오를 동시에 실행할 수 없어요.
- 여러 가지 다른 분석이 서로 덮어쓰는 걸 원하지 않죠.
- 기본 그래프를 수정하고 싶지도 않아요. 왜냐하면 해당 정보를 다른 사용자에게 노출하게 되니까요. 사용자가 특정 회사 데이터를 볼 수 있도록 허용하는 보안 요구 사항이 있을 수 있지만, 분석에 대한 모든 것을 보여주고 싶진 않을 수 있잖아요.
해결책은 "하위 그래프"라는 개념을 분리해서 그 자체로 새로운 Node로 만드는 거예요. 그러면 우리는 그걸 Overlay Node로 연결해서 그래프의 나머지 부분에 연결할 수 있어요. 이렇게 하면 분석 시나리오에 포함된 내용을 항상 알 수 있죠.
이렇게 하는 거예요:
이걸 계산하는 Cypher 쿼리는 좀 더 복잡해요. 왜냐하면 무역 가치와 거리 계산, 그리고 Overlay Node 생성, 이 모든 걸 한 번에 해야 하거든요.
WITH 'My Analysis of A Corp' as SCENARIO
MATCH (startingPoint:Company { name: "A" })
OPTIONAL MATCH (startingPoint)-[spTrades:TRADES_WITH]-(:Company)
WITH startingPoint, sum(spTrades.value) as spTradeValue, SCENARIO
CREATE (overlay:Overlay {
scenario: SCENARIO,
created: datetime(),
analyst: "John"
})
WITH overlay, startingPoint, spTradeValue
MATCH p=shortestPath((startingPoint)-[:OWNS|TRADES_WITH*..3]-(other:Company))
WHERE id(other) <> id(startingPoint)
OPTIONAL MATCH (other)-[otherTrades:TRADES_WITH]-(:Company)
WITH overlay, startingPoint, other, p, spTradeValue, sum(otherTrades.value) as otherTradeValue
MERGE (overlay)-[:CONTAINS {
focusOfAnalysis: true,
distance: 0,
tradeValue: spTradeValue
}]-> (startingPoint)
MERGE (overlay)-[:CONTAINS {
focusOfAnalysis: false,
distance: length(p),
tradeValue: otherTradeValue
}]-> (other);
오버레이 접근 방식의 장점
- 기본 그래프를 수정할 필요가 없어요.
분석을 방해하지 않고 자유롭게 데이터를 가져오거나 내보낼 수 있고 기본 회사 그래프를 변경할 수 있다는 의미죠. - 분석에 대한 메타데이터를 표현할 수 있어요.
참고로Overlaynode에는 생성 날짜와 해당 작업에 관심 있는 analyst가 포함돼요. 각 overlay는 고유한Subgraph ID를 얻을 수 있고, "John이 일주일 이내에 수행한 TinyCorp 관련 분석을 보여줘."와 같은 더 복잡한 query를 날릴 수도 있죠. - 하나의 relationship만 traverse해서 전체 subgraph를 쉽게 통합할 수 있어요.
바로 이Overlay CONTAINSrelationship 덕분이죠. 그래프 거리를 미리 계산해 뒀기 때문에 Cypher traverse를 반복해서 수행할 필요가 없답니다.
BI 커넥터로 가져가기
자, 이제 Overlay node에 초점을 맞춘 간단한 schema를 갖게 됐으니, Tableau에서 간단한 join을 정의하고 다음과 같이 만든 다양한 overlay에 대한 데이터를 가져올 수 있어요.
이건 실제로 "시작점" 섹션의 간단한 표 형식 보기에서 본 것과 동일한 데이터를 보고 있는 거예요. 차이점은 이제 실시간으로 그래프에 다양한 분석을 동적으로 추가할 수 있고 Tableau가 항상 업데이트를 캐치한다는 거죠.
물론 여기까지 오면 데이터 위에 표준 BI 시각화를 구축할 수 있어요.
예를 들어, A로부터의 거리와 relationship의 총 거래 가치를 결합하는 차트를 작성할 수 있죠. 이런 관점에서 보면 B와 “B 자회사”는 총 거래액이 꽤 크고 A의 “직접 이웃”임을 알 수 있어요.
Neo4j BI 커넥터에 대한 자세한 정보는 에서 확인해 보세요.
결론
많은 그래프 사용 사례에서, 관심 있는 하위 그래프에 대한 전문적인 분석을 수행해야 할 때가 많죠. 예를 들어:
- 거래 네트워크 내 기업 간의 종속성
- IT 인프라의 소프트웨어, 네트워크 및 서버
- 금융 사기 네트워크의 상호 관련된 계정
- 소매 시나리오의 주요 고객
이 글에서 설명된 기술은 방대한 데이터 속에서 필요한 정보를 찾아내고, 특정 데이터에 대한 맞춤 분석을 수행하는 데 도움이 될 수 있어요.
이것은 "스키마 유연성" 그래프 데이터 모델링과 Neo4j의 관계 중심 접근 방식이 제공하는 또 다른 이점이라고 할 수 있죠. 이러한 기술이 여러분의 문제 해결에 도움이 되었으면 좋겠네요!
에이치시스템즈의 LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.
'Neo4j' 카테고리의 다른 글
| Neo4j로 FinCEN 파일 분석하기 (0) | 2026.09.08 |
|---|---|
| Neo4j 사용자 정의 함수로 복잡한 네트워크 분석하기 (0) | 2026.09.08 |
| 아마존이 당신의 밥그릇을 빼앗고 있나요? 데이터 기반 리테일러를 위한 생존 전략 [커뮤니티 게시글] (0) | 2026.09.07 |
| 거의 다 왔다! Neo4j 1.9-RC1 출시 임박! (0) | 2026.09.07 |
| Neo4j와 Azure Machine Learning으로 AI, 한 단계 더 똑똑하게 (0) | 2026.09.07 |
