java - 使用 lucene 改进多线程索引

标签 java multithreading lucene indexing

我正在尝试使用多线程在 Lucene 中构建索引。因此,我开始编码并编写了以下代码。首先,我找到文件并为每个文件创建一个线程来为其编制索引。之后我加入线程并优化索引。它有效,但我不确定......我可以大规模信任它吗?有什么办法可以改善吗?

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());
    }

    }
}

任何hep都被认为是。

最佳答案

如果你想并行索引,你可以做两件事:

  • 并行调用 addDocument,
  • 增加合并调度程序的最大线程数。

您正走在并行调用 addDocuments 的正确道路上,但是为每个文档生成一个线程不会随着您需要索引的文档数量的增长而扩展。您应该使用固定大小的 ThreadPoolExecutor .由于此任务主要是 CPU 密集型任务(取决于您的分析器和检索数据的方式),因此将计算机的 CPU 数量设置为最大线程数可能是一个好的开始。

关于合并调度程序,您可以增加可用于 setMaxThreadCount method of ConcurrentMergeScheduler 的最大线程数.请注意,磁盘在顺序读/写方面比随机读/写要好得多,因此为合并调度程序设置过高的最大线程数更有可能减慢索引速度而不是加快索引速度。

但在尝试并行化您的索引编制过程之前,您可能应该尝试找出瓶颈所在。如果您的磁盘太慢,瓶颈很可能是刷新和合并步骤,因此并行调用 addDocument(本质上包括分析文档并将分析结果缓冲在内存中)不会提高索引速度完全没有。

一些旁注:

  • Lucene 的开发版本正在进行一些工作以提高索引并行性(特别是刷新部分,blog entry 解释了它是如何工作的)。

  • Lucene 在 how to improve indexing speed 上有一个不错的 wiki 页面您可以在其中找到提高索引速度的其他方法。

关于java - 使用 lucene 改进多线程索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9317981/

相关文章:

java - 如何使用 Solr/Lucene 序列化/反序列化 map ?

java - 如何在我的 Lucene 应用程序中使用 ASCIIFoldingFilter?

c# - Lucene.net 可以用于基于标签的搜索系统吗?

java - Swing 中的 Round Double 值

java - 数组有固有的 hashCode() 吗?

c# - 如何获取事件线程数?

单例上的 C++

Java openStream() 工作时间取决于网站代码?

java - 无法获取 oracle-java8-installer 的 Java 包

c# - 从库中捕获主线程 SynchronizationContext 或 Dispatcher