繁体   English   中英

如何更新Lucene.NET索引?

[英]How to update a Lucene.NET index?

我正在使用Lucene.NET(v2.0)在Visual Basic 9(VS2008)中开发桌面搜索引擎。

我使用以下代码初始化IndexWriter

Private writer As IndexWriter

writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), False)

writer.SetUseCompoundFile(True)

如果我选择相同的文档文件夹(包含要编制索引的文件)两次,则会在索引中创建该文档文件夹中每个文件的两个不同条目。

我希望IndexWriter丢弃索引中已存在的所有文件。

我该怎么做才能确保这一点?

正如Steve所提到的,您需要使用IndexReader的实例并调用其DeleteDocuments方法。 DeleteDocuments接受Term对象的实例或Lucene的文档内部id(通常不建议尽可能使用内部id,并且会随着Lucene合并段而改变)。

最好的方法是使用您存储在特定于应用程序的索引中的唯一标识符。 例如,在医生办公室的患者索引中,如果您有一个名为“patient_id”的字段,您可以创建一个术语并将其作为参数传递给DeleteDocuments。 请参阅以下示例(抱歉,C#):

int patientID = 12;
IndexReader indexReader = IndexReader.Open( indexDirectory );
indexReader.DeleteDocuments( new Term( "patient_id", patientID ) );

然后,您可以使用IndexWriter实例再次添加患者记录。 我从这篇文章中学到了很多东西http://www.codeproject.com/KB/library/IntroducingLucene.aspx

希望这可以帮助。

有关id字段的删除有许多过时的例子。 下面的代码适用于Lucene.NET 2.4。

如果您已经在使用IndexWriter或访问IndexSearcher.Reader,则无需打开IndexReader。 您可以使用IndexWriter.DeleteDocuments(Term),但棘手的部分是确保您首先正确存储了您的id字段。 在存储文档时,请确保使用Field.Index.NOT_ANALYZED作为id字段的索引设置。 这会对字段编制索引而不对其进行标记,这非常重要,并且当使用这种方式时,其他任何Field.Index值都不会起作用:

IndexWriter writer = new IndexWriter("\MyIndexFolder", new StandardAnalyzer());
var doc = new Document();
var idField = new Field("id", "MyItemId", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc.Add(idField);
writer.AddDocument(doc);
writer.Commit();

现在,您可以使用同一个编写器轻松删除或更新文档:

Term idTerm = new Term("id", "MyItemId");
writer.DeleteDocuments(idTerm);
writer.Commit();

如果要删除索引中的所有内容并重新填充,可以使用此语句

writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), True)

IndexWriter构造函数的最后一个参数确定是创建新索引,还是打开现有索引以添加新文档。

要更新lucene索引,您需要删除旧条目并写入新条目。 因此,您需要使用IndexReader查找当前项目,使用writer删除它,然后添加新项目。 多个条目也是如此,我认为这是你要做的事情。只需找到所有条目,删除所有条目然后写入新条目。

下面列出了一些选项,可根据要求使用。

见下面的代码快照。 [C#中的源代码,请将其转换为vb.net]

Lucene.Net.Documents.Document doc = ConvertToLuceneDocument(id, data);
Lucene.Net.Store.Directory dir = Lucene.Net.Store.FSDirectory.Open(new DirectoryInfo(UpdateConfiguration.IndexTextFiles));
Lucene.Net.Analysis.Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
Lucene.Net.Index.IndexWriter indexWriter = new Lucene.Net.Index.IndexWriter(dir, analyzer, false, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
Lucene.Net.Index.Term idTerm = new Lucene.Net.Index.Term("id", id);

foreach (FileInfo file in new DirectoryInfo(UpdateConfiguration.UpdatePath).EnumerateFiles())
{
        Scenario 1: Single step update.
                indexWriter.UpdateDocument(idTerm, doc, analyzer);

        Scenario 2: Delete a document and then Update the document
                indexWriter.DeleteDocuments(idTerm);
                indexWriter.AddDocument(doc);

        Scenario 3: Take necessary steps if a document does not exist.

            Lucene.Net.Index.IndexReader iReader = Lucene.Net.Index.IndexReader.Open(indexWriter.GetDirectory(), true);
            Lucene.Net.Search.IndexSearcher iSearcher = new Lucene.Net.Search.IndexSearcher(iReader);
            int docCount = iSearcher.DocFreq(idTerm);
            iSearcher.Close();
            iReader.Close();
            if (docCount == 0)
            {
                    //TODO: Take necessary steps
                    //Possible Step 1: add document
                    //indexWriter.AddDocument(doc);

                    //Possible Step 2: raise the error for the unknown document
            }
}
indexWriter.Optimize();
indexWriter.Close();

除非您只修改少量文档(例如,少于总数的10%),否则几乎肯定会更快(您的里程可能会因存储/索引字段等而异)从头开始重新索引。

也就是说,我总是会索引到一个临时目录,然后在完成后将新的目录移动到位。 这样,在索引构建时几乎没有停机时间,如果出现问题,您仍然可以获得良好的索引。

一种选择当然是删除文档,然后添加文档的更新版本。

或者,您也可以使用IndexWriter类的UpdateDocument()方法:

writer.UpdateDocument(new Term("patient_id", document.Get("patient_id")), document);

这当然要求您有一种机制,通过该机制可以找到要更新的文档(本例中为“patient_id”)。

用更完整的源代码示例写了更多详细信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM