/ / Les robots d'analyse simultanés stockent-ils généralement les URL visitées dans une mappe simultanée ou utilisent-ils la synchronisation pour éviter d'analyser deux fois les mêmes pages? - java, python, multithreading, concurrence, web-crawler

Les robots d’analyse Web simultanés stockent-ils généralement les URL visitées dans une mappe simultanée ou utilisent-ils la synchronisation pour éviter d’explorer deux fois les mêmes pages? - java, python, multithreading, concurrence, web-crawler

Je joue à écrire un simplerobot d'indexation multithread. Je vois que beaucoup de sources parlent des robots Web comme étant évidemment parallèles, car vous pouvez commencer à explorer à partir d’URL différentes, mais je ne les vois jamais discuter de la façon dont les robots Web gèrent les URL qu’ils ont déjà vues auparavant. Il est essentiel d’éviter de repasser les mêmes pages à plusieurs reprises, mais comment structurer la section critique? Dans quelle mesure les verrous peuvent-ils être fins pour optimiser les performances? Je souhaite simplement voir un bon exemple qui n’est ni trop dense ni trop trop simpliste.

Réponses:

1 pour la réponse № 1

Si vous insistez pour le faire en utilisant uniquement le framework java concurrency, le ConcurrentHashMap peut être le chemin à parcourir. La méthode intéressante est la ConcurrentHashMap.putIfAbsent méthode, cela vous donnera une très bonne efficacité, et l’idée de l’utiliser est la suivante:

Vous aurez une "source multithread deadresses url entrantes "dans les pages analysées - vous pouvez utiliser une file d'attente simultanée pour les stocker, ou simplement créer un service ExecutorService avec une file d'attente (illimitée?) dans laquelle vous placerez des Runnables qui analyseront les URL.

À l’intérieur des Runnables, vous devriez avoir une référence à ce ConcurrentHashMap commun de pages déjà explorées, et au tout début du run méthode faire:

private final ConcurrentHashMap<String, Long> crawledPages = new ConcurrentHashMap<String, Long>();
...

private class Crawler implements Runnable {
private String urlToBeCrawled;

public void Crawler(String urlToBeCrawled) {
this.urlToBeCrawled = urlToBeCrawled;
}

public void run() {
if (crawledPages.putIfAbsent(urlToBeCrawled, System.currentTimeMillis())==null) {
doCrawlPage(urlToBeCrawled);
}
}
}

si crawledPages.putIfAbsent(urlToBeCrawled) reviendra nul pour vous, alors vous savez que celala page n’a été explorée par personne, car cette méthode attribue une valeur atomique à la progression de l’exploration de cette page - c’est le fil de la chance, si elle renvoie une valeur non nulle, alors vous savez que quelqu'un a déjà pris soin de cette URL , votre runnable doit donc se terminer et le thread retourne au pool pour être utilisé par le prochain Runnable.


2 pour la réponse № 2

Cas d'utilisation de domaine spécifique: Utilisation en mémoire

Si c'est un domaine spécifique, dites abc.com alors il est préférable d'avoir vistedURL set ou Concurrent hash map en mémoire, en mémoire sera plus rapide pour vérifier l'état visité, la consommation de mémoire sera comparativement moins. DB aura des frais généraux d'E / S et il est coûteux et la vérification du statut visité sera très fréquente. Cela va considérablement toucher votre performance. Selon votre cas d'utilisation, vous pouvez utiliser en mémoire ou dans une base de données. Mon cas d'utilisation était spécifique au domaine où l'URL visitée ne sera plus visitée. J'ai donc utilisé la carte de hachage simultanée.


1 pour la réponse № 3

Vous pouvez utiliser ConcurrentHashMap stocker pour trouver une URL en double.ConcurrentHashMap utilisez également le mécanisme de verrouillage fractionné au lieu d'utiliser le verrouillage global.

ou vous pouvez utiliser votre propre implémentation où vous pouvez fractionner toutes vos données entre différentes clés.

Pour un exemple d'API Guava

Striped<ReadWriteLock> rwLockStripes = Striped.readWriteLock(10);
String key = "taskA";
ReadWriteLock rwLock = rwLockStripes.get(key);
try{
rwLock.lock();
.....
}finally{
rwLock.unLock();
}

Exemple de ConcurrentHashMap

 private Set<String> urls = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());

0 pour la réponse № 4

pour le robot, n'utilisez pas ConcurrentHashMap, utilisez plutôt Databse

Le nombre d’URL visistées augmentera très rapidement,il n'est donc pas judicieux de les stocker en mémoire, mieux d'utiliser un databese, de stocker l'URL et la date de la dernière exploration, puis vérifiez simplement l'URL si elle existe déjà dans la base de données ou si elle peut être actualisée. J'utilise par exemple une base de données Derby en mode intégré, et cela fonctionne parfaitement pour mon robot d'exploration de sites Web. Je ne conseille pas d’utiliser une mémoire DB comme H2, car avec le nombre de pages analysées, vous obtiendrez éventuellement une exception OutOfMemoryException.

Vous aurez plutôt rarement le cas de ramperla même page plusieurs fois dans le même temps, il est donc suffisant de vérifier dans la base de données si elle a déjà été explorée récemment pour ne pas gaspiller des ressources importantes en "nouvelle analyse des mêmes pages, encore et encore". Je pense que c’est "une bonne solution qui ne soit ni trop dense ni trop simpliste"

En outre, l'utilisation de Databse avec la "date de la dernière visite"pour url, vous pouvez arrêter et continuer le travail quand vous le souhaitez. Avec ConcurrentHashMap, vous perdrez tous les résultats lors de la fermeture de l'application. Vous pouvez utiliser "date de la dernière visite" pour url afin de déterminer si elle nécessite une nouvelle analyse ou non.