对Lucene索引文件进行线程安全写入

本文关键字:线程 安全 Lucene 索引 文件 | 更新日期: 2023-09-27 18:21:48

我有一个应用程序,它可以对网站进行爬网,并将内容作为lucene索引文件写入物理目录。

当我将线程用于此目的时,我会遇到写错误或由于锁定而导致的错误。

我想使用多个线程并在不错过任何线程的任务的情况下写入索引文件。

public class WriteDocument
{
    private static Analyzer _analyzer;
    private static IndexWriter indexWriter;
    private static string Host;
    public WriteDocument(string _Host)
    {
        Host = _Host;
        Lucene.Net.Store.Directory _directory = FSDirectory.GetDirectory(Host, false);
        _analyzer = new StandardAnalyzer();
        bool indexExists = IndexReader.IndexExists(_directory);
        bool createIndex = !indexExists;
        indexWriter = new IndexWriter(_directory, _analyzer, true);
    }
    public void AddDocument(object obj)
    {
           DocumentSettings doc = (DocumentSettings)obj;               
           Field urlField = new Field("Url", doc.downloadedDocument.Uri.ToString(), Field.Store.YES, Field.Index.TOKENIZED);
            document.Add(urlField);
            indexWriter.AddDocument(document);
            document = null;
            doc.downloadedDocument = null;
            indexWriter.Optimize();
            indexWriter.Close();
      }
}

对于上面的类,我传递的值如下:

DocumentSettings writedoc = new DocumentSettings()
{
      Host = Host,
      downloadedDocument = downloadDocument
};
Thread t = new Thread(() =>
{
doc.AddDocument(writedoc);
});
t.Start();

如果我在t.Start();之后添加t.Join();,代码对我来说是有效的,没有任何错误。但这会减慢我的进程,实际上,这等于我在不使用线程的情况下得到的输出。

我得到的错误像:

Cannot rename /indexes/Segments.new to /indexes/Segments 
the file is used by some other process.

有人能帮我处理这个代码吗?

对Lucene索引文件进行线程安全写入

IndexWriter不是线程安全的,所以这是不可能的。

如果你想使用多个线程进行下载,你需要构建某种单线程的"消息泵",你可以向它提供你正在下载和创建的文档,并将它们放入队列中。

例如,在AddDocument方法中,不直接使用索引,只需将它们发送到一个服务,该服务最终会对其进行索引。

该服务应该一直尝试索引队列中的所有内容,如果暂时没有队列,请休眠一段时间。

您可以采取的一种方法是为每个线程创建一个单独的索引,并在最后将它们全部合并回来。例如index1、index2…indexn(对应于线程1..n)并合并它们。