사용 사례: 싱글뷰
산업: 금융 서비스
제품: MongoDB Atlas
솔루션 개요
금융 범죄는 네트워크에서 활동합니다. 자금 세탁, 사기 조직 및 제재 회피는 셸 회사의 웹, 프록시 디렉터 및 계층화된 트랜잭션 경로에 의존합니다. 컴플라이언스 팀은 의심되는 엔티티 주변의 관계 네트워크를 매핑하고 분석 해야 합니다.
기존의 접근 방식에는 두 가지 병목 현상이 실행 .
비싼 쿼리: 관계형 데이터베이스는 재귀적인 CTE(Common Table Expressions)를 사용합니다. 이러한 쿼리는 2~3개의 홉을 초과하면 비용이 많이 듭니다.
지속적인네트워크 왕복: 클라이언트 사이드 그래프 처리 데이터를 애플리케이션 계층으로 가져옵니다. 클라이언트 각 홉에 대해 새 쿼리 실행합니다.
이 솔루션에서는 다음을 수행할 수 있습니다.
이러한 병목 현상을 방지하려면 MongoDB 연산자를 사용하는 네트워크 분석 엔진 빌드하세요.
멀티 홉 그래프 순회, 최단 경로 감지, 중심성 채점, 커뮤니티 감지 및 위험 전파를 MongoDB의 집계 프레임워크 내에서 직접 실행합니다.
이 솔루션은 네트워크 분석 엔진 과 이를 지원하는 MongoDB 연산자에 중점을 둡니다. MongoDB Atlas , FastAPI 및 Next.js를 사용하여 전체 아키텍처를 구현 하려면 이전 솔루션 라이브러리인금융 범죄 완화를 따르세요.
전용 그래프 데이터베이스 대신 MongoDB 사용해야 하는 이유
검색 인덱스, 벡터 임베딩, 변경 스트림과 함께 MongoDB 에 엔터티 및 관계를 저장합니다.
그래프 워크로드를 MongoDB 에 유지하므로 두 시스템 간의 데이터 동기화, 예비 인프라 관리, 시스템 간 지연 시간 발생을 방지할 수 있습니다.
MongoDB의
$graphLookup연산자 사용하여 각 홉에서 표준 인덱싱된 쿼리로 너비 우선 검색 실행 하면 별도의 그래프 엔진 아닌 인덱스에 따라 성능이 좌우됩니다.컴플라이언스 조사에서 일반적인 1-5홉 탐색의 경우, 이 접근 방식은 애플리케이션 이 이미 읽고 쓰는 것과 동일한 데이터를 쿼리하면서 전용 그래프 데이터베이스를 일치시킵니다.
참고
컴플라이언스 조사에서는 일반적으로 주제에서 몇 가지 단계를 추적합니다. 즉각적인 거래 상대방과 첫 번째 계층 중개자는 1~2 홉 떨어져 있는 반면, 셸 구조와 자금 이동 경로는 일반적으로 3~5 홉 내에 속합니다. 그 외에도 링크의 의미가 줄어들고 설명하기가 어려워지므로 대부분의 실용적인 조사는 이 1~5홉 범위 에 유지됩니다.
참조 아키텍처
네트워크 분석 엔진 FastAPI 서비스 계층과 MongoDB Atlas 사이에 위치하며 집계 파이프라인 통해 그래프 작업을 처리합니다.
그림 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} ]
그림 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. 순회 중 필터링과 사후 필터링
데이터 모델 접근 방식
이 솔루션은 entities 및 relationships의 두 컬렉션을 사용합니다. 인접 목록 패턴 따릅니다. 엣지 메타데이터 (신뢰도, 증거, 검증 상태)는 관계 문서 에서 최상위 필드로 존재합니다.
관계 스키마
{ "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.entityId및target.entityId구조는$graphLookupconnectFromField의 및connectToField매개변수에 직접 매핑됩니다. 또한 조인 없이 에지 수준에서 엔터티 유형 메타데이터 보존합니다.분리
strength개인정보 정책에confidence필드: 강도는 멀리 떨어진 비즈니스 동료와 비교하여 %의 소유권을 보유한 UBO와 같은 관계 본질적으로 얼마나 강한지를 90보여줍니다. Confidence는 두 개의 독립적인 출처에서 검증한 데이터 포인트와 공유 주소 에서 추론한 데이터 점 에 대한 신뢰를 확보합니다. 위험 전파는 두 값을 서로 다르게 사용합니다.activeboolean 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개의 핵심 그래프 작업을 안내합니다.
필수 인덱스 만들기
$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홉 순회는 최적의 위치에 있습니다.
최단 경로depthField 찾기()
위험도가 낮은 고객이 승인된 엔터티에 연결하는지 확인하고 정확한 체인을 재구성합니다.
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 은 전체 관계 체인을 재구성합니다.
네트워크 통계$facet 계산()
$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 밀리초 내에 실행됩니다.
점수 중심성(도메인별$switch 가중치의 경우)
가장 의심스러운 행위자를 연결하는 엔티티를 식별합니다.
중심성 파이프라인
$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%)을 혼합하며, 이 모두는 서버 측에서 계산된 것입니다.
커뮤니티 감지 및 위험 전파
커뮤니티 감지는
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_address및business_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