13. Law of the instrument (of the
hammer) : cognitive bias that
involves an over-reliance on a
familiar tool.
A.Maslow 1966
14. Did Google have a graph problem back in the
early 2000s?
I’d say it was an information retrieval problem
15. nd so, my fellow graphistas: ask not
whether you have a graph problem - instead, look
at your problem with a graph thinking mindset”
J. Barrasa - Graph Connect Europe 2017
“A
16. Example 1: Credit card fraud origination and
assessment of potential impact
21. WITH { amount: 2.50, currency:"USD", txid:"05015244006",
mid:"5073047", tid:"5073440-7", timestamp:1490060618007,
cardno:"5224654370862586050" } AS newTxData
MATCH (lastTx:Transaction { cardno: newTxData.cardno })
WHERE NOT (lastTx)-[:NEXT]->()
CREATE (newTx:Transaction) SET newTx += newTxData
CREATE (lastTx)-[:NEXT]->(newTx)
WITH newTx, newTxData
MERGE (term:Terminal { tid: newTxData.tid})
CREATE (newTx)-[:IN_TERMINAL]->(term)
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Transactions
22. WITH { amount: 2.50, currency:"USD", txid:"05015244006",
mid:"5073047", tid:"5073440-7", timestamp:1490060618007,
cardno:"5224654370862586050" } AS newTxData
MATCH (lastTx:Transaction { cardno: newTxData.cardno })
WHERE NOT (lastTx)-[:NEXT]->()
CREATE (newTx:Transaction) SET newTx += newTxData
CREATE (lastTx)-[:NEXT]->(newTx)
WITH newTx, newTxData
MERGE (term:Terminal { tid: newTxData.tid})
CREATE (newTx)-[:IN_TERMINAL]->(term)
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Transactions
23. WITH { amount: 2.50, currency:"USD", txid:"05015244006",
mid:"5073047", tid:"5073440-7", timestamp:1490060618007,
cardno:"5224654370862586050" } AS newTxData
MATCH (lastTx:Transaction { cardno: newTxData.cardno })
WHERE NOT (lastTx)-[:NEXT]->()
CREATE (newTx:Transaction) SET newTx += newTxData
CREATE (lastTx)-[:NEXT]->(newTx)
WITH newTx, newTxData
MERGE (term:Terminal { tid: newTxData.tid})
CREATE (newTx)-[:IN_TERMINAL]->(term)
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Transactions
24. WITH { amount: 2.50, currency:"USD", txid:"05015244006",
mid:"5073047", tid:"5073440-7", timestamp:1490060618007,
cardno:"5224654370862586050" } AS newTxData
MATCH (lastTx:Transaction { cardno: newTxData.cardno })
WHERE NOT (lastTx)-[:NEXT]->()
CREATE (newTx:Transaction) SET newTx += newTxData
CREATE (lastTx)-[:NEXT]->(newTx)
WITH newTx, newTxData
MERGE (term:Terminal { tid: newTxData.tid})
CREATE (newTx)-[:IN_TERMINAL]->(term)
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Transactions
26. WITH { txid:"0501524400006"} AS unrecognizedTx
MATCH (tx:Transaction { txid: unrecognizedTx.txid })
SET tx:FraudTx
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Reported fraud
27. WITH { txid:"0501524400006"} AS unrecognizedTx
MATCH (tx:Transaction { txid: unrecognizedTx.txid })
SET tx:FraudTx
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Reported fraud
28. WITH { txid:"0501524400006"} AS unrecognizedTx
MATCH (tx:Transaction { txid: unrecognizedTx.txid })
SET tx:FraudTx
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Reported fraud
29. WITH { txid:"0501524400006"} AS unrecognizedTx
MATCH (tx:Transaction { txid: unrecognizedTx.txid })
SET tx:FraudTx
Tx
Tx
Tx
Tx
Fraud
Fraud
Data load: Reported fraud
31. MATCH (term:Terminal)<-[:IN_TERMINAL]-(t)-[n:NEXT*]->(:FraudTx)
WITH term , count(distinct t.cardno) as ct,
min(t.timestamp) as mindate, max(t.timestamp) as maxdate
WHERE ct > 1
MATCH (term)<-[:IN_TERMINAL]-(otherTx)
WHERE otherTx.timestamp < maxdate and otherTx.timestamp > mindate
RETURN term.tid AS terminal,mindate,maxdate,
100 * ct / COUNT(DISTINCT otherTx.cardno) AS impact,
(maxdate - mindate)/(24*3600000) as timewindow
ORDER BY impact DESC, timewindow DESC
Query: Fraud origination at terminal level
32. MATCH (term:Terminal)<-[:IN_TERMINAL]-(t)-[n:NEXT*]->(:FraudTx)
WITH term , count(distinct t.cardno) as ct,
min(t.timestamp) as mindate, max(t.timestamp) as maxdate
WHERE ct > 1
MATCH (term)<-[:IN_TERMINAL]-(otherTx)
WHERE otherTx.timestamp < maxdate and otherTx.timestamp > mindate
RETURN term.tid AS terminal,mindate,maxdate,
100 * ct / COUNT(DISTINCT otherTx.cardno) AS impact,
(maxdate - mindate)/(24*3600000) as timewindow
ORDER BY impact DESC, timewindow DESC
Query: Fraud origination at terminal level
33. MATCH (term:Terminal)<-[:IN_TERMINAL]-(t)-[n:NEXT*]->(:FraudTx)
WITH term , count(distinct t.cardno) as ct,
min(t.timestamp) as mindate, max(t.timestamp) as maxdate
WHERE ct > 1
MATCH (term)<-[:IN_TERMINAL]-(otherTx)
WHERE otherTx.timestamp < maxdate and otherTx.timestamp > mindate
RETURN term.tid AS terminal,mindate,maxdate,
100 * ct / COUNT(DISTINCT otherTx.cardno) AS impact,
(maxdate - mindate)/(24*3600000) as timewindow
ORDER BY impact DESC, timewindow DESC
Query: Fraud origination at terminal level
34. MATCH (term:Terminal)<-[:IN_TERMINAL]-(t)-[n:NEXT*]->(:FraudTx)
WITH term , count(distinct t.cardno) as ct,
min(t.timestamp) as mindate, max(t.timestamp) as maxdate
WHERE ct > 1
MATCH (term)<-[:IN_TERMINAL]-(otherTx)
WHERE otherTx.timestamp < maxdate and otherTx.timestamp > mindate
RETURN term.tid AS terminal,mindate,maxdate,
100 * ct / COUNT(DISTINCT otherTx.cardno) AS impact,
(maxdate - mindate)/(24*3600000) as timewindow
ORDER BY impact DESC, timewindow DESC
Query: Fraud origination at terminal level
36. WITH { tid : '2373743-7', from: 1487340089000, to:
1488039852000 } AS compTerm
MATCH (term:Terminal { tid: compTerm.tid} )<-[:IN_TERMINAL]-(t)
WHERE NOT (t)-[:NEXT*]->(:FraudTx)
AND t.timestamp > compTerm.from
AND t.timestamp < compTerm.to
RETURN distinct t.cardno AS cardAtRisk
Query: Proactive prevention
37. WITH { tid : '2373743-7', from: 1487340089000, to:
1488039852000 } AS compTerm
MATCH (term:Terminal { tid: compTerm.tid} )<-[:IN_TERMINAL]-(t)
WHERE NOT (t)-[:NEXT*]->(:FraudTx)
AND t.timestamp > compTerm.from
AND t.timestamp < compTerm.to
RETURN distinct t.cardno AS cardAtRisk
Query: Proactive prevention
38. WITH { tid : '2373743-7', from: 1487340089000, to:
1488039852000 } AS compTerm
MATCH (term:Terminal { tid: compTerm.tid} )<-[:IN_TERMINAL]-(t)
WHERE NOT (t)-[:NEXT*]->(:FraudTx)
AND t.timestamp > compTerm.from
AND t.timestamp < compTerm.to
RETURN distinct t.cardno AS cardAtRisk
Query: Proactive prevention
45. MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER]->(u)
WHERE t.timestamp - i.timestamp < 15*24*3600000 AND
t.amount < 210 AND t.amount > 199 AND
size((x)-[:TRANSFER]-())=1
RETURN p
46. MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER]->(u)
WHERE t.timestamp - i.timestamp < 15*24*3600000 AND
t.amount < 210 AND t.amount > 199 AND
size((x)-[:TRANSFER]-())=1
RETURN p
47. MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER]->(u)
WHERE t.timestamp - i.timestamp < 15*24*3600000 AND
t.amount < 210 AND t.amount > 199 AND
size((x)-[:TRANSFER]-())=1
RETURN p
49. Fraudsters got more and more sophisticated...
<-[:INVITES]--
--[:INVITES]->
---[:INVITES]->
-[:TRANSFER]->
-[:TRANSFER]->
<-[:TRANSFER]---
50. But cypher beat them all!
MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER*3..]->(u)
WHERE all(r IN relationships(p) WHERE type(r) <>'TRANSFER' OR
(r.timestamp - i.timestamp < 15*24*3600000 AND
r.amount < 210 AND r.amount > 199)) AND
all(n IN nodes(p) WHERE n=u or size((n)-[:TRANSFER]->())=1)
RETURN p
51. But cypher beat them all!
MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER*3..]->(u)
WHERE all(r IN relationships(p) WHERE type(r) <>'TRANSFER' OR
(r.timestamp - i.timestamp < 15*24*3600000 AND
r.amount < 210 AND r.amount > 199)) AND
all(n IN nodes(p) WHERE n=u or size((n)-[:TRANSFER]->())=1)
RETURN p
and *3.. detects chains of any length!
52. But cypher beat them all!
MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER*3..]->(u)
WHERE all(r IN relationships(p) WHERE type(r) <>'TRANSFER' OR
(r.timestamp - i.timestamp < 15*24*3600000 AND
r.amount < 210 AND r.amount > 199)) AND
all(n IN nodes(p) WHERE n=u or size((n)-[:TRANSFER]->())=1)
RETURN p
54. I could go on with more variants the pattern...
<-[:INVITES]-
--[:INVITES]->---[:INVITES]->
-[:TRANSFER]->
-[:TRANSFER]->
-[:TRANSFER]->
MATCH p = (u:User)-[i:INVITES]->(x)-[t:TRANSFER*3..]->()