Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/

$graphLookup을 사용한 AML 네트워크 분석

사용 사례: 싱글뷰

산업: 금융 서비스

제품: MongoDB Atlas

금융 범죄는 네트워크에서 활동합니다. 자금 세탁, 사기 조직 및 제재 회피는 셸 회사의 웹, 프록시 디렉터 및 계층화된 트랜잭션 경로에 의존합니다. 컴플라이언스 팀은 의심되는 엔티티 주변의 관계 네트워크를 매핑하고 분석 해야 합니다.

기존의 접근 방식에는 두 가지 병목 현상이 실행 .

  • 비싼 쿼리: 관계형 데이터베이스는 재귀적인 CTE(Common Table Expressions)를 사용합니다. 이러한 쿼리는 2~3개의 홉을 초과하면 비용이 많이 듭니다.

  • 지속적인네트워크 왕복: 클라이언트 사이드 그래프 처리 데이터를 애플리케이션 계층으로 가져옵니다. 클라이언트 각 홉에 대해 새 쿼리 실행합니다.

이 솔루션에서는 다음을 수행할 수 있습니다.

  • 이러한 병목 현상을 방지하려면 MongoDB 연산자를 사용하는 네트워크 분석 엔진 빌드하세요.

  • 멀티 홉 그래프 순회, 최단 경로 감지, 중심성 채점, 커뮤니티 감지 및 위험 전파를 MongoDB의 집계 프레임워크 내에서 직접 실행합니다.

이 솔루션은 네트워크 분석 엔진 과 이를 지원하는 MongoDB 연산자에 중점을 둡니다. MongoDB Atlas , FastAPI 및 Next.js를 사용하여 전체 아키텍처를 구현 하려면 이전 솔루션 라이브러리인금융 범죄 완화를 따르세요.

  • 검색 인덱스, 벡터 임베딩, 변경 스트림과 함께 MongoDB 에 엔터티 및 관계를 저장합니다.

  • 그래프 워크로드를 MongoDB 에 유지하므로 두 시스템 간의 데이터 동기화, 예비 인프라 관리, 시스템 간 지연 시간 발생을 방지할 수 있습니다.

  • MongoDB의 $graphLookup 연산자 사용하여 각 홉에서 표준 인덱싱된 쿼리로 너비 우선 검색 실행 하면 별도의 그래프 엔진 아닌 인덱스에 따라 성능이 좌우됩니다.

  • 컴플라이언스 조사에서 일반적인 1-5홉 탐색의 경우, 이 접근 방식은 애플리케이션 이 이미 읽고 쓰는 것과 동일한 데이터를 쿼리하면서 전용 그래프 데이터베이스를 일치시킵니다.

참고

컴플라이언스 조사에서는 일반적으로 주제에서 몇 가지 단계를 추적합니다. 즉각적인 거래 상대방과 첫 번째 계층 중개자는 1~2 홉 떨어져 있는 반면, 셸 구조와 자금 이동 경로는 일반적으로 3~5 홉 내에 속합니다. 그 외에도 링크의 의미가 줄어들고 설명하기가 어려워지므로 대부분의 실용적인 조사는 이 1~5홉 범위 에 유지됩니다.

네트워크 분석 엔진 FastAPI 서비스 계층과 MongoDB Atlas 사이에 위치하며 집계 파이프라인 통해 그래프 작업을 처리합니다.

Agentic 조사 파이프라인
클릭하여 확대

그림 1. Agentic 조사 파이프라인

듀얼 $graphLookup 패턴

자금 세탁 네트워크는 양방향 흐름을 수반합니다. 엔터티는 한 관계 에서 자금을 소싱하고 다른 관계에서 이를 받을 수 있습니다.

단일 $graphLookup 은 한 방향으로만 가장자리를 이동합니다. 이 솔루션은 정방향 및 역방향이라는 두 가지 병렬 조회를 실행하고 결과를 통합 네트워크 그래프 로 병합합니다.

pipeline = [
{"$match": {"entityId": center_entity_id}},
# Forward traversal: follow source → target edges
{"$graphLookup": {
"from": "relationships",
"startWith": "$entityId",
"connectFromField": "target.entityId",
"connectToField": "source.entityId",
"as": "forward_relationships",
"maxDepth": max_depth - 1,
"restrictSearchWithMatch": {
"active": True,
"confidence": {"$gte": min_confidence}
}
}},
# Reverse traversal: follow target → source edges
{"$graphLookup": {
"from": "relationships",
"startWith": "$entityId",
"connectFromField": "source.entityId",
"connectToField": "target.entityId",
"as": "reverse_relationships",
"maxDepth": max_depth - 1,
"restrictSearchWithMatch": {
"active": True,
"confidence": {"$gte": min_confidence}
}
}},
# Merge both directions
{"$project": {
"entityId": 1,
"all_relationships": {
"$concatArrays": [
"$forward_relationships",
"$reverse_relationships"
]
}
}},
{"$unwind": "$all_relationships"},
{"$replaceRoot": {"newRoot": "$all_relationships"}},
{"$limit": max_relationships}
]
이중 $graphLookup — 양방향 네트워크 검색
클릭하여 확대

그림 2. 이중 $graphLookup — 양방향 네트워크 검색

애플리케이션 한 번의 왕복으로 전체 네트워크 그래프 수신합니다. 두 탐색 모두 하나의 집계 파이프라인 에서 실행 초기 쿼리 에서 반환된 각 문서 에 대해 별도의 후속 쿼리 실행하는 N+1 쿼리 문제가 해결됩니다.

How $graphLookup 그래프 탐색

$graphLookup 불연속형 파동에서 너비 우선 검색 (BFS)을 수행합니다.

  • 시드:startWith 입력 문서 에 대해 을(를) 평가합니다. 배열 값은 동시에 프론티어를 시딩합니다(다중 루트 BFS).

  • 쿼리: 필터하다 { connectToField: { $in: [frontier_values] }} restrictSearchWithMatch 와 병합된 를 구성합니다. from 컬렉션 에 대해 표준 인덱싱된 쿼리 로 실행합니다.

  • 확장: 방문한 설정하다 에 없는 일치하는 각 문서 에 대해 결과에 추가하고 connectFromField 값을 추출하여 다음 프론티어로 푸시합니다.

  • 반복: 깊이를 증가시킵니다.2 경계가 비어 있거나 에 maxDepth 도달할 때까지 단계로 돌아갑니다.

  • 조립: 축적된 모든 문서를 as 필드 아래의 배열 에 배치합니다.

주기 감지는 자동으로 이루어집니다. 내부 방문 설정하다 자금 세탁 구조에서 일반적으로 발생하는 순환 그래프(A → B → C → A)의 무한 루프를 방지합니다. 각 문서 결과에 정확히 한 번만 표시됩니다.

restrictSearchWithMatch 이점

restrictSearchWithMatch 필터하다 기준을 사후 필터가 아닌 순회 자체에 푸시합니다. MongoDB 전체 그래프 발견하고 나중에 필터링하는 대신 순회 중에 죽은 브랜치를 정리합니다. 대규모 네트워크의 경우 작업 세트 수십 배 줄일 수 있습니다.

순회 중 필터링과 사후 필터링
클릭하여 확대

그림 3. 순회 중 필터링과 사후 필터링

이 솔루션은 entitiesrelationships의 두 컬렉션을 사용합니다. 인접 목록 패턴 따릅니다. 엣지 메타데이터 (신뢰도, 증거, 검증 상태)는 관계 문서 에서 최상위 필드로 존재합니다.

관계 스키마

{
"relationshipId": "REL_8910",
"source": {
"entityId": "ENT_123",
"entityType": "individual"
},
"target": {
"entityId": "ENT_456",
"entityType": "organization"
},
"type": "beneficial_owner_of",
"direction": "directed",
"strength": 0.85,
"confidence": 0.95,
"active": true,
"verified": true,
"evidence": [
{
"evidence_type": "corporate_registry",
"confidence": 0.95,
"source": "Companies House UK"
}
],
"datasource": "KYC_onboarding"
}
  • 중첩된 소스/대상 참조:source.entityIdtarget.entityId 구조는 $graphLookup connectFromField 의 및 connectToField 매개변수에 직접 매핑됩니다. 또한 조인 없이 에지 수준에서 엔터티 유형 메타데이터 보존합니다.

  • 분리 strength 개인정보 정책에 confidence 필드: 강도는 멀리 떨어진 비즈니스 동료와 비교하여 %의 소유권을 보유한 UBO와 같은 관계 본질적으로 얼마나 강한지를 90보여줍니다. Confidence는 두 개의 독립적인 출처에서 검증한 데이터 포인트와 공유 주소 에서 추론한 데이터 점 에 대한 신뢰를 확보합니다. 위험 전파는 두 값을 서로 다르게 사용합니다.

  • active boolean for soft-delete: AML 시스템에는 감사 추적이 active: false 필요합니다. 문서 제거하는 대신 를 설정하여 관계 삭제합니다. 이 플래그는 restrictSearchWithMatch 에서 순회 필터하다 역할도 합니다.

리포지토리 를 복제하고 GitHub README의 설정 지침을 따릅니다:

git clone https://github.com/mongodb-industry-solutions/fsi-aml-fraud-detection.git
cd fsi-aml-fraud-detection/aml-backend
poetry install
poetry run uvicorn main:app --host 0.0.0.0 --port 8001 --reload

다음 하위 섹션에서는 NetworkRepository에 구현된 6개의 핵심 그래프 작업을 안내합니다.

1
  • $graphLookup 모든 BFS 파에서 { connectToField: { $in: [frontier] } } 쿼리 실행합니다. 양방향 순회 방향에서 connectToField 을(를) 인덱싱합니다.

db.relationships.createIndex({
"source.entityId": 1,
"active": 1,
"confidence": -1
});
db.relationships.createIndex({
"target.entityId": 1,
"active": 1,
"confidence": -1
});

인덱스 이점은 1~3 홉에서 가장 강하고 깊이가 증가함에 따라 감소합니다. AML 조사에서 1-4홉 순회는 최적의 위치에 있습니다.

2
  • 참조 아키텍처에 설명된 이중 $graphLookup 파이프라인 사용하여 단일 집계 으로 완전한 양방향 네트워크를 빌드 할 수 있습니다.

  • /network/{entity_id} 엔드포인트는 구성 가능한 깊이, 신뢰 임계값 및 최대 노드 수를 사용하여 이 작업을 노출합니다.

3
  • 위험도가 낮은 고객이 승인된 엔터티에 연결하는지 확인하고 정확한 체인을 재구성합니다.

  • depthField 를 사용하여 검색된 각 관계 에 해당 홉 거리를 주석으로 추가합니다.

pipeline = [
{"$match": {"entityId": source_entity_id}},
{"$graphLookup": {
"from": "relationships",
"startWith": "$entityId",
"connectFromField": "source.entityId",
"connectToField": "target.entityId",
"as": "forward_paths",
"maxDepth": max_depth - 1,
"depthField": "depth"
}},
{"$graphLookup": {
"from": "relationships",
"startWith": "$entityId",
"connectFromField": "target.entityId",
"connectToField": "source.entityId",
"as": "reverse_paths",
"maxDepth": max_depth - 1,
"depthField": "depth"
}},
{"$project": {
"all_paths": {"$concatArrays": ["$forward_paths", "$reverse_paths"]}
}},
{"$unwind": "$all_paths"},
{"$match": {"$or": [
{"all_paths.source.entityId": target_entity_id},
{"all_paths.target.entityId": target_entity_id}
]}},
{"$sort": {"all_paths.depth": 1}},
{"$limit": 1}
]

결과는 가장 짧은 깊이를 식별합니다. 해당 깊이에서 두 번째 제한된 $graphLookup 은 전체 관계 체인을 재구성합니다.

4
  • $facet 를 사용하여 단일 파이프라인 에서 동일한 엔터티 설정하다 에 대해 위험 분산, 엔터티 유형 분석, 허브 감지, 중요도 점수 및 기본 지표 등 5개의 병렬 분석을 실행 .

stats_pipeline = [
{"$match": {"entityId": {"$in": network_entity_ids}}},
{"$addFields": {
"connection_count": {"$size": {"$ifNull": ["$connected_entities", []]}}
}},
{"$facet": {
"basic_stats": [{"$group": {
"_id": None,
"total_nodes": {"$sum": 1},
"avg_risk_score": {"$avg": "$riskAssessment.overall.score"},
"max_risk_score": {"$max": "$riskAssessment.overall.score"}
}}],
"risk_distribution": [
{"$group": {"_id": "$riskAssessment.overall.level", "count": {"$sum": 1}}},
{"$sort": {"_id": 1}}
],
"hub_entities": [
{"$match": {"connection_count": {"$gte": 2}}},
{"$sort": {"connection_count": -1}},
{"$limit": 5},
{"$project": {"entityId": 1, "name": 1, "connection_count": 1}}
]
}}
]

$facet이(가) 없으면 각 분석에는 별도의 파이프라인 필요합니다. $facet 는 모든 하위 파이프라인을 병렬로 처리하고 결과를 단일 응답으로 반환합니다. 이 작업은 2~5 밀리초 내에 실행됩니다.

5
  • 가장 의심스러운 행위자를 연결하는 엔티티를 식별합니다.

  • 중심성 파이프라인 $facet 를 사용하여 발신 및 수신 연결을 별도로 집계한 다음 병합하고 점수를 매깁니다.

  • $switch 연산자 집계 내부에서 직접 각 관계 유형에 위험 가중치를 할당합니다.

"outgoing_risk_weighted": {
"$sum": {"$multiply": [
"$confidence",
{"$switch": {
"branches": [
{"case": {"$in": ["$type", [
"confirmed_same_entity",
"business_associate_suspected"
]]}, "then": 0.9},
{"case": {"$in": ["$type", [
"director_of", "ubo_of",
"parent_of_subsidiary"
]]}, "then": 0.7},
{"case": {"$in": ["$type", [
"household_member",
"professional_colleague_public"
]]}, "then": 0.3}
],
"default": 0.5
}}
]}
}
  • confirmed_same_entity 연결은 household_member 링크보다 위험 가중치 중심성에 훨씬 더 많이 기여합니다.

  • 최종 복합 점수는 정규화된 정도 중심성(40%), 평균 신뢰 가중치(30%), 위험 가중 중심성(30%)을 혼합하며, 이 모두는 서버 측에서 계산된 것입니다.

6
  • 커뮤니티 감지는 confidence >= 0.7 에 대한 집계 필터링을 통해 인접 맵을 구축하여 신뢰도가 높은 관계 주위에만 커뮤니티 경계를 그립니다.

adjacency_pipeline = [
{"$match": {
"$or": [
{"source.entityId": {"$in": entity_ids}},
{"target.entityId": {"$in": entity_ids}}
],
"active": True,
"confidence": {"$gte": 0.7}
}},
{"$group": {
"_id": "$source.entityId",
"connections": {"$addToSet": "$target.entityId"}
}}
]
  • $addToSet 연결을 자동으로 제거 — shared_addressbusiness_associate 관계를 모두 공유 두 엔터티가 단일 연결로 표시됩니다.

위험 전파는 가 네트워크를 발견한후 관계 체인을 통해 기하급수적 감쇠를 적용합니다.$graphLookup

propagated_risk = (
parent_entity_risk
* propagation_factor # decay per hop (default: 0.5)
* relationship_confidence # trust level for this edge
* type_risk_weight # domain-specific weight
)

승인된 엔터티의 셸 회사 (높은 신뢰, 고 위험 관계 유형)는 거의 전체 위험 점수를 받습니다. 회계사의 소셜 미디어 연결은 거의 아무것도 수신하지 못합니다. 탐색은 너비 우선이며 3 홉으로 깊이가 제한되며 전파된 점수가 구성 가능한 임계값 아래로 떨어지면 중지됩니다.

  • 이중 사용 $graphLookup 양방향 네트워크 검색의 경우: 정방향 및 역방향으로 두 번의 병렬 조회를 실행하고 결과를 와 $concatArrays 병합하여 하나의 집계 으로 전체 네트워크를 캡처합니다.

  • 다음을 사용하여 필터를 순회에 푸시합니다. restrictSearchWithMatch: 나중에 전체 그래프 필터링하는 대신 BFS 중에 데드 브랜치를 정리하여 대규모 네트워크의 작업 세트 줄입니다.

  • 복합 인덱스 생성 connectToField 순회 필터: 은(는)$graphLookup $match/$in 모든 BFS 파동에서 쿼리 connectToField 실행하므로 active 을(를) 및 와(과) 함께 인덱싱 각 confidence 홉에서 컬렉션 스캔을 방지할 수 있습니다.

  • 다음을 갖춘 컴퓨팅 네트워크 분석 서버 측 $facet 개인정보 정책에 $switch: 병렬 하위 파이프라인에서 위험 분산, 허브 감지 및 중심성 점수를 실행하고 $switch 를 사용하여 집계 내의 관계 유형에 도메인별 위험 가중치를 할당합니다.

  • 위험 전파를 위한 지수 감쇠 적용: 기반 네트워크 $graphLookup검색과 관계 신뢰 및 유형이 포함된 홉별 감쇠 공식을 결합하여 모델이 위험도가 높은 구조적 연결과 위험도가 낮은 소셜 연결을 자동으로 구분합니다. 이는 주요 학습 내용을 일관적인 명령형 스타일로 유지하라는 가이드라인과 일치합니다.

  • Luis Pazmiño

  • 메하르 그루월

  • Andrea Alaman Calderon

돌아가기

오픈 금융 데이터 저장

이 페이지의 내용