【Neo4j】Fraud Detection實作
Neo4j Sandbox
看一下圖架構
CALL db.schema.visualization()
看label的數量
看關聯的數量
了解數據
Module #1: First-party Fraud
Synthetic identity fraud and first party fraud can be identified by performing entity link analysis to detect identities linked to other identities via shared PII.
There are three types of personally identifiable information (PII) in this dataset – SSN, Email and Phone Number
Our hypothesis is that clients who share identifiers are suspicious and have a higher potential to commit fraud. However, all shared identifier links are not suspicious, for example, two people sharing an email address. Hence, we compute a fraud score based on shared PII relationships and label the top X percentile clients as fraudsters.
We will first identify clients that share identifiers and create a new relationship between clients that share identifiers
Fraud detection workflow in Neo4j GDS
We will construct a workflow with graph algorithms to detect fraud rings, score clients based on the number of common connections and rank them to select the top few suspicious clients and label them as fraudsters.
- Identify clusters of clients sharing PII using a community detection algorithm (Weakly Connected Components)
- Find similar clients within the clusters using pairwise similarity algorithms (Node Similarity)
- Calculate and assign fraud score to clients using centrality algorithms (Degree Centrality) and
- Use computed fraud scores to label clients as potential fraudsters
創建投影圖
使用Native Projection
CALL gds.graph.project('wcc',// 投影圖的名稱
// 投影客戶節點
{
Client: {
label: 'Client'
}
},
{
SHARED_IDENTIFIERS:{
type: 'SHARED_IDENTIFIERS', // 邊
orientation: 'UNDIRECTED', // 無向
// 加入屬性至投影圖節點
properties: {
count: {
property: 'count'
}
}
}
}
) YIELD graphName,nodeCount,relationshipCount,projectMillis;
call gds.graph.drop(‘wcc’) 移除內存圖
Memory Estimation and Graph Projection
It is a good practice to run memory estimates before creating your graph to make sure you have enough memory to create an in-memory graph. For more information, click here: Memory Estimation
Named graphs can be created using either a Native projection or a Cypher projection. Native projections provide the best performance by reading from the Neo4j store files. Using Cypher projections is a more flexible and expressive approach with diminished focus on performance compared to the native projections. For more information, click here: Native and Cypher Projection
找到同社區的
CALL gds.wcc.stream('wcc',
{
nodeLabels: ['Client'],
relationshipTypes: ['SHARED_IDENTIFIERS'],
consecutiveIds: true
}
)
YIELD componentId, nodeId
WITH componentId AS cluster, gds.util.asNode(nodeId) AS client
WITH cluster, collect(client.id) AS clients
WITH cluster, clients, size(clients) AS clusterSize WHERE clusterSize > 1
UNWIND clients AS client
MATCH (c:Client) WHERE c.id = client
SET c.firstPartyFraudGroup=cluster;
超過9個人共享信息
// 找到所有客戶,使用Cypher寫入
MATCH(c:Client) WHERE c.firstPartyFraudGroup is not NULL
WITH collect(c) as clients
MATCH(n) WHERE n:Email OR n:Phone OR n:SSN
WITH clients, collect(n) as identifiers
WITH clients + identifiers as nodes
// 客戶指向email phone ssn,
MATCH(c:Client) -[:HAS_EMAIL|:HAS_PHONE|:HAS_SSN]->(id)
WHERE c.firstPartyFraudGroup is not NULL
WITH nodes, collect({source: c, target: id}) as relationships
// 使用cyhper運行我投影的內存圖(4類節點)
CALL gds.graph.project.cypher('similarity',
"UNWIND $nodes as n RETURN id(n) AS id,labels(n) AS labels",
"UNWIND $relationships as r RETURN id(r['source']) AS source, id(r['target']) AS target, 'HAS_IDENTIFIER' as type",
{ parameters: {nodes: nodes, relationships: relationships}}
)
YIELD graphName, nodeCount, relationshipCount, projectMillis
RETURN graphName, nodeCount, relationshipCount, projectMillis
欺詐客戶跟交易人員
MATCH (c1:FirstPartyFraudster)-[]->(t:Transaction)-[]->(c2:Client)
WHERE NOT c2:FirstPartyFraudster
WITH c1, c2, sum(t.amount) AS totalAmount
SET c2:SecondPartyFraudSuspect
CREATE (c1)-[:TRANSFER_TO {amount:totalAmount}]->(c2);
MATCH (c1:FirstPartyFraudster)<-[]-(t:Transaction)<-[]-(c2:Client)
WHERE NOT c2:FirstPartyFraudster
WITH c1, c2, sum(t.amount) AS totalAmount
SET c2:SecondPartyFraudSuspect
CREATE (c1)<-[:TRANSFER_TO {amount:totalAmount}]-(c2);
Second-party Fraud
Our objective is to find out clients who may have supported the first party fraudsters and were not identified as potential first party fraudsters.
Our hypothesis is that clients who perform transactions of type Transfer where they either send or receive money from first party fraudsters are flagged as suspects for second party fraud.
To identify such clients, make use of TRANSFER_TO relationships and use this recipe:
- Use WCC (community detection) to identify networks of clients who are connected to first party fraudsters
- Use PageRank (centrality) to score clients based on their influence in terms of the amount of money transferred to/from fraudsters
- Assign risk score (
secondPartyFraudScore) to these clients
CALL gds.wcc.stream('SecondPartyFraudNetwork')
YIELD nodeId, componentId
WITH gds.util.asNode(nodeId) AS client, componentId AS clusterId
WITH clusterId, collect(client.id) AS cluster
WITH clusterId, size(cluster) AS clusterSize, cluster
WHERE clusterSize > 1
UNWIND cluster AS client
MATCH(c:Client {id:client})
SET c.secondPartyFraudGroup=clusterId;
CALL gds.pageRank.stream('SecondPartyFraudNetwork',
{relationshipWeightProperty:'amount'}
)YIELD nodeId, score
WITH gds.util.asNode(nodeId) AS client, score AS pageRankScore
WHERE client.secondPartyFraudGroup IS NOT NULL
AND pageRankScore > 0 AND NOT client:FirstPartyFraudster
MATCH(c:Client {id:client.id})
SET c:SecondPartyFraud
SET c.secondPartyFraudScore = pageRankScore;
drop 內存圖
End of Module #2
In this module we accomplished the following tasks:
- Identified clusters of clients and first-party fraudsters transferring money between them
- Calculated second-party fraud score and identified second-party fraudsters
Unresolved directive in fraud-detection.adoc – include::scripts-end.txt[]

