2013-03-12 2 views
2

Je dois trouver quelques valeurs très rapide basé sur un multi-clé. La clé est composée de: < Int userId, String measureName, Date startDate, Date endDate > et la valeur est un double.HashMap avec des plages de dates

Le problème est que je dois demander la valeur indiquant un jour, et non une plage de dates. Donc, si je demande un userId, un measureName et un jour, la structure de données doit répondre avec la valeur où le jour est entre startDate et endDate (il n'y a pas de chevauchement entre les plages de dates).

Je ne peux pas comprendre quelle est la meilleure structure de données pour implémenter ceci. HashMap? TreeMap? MultiKeyMap? RangeMap? Aidez-moi! :)

+2

Combien d'entrées êtes-vous susceptible d'avoir pour chaque combinaison utilisateur/mesure? –

+0

Si vous pensez à smart metering/timeseries pas d'entre eux. Trouver une autre solution Semblable aux timeseries –

+0

pas trop, disons 100, le problème est que cela demande beaucoup de temps. (80k fois pour une fonction appelée assez souvent) – user2088834

Répondre

2

Je pense que vous devriez utiliser TreeMap et des méthodes telles que: 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) mais utiliser en fonction de comparaison une seule date - startDate ou endDate. Comme ces plages ne se chevauchent pas, cela ne devrait pas poser de problème et rendre les méthodes mentionnées de TreeMap utilisables.

Par exemple, si vous décidez d'utiliser en comparaison endDate (et d'autres domaines, à l'exception d'autres dates) que vous devez utiliser la méthode floorEntry

+0

Bien qu'il n'y ait pas de chevauchement, il peut y avoir des dates qui ne sont pas dans une plage de dates de début/fin ... – matts

+0

... Mais vous ne devriez avoir qu'à comparer la fin une fois. – jahroy

+0

@jahroy Oh, je vois; J'ai mal compris et j'ai pensé que la suggestion était d'utiliser les dates directement comme clé de la carte. – matts

0

TreeMap avec un objet clé personnalisé serait le mieux. Vous auriez quelque chose comme:

... 
TreeMap<MyMultiKey,Double> map = ... 

class MyMultiKey implements Comparable<MyMultiKey>{ 
... 
} 

En supposant la méthode de compareToMyMultiKey a été mis en œuvre pour commander vos clés multi-correctement, vous pouvez créer une nouvelle MyMultiKey exemple chaque fois que vous vouliez rechercher un jour spécifique en utilisant map.floorKey(MyMultiKey m) et map.higherKey(MyMultiKey m) pour vous assurer que vous avez trouvé une clé avec une heure de début et de fin qui contenait le jour que vous avez spécifié dans votre nouvelle instance de clé.

0

Je recommande une carte pour la clé partielle utilisateur/mesure. La valeur serait un tableau trié de tuples (plage de dates, floatval). Dans ce tableau, vous effectuez une recherche binaire pour une plage de dates contenant le jour.

0

Qu'en est-il d'une combinaison de Map et de List? La carte a une clé composée de userId et measureName, la valeur est une gamme liste de date triée et 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 doit mettre en œuvre hashCode() et equals() utilisant ses membres userId et measureName. Entry doit Comparable<Entry>compareTo() doit retourner 0 si une plage fait partie de l'autre (comparaison startDate est < = 0 et la comparaison endDate est> = 0 ou 0 si la comparaison startDate est> = 0 et la comparaison endDate est < = 0) Sinon, comparez startDate + (endDate-startDate)/2 (milieu de la plage) quel que soit le double value.

Si vous lisez et ne modifiez pas cette structure, elle devrait être rapide. La comparaison sera compilée en natif si elle est utilisée beaucoup. Si la fonction fonctionne sur un seul utilisateur et mesure uniquement, vous pouvez uniquement utiliser la liste triée, si seulement sur un seul utilisateur, vous pouvez créer une structure similaire à Map<UserId<Map<MeasureName,List<Entry>>>>.

Essayez d'abord une solution simple, mesurez avant et après, effectuez les optimisations de performance seulement si nécessaire.

Questions connexes