X

Oracle Big Data Spatial and Graph - technical tips, best practices, and news from the product team

Identifying Potential Fraud Activities in Finance

Alan Wu
Architect

There are many forms of fraud activities in pretty much every
single aspect of our social life. In this blog post, I am going to
discuss one specific financial fraud that is based on circular
payment scheme. In such a scheme, a notable pattern is that there
is a clear, circular payment (or purchase) relationship that
chains together a set of individuals or financial institutions.
Using a simple example,  user A made a payment to user B, user B
made a payment to user C, and user C made a payment back to user
A. Granted that not every single circular payment is a true fraud
case. Circular payments, nevertheless, deserve a scrutiny.

Starting from v1.2.0, Oracle Big Data Spatial and Graph (BDSG) property graph has support for PGQL, a declarative, SQL-like query language for querying property graph data. It has clean and intuitive syntax. See [1] for the language specification.  PGQL, together with the scalable graph database and powerful graph analytics, can be used to detect circular payment in a graph.  An end-to-end flow is shown next. As usual, Big Data Lite VM is used and BDL 4.5 has BDSG v1.2.0 pre-installed. No vertex or edge property is used for simplicity. It is straightforward, however, to add a name property to vertices, and a weight property to edges.

// Start Groovy for BDSG against Oracle NoSQL Database (Apache HBase can also be used).
//
cd /opt/oracle/oracle-spatial-graph/property_graph/dal/groovy/
sh gremlin-opg-nosql.sh

server = new ArrayList<String>();
server.add("bigdatalite:5000");


// We start with creating an empty graph
named "loop"
in Oracle NoSQL Database

cfg = GraphConfigBuilder.forPropertyGraphNosql()
.setName("loop").setStoreName("kvstore") .setHosts(server)
.hasEdgeLabel(true).setLoadEdgeLabel(true).addEdgeProperty("weight",
PropertyType.DOUBLE, "1000000")
.setMaxNumConnections(2).addVertexProperty("name",
PropertyType.STRING, "empty name").build();


opg = OraclePropertyGraph.getInstance(cfg);
opg.clearRepository();


// Add a cycle of 2 edges to the "loop" graph

//
a21=opg.addVertex(21l);
a22=opg.addVertex(22l);
e1=opg.addEdge(2122, a21,a22, 'paid');
e2=opg.addEdge(2221, a22,a21, 'paid');
opg.commit()


// Add a
cycle of 3 edges to
the "loop" graph


//
a31=opg.addVertex(31l);
a32=opg.addVertex(32l);
a33=opg.addVertex(33l);
opg.addEdge(3132, a31,a32, 'paid');
opg.addEdge(3233, a32,a33, 'paid');
opg.addEdge(3331, a33,a31, 'paid');
opg.commit()


// Add a cycle of 4 edges to
the "loop" graph


//
a41=opg.addVertex(41l);
a42=opg.addVertex(42l);
a43=opg.addVertex(43l);
a44=opg.addVertex(44l);
opg.addEdge(4142, a41,a42, 'paid');
opg.addEdge(4243, a42,a43, 'paid');
opg.addEdge(4344, a43,a44, 'paid');
opg.addEdge(4341, a44,a41, 'paid');
opg.commit()


// Add a cycle of 5 edges
to the "loop" graph


//
a51=opg.addVertex(51l);
a52=opg.addVertex(52l);
a53=opg.addVertex(53l);
a54=opg.addVertex(54l);
a55=opg.addVertex(55l);
opg.addEdge(5152, a51,a52, 'paid');
opg.addEdge(5253, a52,a53, 'paid');
opg.addEdge(5354, a53,a54, 'paid');
opg.addEdge(5455, a54,a55, 'paid');
opg.addEdge(5551, a55,a51, 'paid');
opg.commit()


// Now, read the graph into the in-memory
analyst


//
session=Pgx.createSession("session_ID_1");
analyst=session.createAnalyst();
pgxGraph =
session.readGraphWithProperties(opg.getConfig(), true);



// Execute a query to find a
cycle with 2 hops
// An in-equality constraint is added to avoid finding a
smaller ci
rcle

//
pgxResultSet = pgxGraph.queryPgql("SELECT n,m WHERE
(n)->(m)->(n), n!=m")

pgxResultSet.print(10);
pgxResultSet.getNumResults()


// Execute a query to find a
cycle with 3 hops
// In-equality constraints are added to avoid finding a
smaller ci
rcle

//

pgxResultSet = pgxGraph.queryPgql("SELECT n,m,o WHERE
(n)->(m)->(o)->(n), n!=m,n!=o,m!=o")

pgxResultSet.print(10);
pgxResultSet.getNumResults()


// Execute a query to find a
cycle with 4 hops
// In-equality constraints are added to avoid finding a
smaller ci
rcle

//


pgxResultSet = pgxGraph.queryPgql("SELECT n,m,o,p WHERE
(n)->(m)->(o)->(p)->(n),
n!=m,n!=o,n!=p,m!=o,m!=p,o!=p")

pgxResultSet.print(10);
pgxResultSet.getNumResults()


// Execute a query to find a
cycle with 5 hops
// In-equality constraints are added to avoid finding a
smaller ci
rcle

//
pgxResultSet = pgxGraph.queryPgql("SELECT n,m,o,p,q WHERE
(n)->(m)->(o)->(p)->(q)->(n),
n!=m,n!=o,n!=p,n!=q,m!=o,m!=p,m!=q,o!=p,o!=q,p!=q")

pgxResultSet.print(10);
pgxResultSet.getNumResults()


An example output of the last command is as follows:


------------------------------------------------------------------------------------------------
| n                | m                | o               
| p                | q                |

================================================================================================
| PgxVertex[ID=53] | PgxVertex[ID=54] | PgxVertex[ID=55]
| PgxVertex[ID=51] | PgxVertex[ID=52] |

| PgxVertex[ID=52] | PgxVertex[ID=53] | PgxVertex[ID=54]
| PgxVertex[ID=55] | PgxVertex[ID=51] |

| PgxVertex[ID=51] | PgxVertex[ID=52] | PgxVertex[ID=53]
| PgxVertex[ID=54] | PgxVertex[ID=55] |

| PgxVertex[ID=55] | PgxVertex[ID=51] | PgxVertex[ID=52]
| PgxVertex[ID=53] | PgxVertex[ID=54] |

| PgxVertex[ID=54] | PgxVertex[ID=55] | PgxVertex[ID=51]
| PgxVertex[ID=52] | PgxVertex[ID=53] |

------------------------------------------------------------------------------------------------
==>null
opg-nosql> pgxResultSet.getNumResults()
==>5

You may wonder how one would detect circles without knowing
the size of a circle? For that, we have a built-in API to detect
strongly connected components (SCC). One can easily find circles
in each SCC and it is guaranteed that there is zero circles across
SCC's.  Details on that are in an upcoming blog post.


Stay tuned.

Acknowledgement: thanks Jay Banerjee and Oskar van Rest  for their input on this blog post.

[1] PGQL 0.9 Specification: https://docs.oracle.com/cd/E56133_01/1.2.0/PGQL_Specification.pdf


Join the discussion

Comments ( 1 )
  • giovanni corcione Monday, August 29, 2016

    Thanks for such useful use case!


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.