Overview
I think you can solve your problem in a relatively simple 3-step process:
Given two (consecutive) snapshots of the state of your entities, determine the changes between them.
Repeat this step until all (available) snapshots are processed and store the changes somewhere.
Query the stored changes for something that is of interest to you.
Finding the Changes
I would most likely create a hash table for the first snapshot. There are a few options here:
Use the Id
to map to a data structure that holds your entity's values
Use an (Id, AttributeName)
tuple as the key to map to the values directly. Depending on your language, this might only make sense if all values are of the same type.
Do the same as above, but use one hash table for each type of attribute.
Now you turn the second snapshot into a hash table and compare it to the first. When you've found and stored all changes, you discard the first hash table (but keep the second one) and repeat this procedure with snapshots two and three - and so on...
Storing the Changes
Each change you find can be represented by a tuple such as (Time, EntityId, AttributeName, OldValue, NewValue)
. Depending on what you'd like to query, you may not need all of these fields.
Once you've found a change, the question becomes where to store them. A database seems like the ideal solution. If you have enough memory and don't want to persist the changes, you can use an in-memory DB.
The database will provide all the features to make querying easy and efficient. In particular, you'll have an established query-language and can create the relevant indices.
Added and Removed Entities
If the set of monitored entities remains constant, you can find all differences by simply iterating over one hash table's keys and comparing the key's values in both tables.
However, when entities may be added and removed, it may be helpful to deal with each case (added, changed, removed) separately.
Added entities can be easily found while building the new hash table. Simply check whether the entity already existed in the old one.
Removed entities can be found together with changed entities while iterating over the entities in the old table.
Alternatively, you can of course use the intersect/complement operations on your key-sets.