首先lucene不支持更新单个字段,因此尝试隔离和优化单个字段的更新过程没有任何好处。
基本上你正在寻找的是一种方法:
如果 lucene 索引不是主数据存储,您应该使用主数据存储来获取文档集新值,然后用伪代码重新索引整个文档:
public void updateField(String docId, int newFieldvalue) {
MyDataObject data = primaryDataStore.fetch(docId);
data.setFieldValue(newFieldValue);
primaryDataStore.save(data);
updateIndex(data);
}
public void updateIndex(MyDataObject object) {
// convertToLucene is more or less the code in the
// first snippet of your question
Document d = convertToLucene(object);
// IndexWriter should be created once
// IndexWriter.updateDocument will internally delete and index
// the document
this.writer.updateDocument(new Term("id", object.getId()), d);
// potentially call writer.commit()
}
如果 lucene 是您的主要数据存储,它会更复杂,我强烈建议(如果还不算太晚的话)使用 solr 或 elasticsearch,它们提供了一个很好的 REST API,使 lucene 更像一个文档存储。
您必须考虑到 lucene 不是“开箱即用”的文档数据存储。如果您想使用 lucene 作为主数据存储,您可以使用您选择的格式(JSON、二进制序列化...)将文档存储在存储字段中。
要获取文档,您必须对使用 TermQuery 创建的字段“id”执行搜索查询,使用收集器或 TodDocs,然后在 IndexReader 或 IndexSearcher 上调用 document(int luceneDocId) 以用伪代码获取存储的字段(替换之前sn-p中使用的primaryDataStore.fetch(docId)的方法):
public MyDataObject fetchFromLucene(String docId) {
IndexSearcher searcher = getSearcher();
TopDocs docs = searcher.search(new TermQuery(new Term("id", docId)), 1);
if (docs.totalHits > 0) {
Document d = searcher.document(docs.scoreDocs[0].doc);
// "document_data" is a binary field you'll have to add
// on every lucene docs where you put a serialized version
// of your domain object.
return deserialize( d.getBinaryValue("document_data") );
}
return null;
}
public MyDataObject deserialize(ByteRef data) {
// a method to deserialize binary data into MyDataObject
return deserializedData;
}
简而言之,如果您想直接将 lucene 作为主数据存储来处理,您最终会编写大量样板代码。
请注意,您必须自己管理许多低级 lucene 方面,例如以高效的方式刷新您的 IndexReaders。