Bonjour.

Il y a quelques années, notre équipe (conformité dans une banque suisse) a été confrontée à une tâche très intéressante: il était nécessaire de générer un grand graphique des transactions entre les clients, les entreprises et les distributeurs automatiques de billets, d'ajouter à ce graphique des schémas similaires au blanchiment d'argent et d'autres schémas d'activités criminelles, et également d'ajouter un minimum informations sur les nœuds de ce graphique - noms, adresses, heure, etc. Bien sûr, toutes les données devaient être générées à partir de zéro, sans utiliser les données client existantes.
Pour résoudre ce problème, un générateur a été écrit, que je voudrais partager avec vous. Sous la coupe, vous trouverez une histoire expliquant pourquoi nous en avions besoin, et une description du fonctionnement du générateur. Pour les impatients - voici le code . Je serais ravi que quelqu'un profite de notre expérience.
Pourquoi faisons-nous un tel non-sens?
Notre équipe a décidé de participer en tant que sponsors au hackathon LauzHack
. L'une des conditions de participation au format sponsor était la fourniture d'une véritable tâche commerciale aux participants. Juste à ce moment-là, nous avions un projet très intéressant lié à l'automatisation de la recherche de délits financiers et de blanchiment d'argent parmi les transactions de nos clients, et sans hésitation, nous avons décidé d'offrir la même tâche aux participants du hackathon.
Pour des raisons évidentes, nous ne pouvions pas utiliser de données réelles, nous avons donc dû les créer. Pour rendre la tâche aussi proche que possible de la réalité, nous avons examiné les statistiques des données réelles et essayé, comme nous le pouvions, de rapprocher les données générées des distributions réelles, et nous n'avons pas non plus lésiné sur la quantité et la complexité des données - nous n'avions pas besoin d'une solution fonctionnant sur un graphique de 100 nœuds. et 200 connexions, nous recherchions une solution capable de traiter des graphiques de la taille de millions de nœuds et de milliards de connexions, et en tenant compte de toutes les informations disponibles sur les nœuds et les connexions.
Qu'avons-nous obtenu
Et nous avons obtenu un générateur assez rapide (ajusté en fonction de la quantité de données), intéressant et configurable! Comprenons en détail
Types de données
Nous voulons avoir un graphique des transactions financières, respectivement, les participants possibles à ce graphique sont:
- Client - vous pouvez dire un compte d'un client abstrait d'une banque. Il est décrit par nom, adresse e-mail, âge, travail, opinions politiques, nationalité, éducation et adresse de résidence
- Une entreprise est une entité commerciale du système financier. Elle est déterminée par le type d'entreprise, le nom et le pays.
- ATM - en gros, les points de sortie de l'argent du graphique que nous contrôlons. Défini par les coordonnées géographiques.
- Transaction - Le fait de transférer de l'argent d'un nœud du graphique à un autre. Défini par le nœud de début et de fin, le montant, la devise et l'heure.
Pour créer ces données, nous utilisons Mimesis , une excellente bibliothèque pour créer de fausses données.
Création d'un graphe: entités de base
Vous devez d'abord créer toutes les entités de base - clients, entreprises et distributeurs automatiques de billets. Le script prend le nombre de clients que vous souhaitez créer et, sur cette base, calcule le nombre d'entreprises et de distributeurs automatiques de billets. Selon nos données, le nombre d'entreprises ayant un grand nombre de transactions avec les clients représente environ 2,5% du nombre de clients, et le nombre de distributeurs automatiques de billets est de 0,05% du nombre de clients. Ces valeurs sont très généralisées et non configurables (câblées dans le code générateur).
Toutes les informations sont enregistrées dans des fichiers .csv. L'écriture dans ces fichiers se produit par lots, k lignes à la fois. Cette valeur est configurée par des arguments de script. De plus, trois types de nœuds sont générés en parallèle.
Création d'un graphe: connexions entre entités
Après avoir créé les entités de base, nous commençons à les connecter ensemble. À ce stade, nous ne générons pas encore les transactions elles-mêmes, mais simplement le fait qu'il existe une connexion entre les nœuds. Cela a été fait pour accélérer le processus de génération du graphe entier et fonctionne approximativement comme suit: si deux nœuds sont connectés, alors nous générons un certain nombre de transactions entre eux, dispersées dans le temps. S'ils ne sont pas connectés, mais les transactions entre ces nœuds n'existent pas.
La probabilité d'une connexion entre les deux nœuds est configurée via des arguments, les valeurs standard sont répertoriées ci-dessous.
Types de connexion possibles:
- Client -> Client (p = 0,4%)
- Client -> Entreprise (p = 1%)
- Client -> ATM (p = 3%)
- Entreprise -> Client (p = 0,5%)
Comme les nœuds, tous les types de connexions sont générés en parallèle et écrits dans leurs fichiers par lots.
Création de graphiques: transactions
Ayant les nœuds du graphique et les connexions entre eux tombant sous la distribution souhaitée, nous pouvons commencer à générer des transactions. Le processus est assez simple en soi, mais sa mise en parallèle est assez difficile. Par conséquent, à ce stade, il n'y a que deux flux indépendants - les transactions en provenance du client et les transactions en provenance de l'entreprise.
Rien de particulièrement intéressant ne se produit à ce stade: le script parcourt la liste des connexions et génère un nombre aléatoire de transactions pour chaque connexion. Il est écrit de la même manière - dans des fichiers .csv par des packages.
Count Creations: Patterns
Et ici, il y a des points intéressants. Les types de modèles de comportement que nous voulions obtenir dans la dernière colonne:
- Flux - une grande quantité va d'un nœud à m à l'autre, chacun de ces m nœuds transfère de l'argent au niveau suivant de n nœuds, et ainsi de suite, jusqu'à ce que le dernier niveau envoie tout l'argent à un destinataire.
- Circulaire - la somme d'argent va dans un cercle et retourne à la source.
- Temps - une certaine somme d'argent va d'un nœud à un autre avec une fréquence fixe.
Examinons chacun de ces modèles plus en détail:
Débit
Pour commencer, le nombre de niveaux à travers lesquels l'argent devra passer est sélectionné. Dans notre implémentation, ce nombre aléatoire entre 2 et 6 n'est pas configurable et est câblé dans le code. Ensuite, deux nœuds du graphique sont sélectionnés - l'expéditeur et le destinataire. Un montant aléatoire est également sélectionné, que l'expéditeur enverra au destinataire (selon la formule intelligente 50000 * random() + 50000 * random()
).
Chaque membre de ce réseau prend une sorte de frais pour leurs services. Dans notre implémentation, le prix maximum pour passer de l'argent via le réseau sera de 10% du montant transféré par l'expéditeur.
Les transactions générées ont un décalage temporel des transactions relatives du niveau de réseau précédent - c'est-à-dire que l'argent arrive d'abord au niveau n-1, et ensuite seulement au niveau n. Les retards sont choisis au hasard dans les 4 à 5 jours. De plus, les transactions générées ont des montants pseudo-aléatoires (limités par le montant initial et tenant compte des frais pour chaque nœud)
Circulaire
Il est généré selon un principe similaire à Flow, mais au lieu d'émetteur et de récepteur différents et de plusieurs niveaux dans ce modèle, l'argent va dans un cercle et retourne au nœud d'origine. Tous les nœuds intermédiaires facturent des frais, comme c'est le cas avec Flow, et les transactions ont également un décalage temporel.
Le temps
Le motif le plus simple. Un certain montant est envoyé de l'expéditeur au destinataire un nombre aléatoire de fois (de 5 à 50, non configurable) avec des décalages temporels pseudo-aléatoires.
Toutes les nouvelles transactions sont écrites de la même manière dans des fichiers .csv par lots.
Représentation aléatoire des graphiques et collecte de toutes les transactions dans un seul fichier
A ce stade, nous avons plusieurs fichiers .csv:
- 3 fichiers avec nœuds (clients, entreprises et distributeurs automatiques de billets)
- 4 fichiers de transactions: un pour les transactions régulières et 3 contenant des modèles.
Un script supplémentaire mélange les transactions de modèle avec les transactions régulières de sorte qu'il n'est pas possible de voir les modèles dans un graphique dans l'ordre dans lequel les transactions sont enregistrées dans un fichier.
Et que faire de tout ça?
Au final, nous avons 4 beaux fichiers avec des nœuds de graphe et des transactions entre eux. Vous pouvez importer dans Neo4J, vous pouvez distribuer via REST, mais tout ce que votre cœur désire, vous pouvez en faire.
Quant à nous, nous avons reçu un retour très positif des participants au hackathon, et quelques solutions très intéressantes pour trouver des motifs dans des graphiques massifs.