Algorithme pour déterminer les transactions parmi les séries de données hebdomadaires?


9

J'essaie de développer un petit outil de reporting (avec backend sqlite). Je peux le mieux décrire cet outil comme un grand livre de "transactions". Ce que j'essaie de faire, c'est de garder une trace des «transactions» de l'extrait de données hebdomadaire:

  • "nouveau" (ou ajouter) - la ressource est nouvelle pour mon application car mon application n'a peut-être pas suivi cette ressource auparavant car elle n'a pas été vue via des extraits.
  • "mise à jour" (ou hit) - il y a eu une utilisation récente de cette ressource, mise à jour de la période de rétention d'une semaine.
  • "supprimer" (ou supprimer) - cet élément n'a vu aucune utilité depuis le dernier rapport (facultatif, mais il serait bien d'avoir pour représenter graphiquement les changements d'une semaine à l'autre de la demande de ressources).

Tout ce que j'ai, c'est un extrait de données hebdomadaire (fichier plat délimité par des tuyaux) provenant d'un ancien système d'archivage / gestion des enregistrements sur lequel je n'ai aucun contrôle.

Chaque ligne peut être distillée à la base:
resource_id | resource info | customer_id | customer_info

Exemples de données:

10| Title X       | 1 | Bob
11| Another title | 1 | Bob
10| Title X       | 2 | Alice

L'objectif est de faciliter la génération de rapports sur les ressources qui n'ont pas été utilisées pendant X mois (en fonction du dernier hit). Il y a une période de rétention où les ressources sont conservées pour en faciliter l'accès si elles sont populaires. Une ressource qui n'a pas été utilisée depuis 18 mois est marquée pour un archivage à long terme ailleurs.

Ce doit être un problème courant. Vous vous demandez s'il existe un algorithme à usage général pour déterminer ce qui est nouveau / identique / supprimé entre les ensembles de données (db vs dernier extrait)?

Réponses:


1

Eh bien, votre réponse est ... Oui. Il existe un algorithme simple que vous pouvez implémenter qui ne nécessite aucun de ces autres éléments. C'est un algorithme de valeur actuelle nette. Il est facile à implémenter et tout ce qu'il faut du côté de la base de données, c'est que vous datiez les données hebdomadaires et écriviez une simple requête et une petite fonction récursive ou pour la boucle, ou vous pourriez faire l'une de ces autres solutions.

NPV = PV- (PV (CP / T) ou la nouvelle valeur actuelle est égale à la valeur actuelle multipliée par la période en cours (mois depuis la dernière entrée) divisée par le terme (par exemple 18 mois) lorsque la valeur de la ressource tombe à 0, c'est sa valeur actuelle nette est dépensé.

Si vous me donnez une langue dans laquelle vous le voulez, je posterai le code ici dans une édition


La langue n'est pas si importante. Ruby ou C ++ si je devais choisir. Si vous pouvez écrire un algorithme en HTML 4.0 Strict, vous serez mon héros. Je plaisante sur cette dernière partie :)
Swartz

Serait intéressé de voir le code. Ruby ou C ++. Je vous remercie.
Swartz du

0

Si vous conservez de toute façon les mises à jour dans un backend SQLite, vous pouvez transformer la mise à jour hebdomadaire en une nouvelle table et la comparer aux données archivées avec des requêtes, avant de la fusionner.

Exemple d'utilisation de SQL pour rechercher de nouveaux ajouts à une table: /programming/2077807/sql-query-to-return-differences-between-two-tables

Si un champ de votre base de données stocke la date de la transaction, vous pouvez simplement interroger tous les utilisateurs qui ont effectué des transactions au cours des 18 derniers mois. L'archive n'est alors que la base de données complète. Alternativement, vous pouvez interroger tous les utilisateurs qui ne l'ont pas fait, extraire leurs données, puis les supprimer. Les mises à jour correspondent à toutes les lignes horodatées cette semaine.


Mieux, c'est une solution centrée sur les données au moins, mais c'est toujours exagéré
J-Boss

J'utilise un sqlite pour le moment car il est facile de commencer. Pourrait facilement passer à MySQL (ou PostgreSQL). Si l'utilisation d'un backend sans SQL permettrait de rendre le travail encore meilleur, je suis à l'écoute.
Swartz

Eh bien, ma pensée était surtout que vous convertir en lignes dans une base de données de toute façon . Si vous n'avez pas besoin de l'exécuter à partir de plusieurs processus simultanément, je ne pense pas que vous souhaitiez passer à quelque chose de plus lourd que SQLite.
Davislor

Pas besoin de traitement simultané. Mais je dois stocker les données sur les ressources quelque part. Une base de données SQL semblait être un bon choix, cependant, rien ne m'empêche de charger des données dans un type de données pour le traitement des deltas. Tout ce que je veux à la fin de chaque exécution d'extrait est de comprendre ce qui est nouveau, ce qui est resté le même et ce qui a disparu. Je peux comprendre comment mettre à jour les enregistrements si nécessaire à partir de ces informations.
Swartz

Après avoir analysé les données et les avoir placées dans la base de données, il est probablement plus simple d'écrire une requête que d'implémenter un algorithme. Cela dit, si vous voulez le coder, l'algorithme que vous voulez définir la différence et il y a une implémentation dans la STL C ++ que vous pouvez utiliser pour le faire sur une seule ligne une fois que vous avez mis les deux ensembles de données dans le conteneur de votre choix, probablement un Vector.
Davislor

0

Idée alternative:

  1. Analysez votre liste de transactions dans une sorte de structure de données, comme un tableau. (En C ++, pensez Vector, et en Java,. ArrayList)

  2. Effectuer une requête sur votre backend SQL telles que SELECT DISTINCT customer_id FROM Transactions ORDER BY customer_idet emballez les ID client triés distincts en un ensemble, old. Si vous faites exactement la même chose avec une WHEREclause séparant les anciennes et les nouvelles transactions, vous pouvez ignorer l'étape 3.

  3. Obtenez les ID client uniques des nouvelles mises à jour dans une structure de données distincte, dans l'ordre trié. Il y a deux structures de données que vous pouvez utiliser pour obtenir est dans une structure de données, new. Le tri par insertion dans une liste à double liaison est très simple, mais l'utilisation d'une table de hachage intermédiaire s'exécuterait en un temps presque linéaire, ou si vous triez le tableau d'origine de toute façon, il est facile d'en obtenir un ensemble.

  4. Faites la différence new- en oldutilisant la bibliothèque standard de votre langue préférée. Votre langue préférée a cet algorithme dans sa bibliothèque standard?

Les autres choses que vous voulez faire sont définitivement des requêtes SQL après avoir mis à jour votre base de données de transactions.

Remarque à l'étape 3: tenez compte de la nature de vos données. Supposons que votre fichier texte répertorie les commandes par ordre chronologique, et au cours d'une semaine typique, il y a beaucoup de nouveaux clients qui reçoivent un nouveau customer_idpar ordre croissant. Supposons que la plupart des autres commandes proviennent d'un petit nombre de clients fidèles fidèles, avec moins customer_id. Ensuite, vos entrées sont déjà principalement triées. Dans ce cas, un tri par insertion où vous essayez d'insérer bas customer_idau customer_iddébut d'une liste à double lien et haut à l'arrière fonctionnerait bien dans la pratique.


1
Je suis plus intéressé par les ressources nouvelles / identiques / mises à jour plutôt que par les clients. Mais oui, l'idée serait la même.
Swartz

0

Si je comprends bien de votre question, vous avez réellement resource_id (+ info) et "list" de client (id + info).

Ainsi, vous pouvez facilement conserver la liste des clients par ressource et vérifier le dernier nœud de chaque liste de la ressource (afin de connaître l'heure de la dernière opération; il vous suffit d'ajouter un champ de date à votre client dans le code)

Je ne suis pas familier avec SQL, donc je donne mon exemple avec HashMapet List mais je suis sûr que c'est la même idée:, HashMap <Resource, List<Customer>>quand Resourcedevrait contenir resourceID comme clé et Customerdevrait contenir l'ID client, les informations et la date d'opération.

Avec cette idée, vous pouvez facilement connaître la dernière heure de fonctionnement et modifier n'importe quelle ressource (ajouter \ supprimer une ressource \ client).


0

Si vous utilisez une base de données SqLite, si vous ajoutez également la date du lot en tant que colonne du tableau,

10| Title X       | 1 | Bob    | 2015-03-01
11| Another title | 1 | Bob    | 2015-03-01
...............................
10| Title X       | 1 | Alice  | 2015-03-05

il serait assez facile d'utiliser un SQL pour obtenir les ressources non utilisées au cours des X derniers jours

Select distinct r.ResourceID from Resources r
where not exists (SELECT julianday('now') - julianday(r.DateUpdated)) < X

Je n'ai pas testé le SQL mais ça devrait vous donner une idée


0

D'après le message d'origine, il semble que les données en cours d'ingestion n'ont pas de champ pour indiquer la date / heure de la transaction, et je suppose que le fichier est ingéré fréquemment selon un calendrier tel que quotidien, horaire, etc.

Je gérerais cela en ajoutant une colonne d'horodatage SQL qui est soit générée automatiquement au niveau de la base de données, soit par le code qui extrait les données et les insère dans la base de données. Ensuite, vous mettez un index sur cette colonne d'horodatage et vous en avez terminé. Laissez le moteur DB faire le travail pour le rendre efficace pour répondre à la question "combien de transactions ne se sont pas produites depuis cette époque", ou "combien entre cette heure et cette heure".

Ensuite, vous planifiez un travail pour interroger et calculer les écarts sur lesquels vous souhaitez générer un rapport. Les transactions qui sont "nouvelles" sont des transactions qui n'ont aucun enregistrement dans la base de données avant la date à laquelle vous demandez "nouveau depuis". Les anciens enregistrements sont ceux qui n'ont effectué aucune transaction depuis une date limite.


-2

N'est-ce pas à cela que servent les HashTables? Si tout ce que vous voulez faire est de garder une trace des ressources qui ont été utilisées au cours des derniers mois et de supprimer les ressources qui n'ont pas été consultées au cours des 18 derniers mois, vous pouvez utiliser un HashTable où la clé est le resource_id et la valeur est le dernière date d'accès.

Pour archiver les enregistrements> 18 mois, vous pouvez parcourir tous les enregistrements de la table de hachage et simplement supprimer (ou déplacer) ces enregistrements spécifiques. (vous pouvez le faire chaque semaine lorsque le rapport arrive)


Pourquoi la nécessité de HashTable si je stocke des choses dans la base de données? Je peux faire des mises à jour des enregistrements db. Je suis plus intéressé par un cas: prenez deux ensembles de données, découvrez les différences (ce qui est ajouté, reste le même, supprimé) entre les deux ensembles. Comment une technique HashTable aiderait-elle à trouver des enregistrements nouveaux et «supprimés»?
Swartz

Si les tables sont indexées dans la base de données, elles sont également des HashTables en arrière-plan. Si vous avez 2 tables, chacune représentant un ensemble de données, vous pouvez obtenir vos enregistrements nouveaux et supprimés en effectuant des jointures externes. Voir ceci pour référence: i.stack.imgur.com/pxUO3.png . Assurez-vous d'avoir des index sur la colonne resource_id et cela devrait être assez rapide. Si vous deviez l'implémenter à partir de zéro, je pense que HashTables serait toujours le chemin à parcourir, car vous pouvez faire la recherche / l'insertion / la suppression dans le temps amorti O (1). Je ne peux pas penser à un moyen plus efficace de le faire.
Adrian Buzea

3
Il existe de meilleures structures de données qui gèrent le vieillissement sans les étapes supplémentaires de l'encombrement dans une table de hachage.

Voulez-vous en mentionner?
Adrian Buzea

@Snowman - J'aurais aimé pouvoir augmenter cela encore quelques fois, je serai tout à fait d'accord avec ce commentaire
J-Boss
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.