J'ai un haschmap avec une mappage de 8 millions de points2D à une liaison linked. Tout fonctionne comme il le devrait, mais il faut très longtemps pour que je reçois des données du hashmap. Y a-t-il une alternative, que je puisse utiliser pour optimiser obtenir des données de sortie? P> Je suis prêt à compromettre le temps nécessaire à mettre () code> en faveur du temps nécessaire pour
obtenez () code>. p> p>
3 Réponses :
Tout d'abord, vérifiez la fonction de hachage de votre clé (point2D). Il devrait être bien distribué ou vous aurez beaucoup de collisions. Voir la réponse de Eugene pour une explication sur la beauté qui est le hashmap.
Deuxièmement, selon la manière dont vous souhaitez accéder aux données (par lesquels je veux dire, vous essayez d'obtenir un même objet), vous pouvez utiliser un cache, Mais ce n'est que si vous ne pouvez pas modifier le Voici mon implémentation d'un cache LRU d'un autre projet. Cela pourrait accélérer certaines choses (ce n'est pas un code merveilleux et ne peut pas cocher la coulée, mais devrait travailler dans la plupart des cas). P> hashcode code>. P>
package util;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class CachedHashMap<K, V> extends HashMap<K, V>{
private static final long serialVersionUID = 36215319740415714L;
private LRUCache<K, V> cache;
private LRUCache<K, Boolean> containsCache;
public CachedHashMap(int cacheSize){
containsCache = new LRUCache<>(2*cacheSize);
cache = new LRUCache<>(cacheSize);
}
@Override
public V put(K key, V value){
cache.put(key, value);
containsCache.put(key, true);
return super.put(key, value);
}
@Override
public boolean containsKey(Object key){
if(containsCache.containsKey(key)){
return containsCache.get(key);
}
boolean contains = super.containsKey(key);
containsCache.put((K) key, contains);
return contains;
}
@Override
public V remove(Object key){
containsCache.remove(key);
cache.remove(key);
return super.remove(key);
}
@Override
public V get(Object key){
if(containsCache.containsKey(key)){
if(!containsCache.get(key))
return null;
}
V value = cache.get(key);
if(value != null)
return value;
value = super.get(key);
K keyCast = (K) key;
if(value != null){
containsCache.put(keyCast, true);
cache.put(keyCast, value);
}else{
containsCache.put(keyCast, false);
}
return value;
}
class LRUCache<A, B> extends LinkedHashMap<A, B> {
private static final long serialVersionUID = -5958373482978477783L;
private int cacheSize;
public LRUCache(int cacheSize) {
super(16, 0.75f, true);
this.cacheSize = cacheSize;
}
protected boolean removeEldestEntry(Map.Entry<A, B> eldest) {
return size() >= cacheSize;
}
}
}
Et si vous recherchez beaucoup de points inexistants, un filtre de floraison peut également être utile.
Je peux vous dire que la différence entre les 8 millions de points sont dans les décimales. Est-ce que cela affectera le hashcode par défaut?
Le XOR ne signifie-t-il pas que si x et y sont égaux, le hashcode sera toujours 0?
Les coordonnées sont toujours 6.xxxx et -55.yyyyy. Si cela produit le même hashcode, je vois vraiment le problème.
Le haschmap mis en cache a rendu le cas moyen disparu à presque rien.
@Hedam Bien sûr, vous avez un cache maintenant. Mais tu caches toujours le vrai problème et c'est bon si tu es ok avec ça
@Hedam c'est génial. Mais Eugene a vraiment raison. Si la vitesse devient un problème à nouveau (comme si elle l'a fait dans le projet où j'ai utilisé ce cache). Les misses de cache seront toujours assez lentes. En tant que fonction de hachage, je suggère de ne pas inclure la partie exposante du double de votre hachage, car ils sont toujours les mêmes. Ensuite, au lieu de XOR, utilisez le nombre de nombres premiers standard.
Pourquoi faites-vous cette double recherche dans si (contient.Cache.containsikeykey (touche)) {retour contient contient.get (clé); } code>? Votre
contenant code> ne contient que les touches actuelles ou, en d'autres termes, mappe toujours sur
true code>, alors pourquoi pas simplement
si (contient. contient.Containskey (touche) {retour vrai; } code>? Eh bien, ou pourquoi ne pas utiliser de
définir code> en premier lieu?
@Hedam différence entre 8 millions de points est dans les décimales code>, mais plus tard, vous donnez un exemple dans lequel la précision n'est que de 4 chiffres après le point. 4 chiffres ne peuvent pas fournir 8 millions d'entrées ...
La contient contient également de faux, car lorsque la carte n'a pas la clé donnée.
@Eugene, c'était un exemple. J'utilise tous les chiffres significatifs dans le float Point2D.
La première chose est de vérifier la distribution du hashcode. D'abord vérifier cela, mais avec un changement mineur. Le code HASHCODE d'une clé code> à l'intérieur d'une carte est re-hachée interne via: Vous devez donc vraiment ré-récupérez votre hashcode avec cette fonction et que plus tard vérifiez comment Il est distribué. P> généralement sous une bonne distribution, votre recherche à l'intérieur d'un Mais c'est le temps nécessaire pour trouver un single em> Entrée sur la carte. Si vous devez en outre obtenir l'élément à partir de la liste code> code> qui signifie une heure supplémentaire (pire, puis trouvant l'entrée sur la carte) p> aussi pour tant d'entrées qu'il est essentiel de spécifier le Mais généralement à moins que vous ne mesuez et mesurez correctement, cela pourrait ne pas être le problème que vous êtes confronté. Vous pouvez regarder dans la mauvaise direction. P> P> Treenodes code> (Voici comment un godet est défini pour de nombreuses entrées) est très rapide à trouver. Pour un godet qui aurait
INTEGER.MAX_VALUE CODE> Les entrées, il faudrait au plus tort
32 code> pour le trouver. Cela se produit parce que la poubelle est transformée en un arbre noir parfaitement noir em>. P>
carte code> en général est
O (1 ) code>. Recherche d'une poubelle avec
Treenodes code> est
O (logn) code>. Et la recherche à l'intérieur d'une liaison linked est
o (n) code> - beaucoup pire que les précédents. P>
loadfactor code> et
InitialCapacité code> initialement em> (au moins initialeCapacité), avant de mettre les éléments dans la carte. Ceci est dû à la rééchage et au déménagement d'éléments pour un autre seau (potentiellement). Si vous les mettez d'abord tous em> et que d'essayer de les trouver, sans modifier la carte
code> - ce ne sera pas un problème lors de la recherche ... p>
La première chose est de vérifier est où le goulot d'étranglement réel est, par ex. en utilisant un profileur. Si je vois linkedlist code> dans la déclaration, je ne suis pas disposé à accepter la déclaration selon laquelle le problème hashmap i> est le problème, sans aucune preuve ...
Pour prouver un point, voici un test JMH code> qui recherche une entrée dans les cartes contenant des
10, 10_000 et 10_000_000 code> entrées. Vous pouvez voir em> à partir des résultats que la recherche est
constante code> - o (1). Le problème est ailleurs dans votre code. Même si vous ne comprenez pas le code, les résultats ne sont que des chiffres lisibles (voir à la fin).
Benchmark (howManyEntries) Mode Cnt Score Error Units
hashmap8Millions.EightMillionsTest.isPresent 1 avgt 5 8.787 ± 0.259 ns/op
hashmap8Millions.EightMillionsTest.isPresent 10 avgt 5 9.988 ± 0.283 ns/op
hashmap8Millions.EightMillionsTest.isPresent 256 avgt 5 9.146 ± 2.081 ns/op
hashmap8Millions.EightMillionsTest.isPresent 10000 avgt 5 8.871 ± 0.574 ns/op
hashmap8Millions.EightMillionsTest.isPresent 1000000 avgt 5 8.894 ± 0.676 ns/op
hashmap8Millions.EightMillionsTest.isPresent 10000000 avgt 5 10.884 ± 5.623 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 1 avgt 5 4.607 ± 0.175 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 10 avgt 5 4.713 ± 0.944 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 256 avgt 5 5.283 ± 0.511 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 10000 avgt 5 8.944 ± 0.144 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 1000000 avgt 5 10.256 ± 0.121 ns/op
hashmap8Millions.EightMillionsTest.mightBePresent 10000000 avgt 5 8.764 ± 0.504 ns/op
La vérification des collisions est toujours un bon point de départ lorsque votre hashmap est lente. La différence entre un
HASHCode (CODE> HASHCODE () Code> peut être énorme.
Probablement pas utile, mais je vais passer à une base de données. :)
Ceci ici Peut-être utile i> être utile: JavaSpecialists.eu/archive/issue235.html
Regarder les choses dans un
hashmap code> devrait être rapide. Raisons possibles:
point2d code> peut ne pas avoir de bon
méthode code> HashCode de sorte que vous obtenez des collisions de hasch ou non la recherche de carte est lente, mais quelque chose d'autre, comme traversant un long
LinkedList code>.
Vous pouvez envisager d'utiliser une structure de données spécifiquement conçue pour les recherches spatiales. Par exemple, si vos "clés" sont corrigées, vous pouvez utiliser un arbre K-D ou similaire.
La base de données n'est pas possible pour le moment. Tous les points du hashmap sont très proches (dans les décimales) - cela pourrait-il causer beaucoup de collisions?
Quelle est la recherche réelle que vous faites ici? Vous recherchez des points exacts ou faites-vous des recherches les plus proches?
Recherches réelles. J'ai des points et je veux trouver les bords liés aux points pour une recherche A *.
Dans un *, un cache LRU devrait aider
Je ne voudrais pas blâmer le
hashmap code> en premier lieu. Voir Quand utiliser LinkedList Over ArrayList? ...
Je pense que cela ne pourrait pas changer de problème pour l'arrayliste, car nous y sortons tous.
@Hedam
ArrayList code> est plus rapide pour itérer que A
LinkedList code>.
Que diriez-vous d'utiliser un cache, comme Ehcache? ehcache.org/documentation/2.7/get-started/introduction.html < / a>
Peut-être qu'une structure de type arborescente serait utile aussi.
S'il vous plaît montrer
point2d.hashscode code> implémentation
@FEDERICOPERALTASCAffner Implémentation par défaut