Alerts: Alert creation example
Introduction
In this chapter, we will learn how to use alerts to identify cases of fraud. With alerts, Linkurious Enterprise can regularly return new potential cases of fraud detected in your database. Once these cases are visible in the interface, they can be assigned to the investigators of your team, they can use the tools available in Linkurious Enterprise to ensure that the fraud case is genuine.
We will cover the use case of money laundering through the purchase of real estate to illustrate how to create Linkurious Enterprise Alerts.
Money laundering through the purchase of real estate (or real estate ML) consists of hiding the origin and injecting fraudulent funds into the legal economy by making a profitable investment. There are different ways to identify real estate fraud. Here are some of them:
- A discrepancy between the usual income of the owner and the property value.
- An anonymous owner, as a result of recourse of either a company or similar arrangements.
- A property underestimated or over-evaluated.
- The indication by a country that there is a risk of money laundering by its citizen in another country.
- The location of the property (represented by location where the loan is done) is not in relation with the buyer location.
- Politically exposed persons.
- Transaction speed.
- The company or type of company owned by the buyer is suspicious.
- Shared intermediaries or common intermediaries for several mortgage loans in a specific time period.
As can be seen, there is a wide variety of different schemes for a fraud case. And a fraudster may use different schemes each time they try to launder funds in order to cover his tracks and hide his illicit activities. Linkurious Enterprise' alert system takes into account and aggregates these different schemes in order to detect and return all data related to one targeted entity.
Here we will create an alert in which we will target a person potentially guilty of laundering money through the purchase of real estate.
Defining the target of the alert
The target is the entity suspected for fraud. It is this entity that the investigator will inquiry during his investigation.
The target is left to the discretion of the alert creator but it will have to be used in each query describing a pattern in order for the system to work and for the alert to return cases.
In our example, the investigators will have to prove the responsibility of an individual in the potential fraud cases generated by the alert. This person will be our target. We will call him here "p" and we will make sure that each query will return a node of type person identified as "p".
Preprocessing data for the alert
In our example, we will be using the maximum monthly installment an individual can have as one of the element to detect fraudulent cases. Using a preprocessing step, we will calculate this amount and set it as a property on all Person
nodes in the graph.
match (p:Person)
Set p.max_monthly_instalment = toFloat(p.annual_revenues/36)
Return p
Defining the models of the alert
In our example, the first pattern we want to detect is a discrepancy between the owner's income and property value, illustrated by the monthly instalment for the loan: if one-third of the buyer's monthly income is less than the monthly cost of the loan to purchase the property, then it may be a case of money laundering.
Here is how this pattern will be translated via the Cypher language:
match (l:MortgageLoan)<-[e:HAS_LOAN]-(p:Person)
where p.max_monthly_instalment < toFloat(l.monthly_instalment)
return l,p,e
As can be seen, we have identified the buyer (an entity of type Person in the given database) by the term p – our defined target – and returned it, along with the entities necessary for the investigation: the loan and the link between the two entities.
If you want to reproduce and test our example, here are all the queries used for each pattern:
A discrepancy between the usual income of the owner and the property value.
match (l:MortgageLoan)<-[e:HAS_LOAN]-(p:Person) where p.max_monthly_instalment < toFloat(l.monthly_instalment) return l,p,e
The indication by a country that there is a risk of money laundering by its citizen in another country.
match (p:Person)-[e:HAS_LOAN]->(l:MortgageLoan) where p.nationality in ["Russia","North Korea", "China"] return l,p,e
The location of the property (represented by location where the loan is done) is far away from the buyer location.
match (l:MortgageLoan)<-[e:HAS_LOAN]-(p:Person) where point.distance(point(l),point(p))/1000 > 300 return l,p,e
The company or the type of company owned by the owner is among a list of sensitive fields.
// We distinguish two patterns here:
// - Company got the loan
match (l:MortgageLoan)<-[e:HAS_LOAN]-(c:Company)<-[:HAS_CONTROL]-(p:Person)
where c.industry in ["Military/Government/Technical","Oil/Gas Transmission"]
return l,c,p,e
// - Person got the loan
match (l:MortgageLoan)<-[e:HAS_LOAN]-(p:Person)-[:HAS_CONTROL]->(c:Company)
where c.industry in ["Military/Government/Technical","Oil/Gas Transmission"]
return l,c,p,e
Setting up the case attributes
We now want to set up some columns that will allow the investigator to quickly understand what type of scheme the fraudster is using to launder funds as well as information about the buyer:
- The name of the owner.
- His or her client id.
- His or her nationality.
- The sum of the values of all the properties for which the individual has taken out loans.
- The total number of bank loans taken out by the individual.
- The difference between the owner instalment capacity and the monthly sum of all loans taken out.
- The average loan term.
- The distance between the individual's principal residence and the location where the loan was taken out.
Let's now take a look at the query that will help us add the above attributes.
match (p:Person) where id(p) in {{"target":nodeset}}
match (l:MortgageLoan) where id(l) in {{"context":nodeset}}
with p,p.max_monthly_instalment,
sum(point.distance(point(l),point(p))) as total_distances,
collect(l) as loans,
sum(toFloat(l.monthly_instalment)) as debt_ratio,
sum(l.purchase_price) as total_properties_value,
sum(l.duration) as loans_duration,
count (l) as total_loans
with p,
loans,
total_properties_value,
total_loans,
loans_duration,
total_distances/total_loans as average_distance,
loans_duration/total_loans as average_loan_duration,
p.max_monthly_instalment - debt_ratio as available_debt_ratio
return p, total_properties_value, total_loans, average_loan_duration, average_distance, available_debt_ratio
In the first line, we want to specifically look up the entity representing our target. To do so, we use the Linkurious Enterprise query templates syntax to specify what type of entity we are looking for. We can thus use 4 different variables to target distinct elements in the data of a case:
{{"target":nodeset}}
will fetch the entities of type "node" in the alert target.{{"target":edgeset}}
will fetch the entities of type "edge" in the alert target.{{"context":nodeset}}
will fetch the entities of type "node" present in the case data.{{"context":edgeset}}
will fetch the entities of type "edge" present in the case data.
so, with these lines:
match (p:Person) where id(p) in {{"target":nodeset}}
we fetch the person node identified as our target, and return it.
In the same way, this line:
match (l:MortgageLoan) where id(l) in {{"context":nodeset}}
will return all entities of type node and category "MortgageLoan" contained in the data returned by the cases.
Navigate to the next section where we dig deeper into the different ways alerts' cases can be processed.