11 votes

Agrégation statistique complexe de séries chronologiques impliquant des associations polymorphes

Ok. Soyez indulgent avec moi, car je dois fournir beaucoup de détails contextuels avant de pouvoir solliciter une réponse raisonnable à ma question.

J'ai un site qui vous permet de faire des choix d'actions quotidiens. Le principe est le suivant : vous êtes invité à choisir entre les entreprises qui s'affrontent pour la journée. Par exemple, GE contre IBM. Vous pouvez faire deux types de choix : Performance (quelle action sera la plus performante ?) et Volume total (les actions combinées seront-elles négociées à des volumes supérieurs ou inférieurs à X ?). Chaque jour, vous disposez de 100 dollars virtuels pour faire vos choix.

En fin de compte, notre objectif ici est de suivre quel utilisateur gagne le plus d'argent par sélection dans diverses catégories (expliquées ci-dessous) sur les périodes suivantes : 5 jours, 15 jours, 30 jours, 90 jours, 180 jours, 1 an, tout le temps. Il est très simple de calculer combien d'argent est gagné par sélection. Il s'agit de l'argent total gagné (ou perdu) / nombre de picks.

Maintenant, chaque entreprise sur laquelle l'utilisateur fait un choix relève d'une hiérarchie catégorielle. Généralement, la hiérarchie catégorielle ressemble à ceci :

Division --> Grand groupe --> Groupe industriel --> Classification --> Société

Voici quelques exemples :

  • Exploitation minière --> extraction de métaux --> minerais de fer --> extraction de minerais bruns --> Compagnie A
  • Exploitation minière --> extraction de métaux --> minerais de fer --> extraction de minerais bruns --> Compagnie B
  • Exploitation minière --> extraction de métaux --> minerais de fer --> extraction de limonite --> Compagnie C
  • Exploitation minière --> Mines de métaux --> Minerais de fer --> Exploitation de la limonite --> Entreprise D
  • Industrie manufacturière --> Produits du tabac --> Cigares --> Stogies --> Company E
  • Industrie manufacturière --> Produits du tabac --> Cigares --> Stogies --> Entreprise F
  • Industrie manufacturière --> Produits du tabac --> Cigares --> Cigarillos --> Company G
  • Industrie manufacturière --> Produits du tabac --> Cigares --> Cigarillos --> Entreprise H
  • et ainsi de suite

Il y a un modèle pour chaque catégorie (et la table correspondante, bien sûr), et ils sont associés (pensez à la clé étrangère) comme vous le voyez ci-dessus.

Il existe un modèle pour le Matchup, chaque enregistrement représentant les entreprises qui s'affrontent pour la journée. Chaque enregistrement conserve la trace du cours initial et du cours final de l'action de chaque société, ainsi que le volume total des échanges.

Chaque matchup a un ou plusieurs :pick_prices qui peuvent changer tout au long de la journée. Normalement, chaque matchup a un :pick price de performance et un :pick price de volume total. Le prix détermine ce que le choix vous coûtera et combien vous gagnez pour un choix correct. (Tout ceci n'est qu'une information générale. Vous n'avez pas besoin de vous soucier de ces calculs de prix particuliers).

À la fin de la journée de négociation, les choix de l'utilisateur sont résolus. Les choix sont représentés dans un modèle de choix, avec les attributs suivants :

  • nom d'utilisateur
  • montant_dépensé (par exemple, 10 $)
  • le résultat (par exemple, WON, LOST)
  • choisir (par exemple, l'entreprise A)
  • matchup_id
  • pick_price_id
  • montant_gagné
  • résolu (vrai ou faux)
  • créé_at
  • updated_at

Actuellement, lorsque chaque prélèvement est résolu, une autre table est mise à jour, appelée pick_records, qui possède les attributs suivants :

  • nom d'utilisateur
  • id. enregistrable
  • recordable_type (Division ou Grand Groupe ou Groupe Industriel ou Classification ou Société)
  • picks (total des picks effectués, quel que soit le type de pick)
  • gagnés (total des choix gagnés, quel que soit le type de choix)
  • perdu (total des picks perdus, quel que soit le type de pick)
  • argent (argent total gagné)
  • money_per_pick (argent / picks)
  • performance_picks
  • performance_won
  • perte de performance
  • argent_de_la_performance
  • performance_argent_par_pick
  • volume_pics
  • volume_won
  • volume_perdu
  • volume_argent
  • volume_argent_par_pick
  • créé_at
  • updated_at

Comme vous pouvez le constater, il s'agit d'un modèle polymorphe. Le tableau regroupe les statistiques des records de picking de tous les temps.

Alors maintenant, voici le défi :

Compte tenu de la conception existante, que dois-je faire pour pouvoir saisir les enregistrements de prélèvement de l'utilisateur sur les périodes suivantes : 5 jours, 15 jours, 30 jours, 90 jours, 180 jours, 1 an, tous les temps ? Il faut que ce soit simple, efficace et rapide !

J'utilise actuellement Rails 2.3.11 sur une base de données MySQL.

3voto

Johan Points 34755

Je ne vois pas l'utilité de la table pick_records.
Vous pouvez effectuer une requête de ce type pour un nombre quelconque de jours :

SELECT 
   user_id
   ,sum(amount_spent) 
   ,sum(IF(result = 'WON',1,0)) as WON_count
   ,sum(IF(result = 'LOST',1,0)) as LOST_count
   ,pick 
   /*matchup_id*/
   ,sum(pc.price) as price
   ,sum(IF(result = 'WON'),amount_won,0)) as amount_won
   ,sum(IF(result = 'LOST'),amount_won,0)) as amount_lost
   ,sum(IF(result = 'WON'),amount_won,-amount_won)) as nett_amount
FROM picks
INNER JOIN pick_price pc ON (pc.id = user.pick_price_id)
WHERE created_at BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()
  AND resolved = 'true'
GROUP BY user_id, pick

0voto

daekrist Points 858

Je ne suis pas sûr d'avoir bien compris la question, mais...

@records=Pick_record.all(:conditions => ["user_id = ?", user_id],
                         :group => "date(created_at)", 
                         :having => ["created_at > ?", 5.days.ago])

0voto

nathanvda Points 25878

Si je comprends bien, il n'y a plus qu'une seule pick_record par utilisateur, et il contient un aperçu de l'ensemble de ses choix, et est mis à jour lors de la résolution d'un choix.

Puisque le contenu de la pick_record peut être calculé, il est simplement utilisé pour la mise en cache et pour s'assurer que vous pouvez fournir les données/rapports très rapidement.

Pour résoudre votre problème, je vous propose ce qui suit :

Au lieu d'avoir un seul pick_record, sur la durée de vie totale, j'aurais un pick_record par période de temps qui vous intéresse. Ainsi, vous auriez un pick_record avec le résultat des 4 derniers jours, un autre avec le résultat des 14 derniers jours, 29 ... Ceux que vous calculez une fois par jour, de préférence la nuit (ou lorsque votre site est peu utilisé). Lorsqu'un rapport pour une période donnée doit être affiché, il suffit d'ajouter le résultat du jour en cours et le tour est joué !

Donc, pour récapituler :

  1. introduire un pick_record par période intéressante (ajouter un champ indiquant la période : 5, 15, 30, ...)
  2. pré-calculer les résultats une fois par jour (travail en arrière-plan, par exemple resque ou delayed_job)
  3. lors de la récupération des résultats de la période, il suffit d'ajouter les résultats de la journée en cours.

Qu'en pensez-vous ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X