Améliorez l'indexation multi-thread avec lucene
Je suis en train de construire mon index de Lucene avec plusieurs threads. Donc, j'ai commencé mon codage et écrit le code suivant. J'ai d'abord trouver les fichiers et pour chaque fichier, j'ai créer un thread à l'index. Après que je me joins les fils et optimiser les index. Il fonctionne, mais je ne suis pas sûr... puis-je avoir confiance dans la grande échelle? Est-il possible de l'améliorer?
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Document;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.StopAnalyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.lucene.index.TermFreqVector;
public class mIndexer extends Thread {
private File ifile;
private static IndexWriter writer;
public mIndexer(File f) {
ifile = f.getAbsoluteFile();
}
public static void main(String args[]) throws Exception {
System.out.println("here...");
String indexDir;
String dataDir;
if (args.length != 2) {
dataDir = new String("/home/omid/Ranking/docs/");
indexDir = new String("/home/omid/Ranking/indexes/");
}
else {
dataDir = args[0];
indexDir = args[1];
}
long start = System.currentTimeMillis();
Directory dir = FSDirectory.open(new File(indexDir));
writer = new IndexWriter(dir,
new StopAnalyzer(Version.LUCENE_34, new File("/home/omid/Desktop/stopwords.txt")),
true,
IndexWriter.MaxFieldLength.UNLIMITED);
int numIndexed = 0;
try {
numIndexed = index(dataDir, new TextFilesFilter());
} finally {
long end = System.currentTimeMillis();
System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
writer.optimize();
System.out.println("Optimization took place in " + (System.currentTimeMillis() - end) + " milliseconds");
writer.close();
}
System.out.println("Enjoy your day/night");
}
public static int index(String dataDir, FileFilter filter) throws Exception {
File[] dires = new File(dataDir).listFiles();
for (File d: dires) {
if (d.isDirectory()) {
File[] files = new File(d.getAbsolutePath()).listFiles();
for (File f: files) {
if (!f.isDirectory() &&
!f.isHidden() &&
f.exists() &&
f.canRead() &&
(filter == null || filter.accept(f))) {
Thread t = new mIndexer(f);
t.start();
t.join();
}
}
}
}
return writer.numDocs();
}
private static class TextFilesFilter implements FileFilter {
public boolean accept(File path) {
return path.getName().toLowerCase().endsWith(".txt");
}
}
protected Document getDocument() throws Exception {
Document doc = new Document();
if (ifile.exists()) {
doc.add(new Field("contents", new FileReader(ifile), Field.TermVector.YES));
doc.add(new Field("path", ifile.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
String cat = "WIR";
cat = ifile.getAbsolutePath().substring(0, ifile.getAbsolutePath().length()-ifile.getName().length()-1);
cat = cat.substring(cat.lastIndexOf('/')+1, cat.length());
//doc.add(new Field("category", cat.subSequence(0, cat.length()), Field.Store.YES));
//System.out.println(cat.subSequence(0, cat.length()));
}
return doc;
}
public void run() {
try {
System.out.println("Indexing " + ifile.getAbsolutePath());
Document doc = getDocument();
writer.addDocument(doc);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
Tout hep est considéré.
source d'informationauteur orezvani
Vous devez vous connecter pour publier un commentaire.
Si vous voulez paralléliser l'indexation, il y a deux choses que vous pouvez faire:
Vous êtes sur la bonne voie pour paralléliser les appels à addDocuments, mais fraie un thread par le document ne sera pas à l'échelle, comme le nombre de documents dont vous avez besoin pour indice de croître. Vous devriez plutôt utiliser une taille fixe ThreadPoolExecutor. Puisque cette tâche est principalement CPU-intensive (en fonction de votre analyseur et de la façon dont vous récupérer vos données), le réglage du nombre de Processeurs de votre ordinateur tant que le nombre maximal de threads peut être un bon début.
Concernant la fusion planificateur, vous pouvez augmenter le nombre maximal de threads qui peuvent être utilisés avec le setMaxThreadCount méthode de ConcurrentMergeScheduler. Méfiez-vous que les disques sont beaucoup mieux à des lectures séquentielles/écrit qu'au hasard de lecture/écriture, comme une conséquence de réglage trop grand nombre maximal de threads de votre planificateur de fusion est plus susceptible de ralentir l'indexation que de l'accélérer.
Mais avant d'essayer de la parallélisation de votre processus d'indexation, vous devriez probablement essayer de trouver où le goulot d'étranglement est. Si votre disque dur est trop lent, le goulot d'étranglement est susceptible d'être la chasse et de la fusion étapes, comme une conséquence de la parallélisation des appels à addDocument (qui consiste essentiellement en l'analyse d'un document et de mise en mémoire tampon le résultat de l'analyse en mémoire) ne va pas améliorer la vitesse d'indexation.
Quelques remarques:
Il y a quelques travaux en cours dans la version de développement de Lucene dans le but d'améliorer l'indexation de parallélisme (les rougeurs partie en particulier, ce l'entrée de blog explique comment il fonctionne).
Lucene a une belle page de wiki sur comment améliorer la vitesse d'indexation où vous pourrez trouver d'autres moyens pour améliorer la vitesse d'indexation.
Je pense que le plus moderne de la façon de le faire est d'utiliser un ThreadPoolExecutor et de soumettre un Praticable que fait votre indexation. Vous pouvez vous attendre à tous les threads de mettre fin à l'aide .awaitTermination, ou un CountdownLatch.
Je ne suis pas un grand fan de votre classe principale étendre Fil, il suffit de créer un exécutable intérieur de la classe qui prend sa depdencies dans un constructeur. Cela rend votre code plus lisible, comme le travail, les fils sont en train de faire sont clairement séparées de l'installation de votre application code.
Quelques notes sur le style, je ne suis pas un grand fan de votre classe principale jeter l'Exception, cela signifie juste que vous n'avez pas une idée claire des différentes vérifié exception des cas le code que vous utilisez peut jeter. Habituellement, il n'est pas la bonne chose à faire, sauf si vous avez une raison bien précise.