Reputation: 31
I need to find some values very fast based on a multi-key.
The key is composed by:
< Int userId, String measureName, Date startDate, Date endDate >
and the value is a double.
The problem is that I have to ask for the value indicating a day, and not a date range.
So if I'll ask for a userId
, a measureName
and a day, the data structure has to answer with the value where the day is between startDate
and endDate
(there are no overlap between date ranges).
I cannot understand which is the better data structure to implement this. HashMap? TreeMap? MultiKeyMap? RangeMap? Help! :)
Upvotes: 3
Views: 4725
Reputation: 20604
What about a combination of Map
and ordered List
? The map has a compound key of userId
and measureName
, the value is a sorted list of date range and double value
:
Map<Key,List<Entry>> data = new HashMap<>();
List<Entry> entries = data.get(new Key(userId, measureName));
int i = Collections.binarySearch(entries, new Entry(searchDate,searchDate, 0.0));
double value = i < 0 ? 0.0 : entries.get(i).value;
Key
has to implement hashCode()
and equals()
using its members userId
and measureName
. Entry
has to implement Comparable<Entry>
where compareTo()
has to return 0 if one range is part of the other (startDate comparison is <= 0 and endDate comparison is >= 0 or 0 if startDate comparison is >= 0 and endDate comparison is <= 0) else compare startDate+(endDate-startDate)/2 (middle of the range) regardless of the double value
.
If you mostly read and not modify this structure, it should be fast. The comparison will be compiled to native if used much. If the function works on a single user and measure only, you can use the sorted list only, if only on a single user, you may create a Map<UserId<Map<MeasureName,List<Entry>>>>
like structure instead.
Try a simple solution first, measure before and after, do performance optimizations only if needed.
Upvotes: 0
Reputation: 36349
I recommend some Map for the User/Measurement partial key. The value would be a sorted array of tuples (date range, floatval). In this array you perform binary search for a date range that contains the day.
Upvotes: 0
Reputation: 1262
I think you should use TreeMap and methods like: http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html#floorEntry(K) http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html#higherEntry(K) but use in comparison function only one date - startDate or endDate. As those ranges don't overlap this shouldn't be a problem and make mentioned methods from TreeMap usable.
For example: if you decide to use in comparison endDate
(and other fields except other dates) than you should use method floorEntry
Upvotes: 3
Reputation: 4569
TreeMap with a custom key object would be best. You'd have something like:
...
TreeMap<MyMultiKey,Double> map = ...
class MyMultiKey implements Comparable<MyMultiKey>{
...
}
Assuming MyMultiKey
's compareTo
method was implemented to order your multi-keys properly, you could create a new MyMultiKey
instance each time you wanted to search for a specific day by using map.floorKey(MyMultiKey m)
and map.higherKey(MyMultiKey m)
to make sure you found a key with a start and end time that contained the day you specified in your new key instance.
Upvotes: 0