我使用的是Lucene.Net 3.0.3.0。
我有一个索引,其中包含具有多个字段和一些未存储的文档。当客户端有与此文档相关的更新时,我想更新相应文档的 ClientName 字段,但我遇到的问题是,当我尝试获取该客户端的所有文档时,更新该字段并放入文档回到索引中,未存储的字段将丢失。
所以像这样的文档:
DocId : 10
ClientId : 125
ClientName (Not stored) : Google
DocTitle (Not stored): Some title
DocContent (Not stored): content of my document
当客户端名称发生更新时,我必须更新字段 clientName,因此我在索引上搜索以查找 clientId 为 125 的所有文档,然后更新 clientname 字段并将文档删除/插入回指数。 但字段
DocTitle
和 DocContent
在此过程中丢失了。
如何更新
ClientName
字段而不丢失其他非存储字段?
编辑:根据建议,这是一段代码,用于迭代搜索结果以更新文档上的字段
for (int i = 0; i < collector.Docs.Count; i++)
{
// retrieve the current document from the search result
var oldDocument = searcher.Doc(collector.Docs[i]);
var reviewId = oldDocument.Get(FIELD_ID);
var updateTerm = new Term(FIELD_ID, reviewId);
oldDocument.RemoveFields(FIELD_CLIENT_NAME);
oldDocument.Add(new Field(FIELD_CLIENT_NAME, newClientName, Field.Store.NO, Field.Index.NOT_ANALYZED));
//writer is an instance of Lucene.Net.Index.IndexWriter
writer.UpdateDocument(updateTerm, oldDocument);
}
从那里开始,文档将正确保存在索引中,但未存储的字段 (
Field.Store.NO
) 会丢失,除了我刚刚更新的 FIELD_CLIENT_NAME
。
不确定幕后发生了什么,但可以肯定的是,您正在尝试的不是在 Lucene 中更新文档的方法。
查看
removeField
中org.apache.lucene.document.Document
方法的定义。
请注意,removeField(s) 方法(如 add 方法)仅在将文档添加到索引之前才有意义。 这些方法不能 用于更改现有索引的内容! 为了实现此目的,必须从索引中删除文档,并且必须添加该文档的新更改版本。
如您所知,更新方法将首先删除与所提供术语匹配的文档,然后添加新文档。
根据我们项目的实践,我能想到的一种可能的方法如下。
假设所有文档都从数据库中索引。所以一旦数据库记录更新,你也必须更新相应的 Lucene 文档。
伪代码可能是这样的
indexWriter.updateDocument(
//databaseRecordId is normally the primary key of updated record
new Term("docId", databaseRecordPId)
indexedDocument // find the updated database record and index it
)
如果您的 Lucene 文档不是“来自”数据库记录,请忘记我所说的。
无论如何,希望对你有帮助。
我也证实了这种行为。 任何未标记为“已存储”的索引字段都将从索引中丢失。
我的工作是确定如何按需检索非存储字段,以便在更新操作期间将它们添加回文档中,或者如果该字段非常小,我只需继续将其最初索引为“存储”,以便文档更新时不需要重新添加。
这真是一个耻辱,因为我很乐意接受一些索引碎片,而不必存储数据。 我能够嵌入索引而无需存储所有字段并启用嵌入式客户端搜索,从而节省了大量空间。