title: How to represent a sequence of actions in a database while keeping detailed information about each action?
body: <p>We have many actions players can take in a game. Imagine a card game (like poker) or a board game where there are multiple choices at each decision point and there is a clear sequence of events. We keep track of each action taken by a player. We care about the action's size (if applicable), other action possibilities that weren't taken, the player who took the action, the action that player faced before his move. Additionally, we need to know whether some action happened or did not happen before the action we're looking at.</p>
  
  <p>The database helps us answer questions like:<br>
  1. How often is action A taken given the opportunity? (sum(actionA)/sum(actionA_opp) <br>
  2. How often is action A taken given the opportunity and given that action B took place? <br>
  3. How often is action A taken with size X, or made within Y seconds given the opportunity and given that action B took place and action C did not? <br>
  4. How often is action A taken given that action B took place performed by player P?</p>
  
  <p>So for each action, we need to keep information about the player that took the action, size, timing, the action performed, what action opportunities were available and other characteristics. There is a finite number of actions.</p>
  
  <p>One game can have on average 6 actions with some going up to 15.<br>
  There could be million of games and we want the aggregate queries across all of them to run as fast as possible. (seconds)</p>
  
  <p>It could be represented in document database with an array of embedded documents like:</p>
  
  <pre><code>game: 123
  actions: [
      {
          player: Player1,
          action: deals,
          time: 0.69,
          deal_opp: 1
          discard_opp: 1
      },
      {
          player: Player2,
          action: discards,
          time: 1.21
          deal_opp: 0,
          discard_opp: 1,
      }
      ...
  ]
  </code></pre>
  
  <p>Or in a relational model:</p>
  
  <pre><code>game  |  player  |  seq_n  |  action  |  time  |  deal_opp  | discard_opp
  123   |  Player  |   1     |   deals  |  0.28  |     1      |     1
  </code></pre>
  
  <p>All possible designs that I come up with can't satisfy all my conditions.
  In the relational model presented, to see the previous actions taken in the same game requires N inner joins where N is previous actions we want to filter for. Given that the table would hold billions of rows, it would require several self joins on a billion row table which seems very inefficient.</p>
  
  <p>If we instead store it in a wide column table, and represent the entire sequence in one row, we have very easy aggregates (can filter what happened and did not by comparing column values, eg. sum(deal)/sum(deal_opp) where deal_opp = 1 to get frequency of deal action given the player had the opportunity to do it) but we don't know WHO took the given action which is a necessity. We cannot just append a player column next to an action to represent who took that action because an action like call or discard or could have many players in a row (in a poker game, one player raises, 1 or more players can call).</p>
  
  <p>More possibilities:</p>
  
  <ul>
  <li>Graph database (overkill given that we have at most 1 other connecting node? - basically a linked list) </li>
  <li>Closure tables (more efficient querying of previous actions)  </li>
  <li>??</li>
  </ul>