故事是这样的。我想在java中使用Lucene索引模仿关系数据库的行为。我需要能够同时进行搜索(阅读)和写作。
例如,我想将项目信息保存到索引中。为简单起见,假设项目有2个字段 - id和name。现在,在向索引添加新项目之前,我正在搜索具有给定id的项目是否已经存在。为此,我使用的是IndexSearcher。此操作成功完成(即IndexSearcher返回包含我正在查找的项目ID的文档的内部文档ID)。 现在我想实际读取这个项目ID的值,所以我现在使用一个IndexReader来获取索引的Lucene文档,我可以从中提取项目ID字段。 问题是IndexReader返回一个包含所有字段为NULL的Document。因此,要重复IndexSearcher正常工作,IndexReader会返回伪造的内容。
我认为这与文件字段数据在刷新IndexWriter时不会保存在硬盘上的事实有关。问题是我第一次做这个索引操作时,IndexReader工作得很好。但是,在重新启动我的应用程序后,会出现上述情况。所以我认为第一次数据浮动在RAM中,但是在硬盘驱动器上没有正确刷新(或完全自IndexSearcher起作用)。
如果我给你源代码,也许会有所帮助,所以在这里(你可以放心地忽略tryGetIdFromMemory部分,我正在使用它作为速度优化技巧):
public class ProjectMetadataIndexer {
private File indexFolder;
private Directory directory;
private IndexSearcher indexSearcher;
private IndexReader indexReader;
private IndexWriter indexWriter;
private Version luceneVersion = Version.LUCENE_31;
private Map<String, Integer> inMemoryIdHolder;
private final int memoryCapacity = 10000;
public ProjectMetadataIndexer() throws IOException {
inMemoryIdHolder = new HashMap<String, Integer>();
indexFolder = new File(ConfigurationSingleton.getInstance()
.getProjectMetaIndexFolder());
directory = FSDirectory.open(indexFolder);
IndexWriterConfig config = new IndexWriterConfig(luceneVersion,
new WhitespaceAnalyzer(luceneVersion));
indexWriter = new IndexWriter(directory, config);
indexReader = IndexReader.open(indexWriter, false);
indexSearcher = new IndexSearcher(indexReader);
}
public int getProjectId(String projectName) throws IOException {
int fromMemoryId = tryGetProjectIdFromMemory(projectName);
if (fromMemoryId >= 0) {
return fromMemoryId;
} else {
int projectId;
Term projectNameTerm = new Term("projectName", projectName);
TermQuery projectNameQuery = new TermQuery(projectNameTerm);
BooleanQuery query = new BooleanQuery();
query.add(projectNameQuery, Occur.MUST);
TopDocs docs = indexSearcher.search(query, 1);
if (docs.totalHits == 0) {
projectId = IDStore.getInstance().getProjectId();
indexMeta(projectId, projectName);
} else {
int internalId = docs.scoreDocs[0].doc;
indexWriter.close();
indexReader.close();
indexSearcher.close();
indexReader = IndexReader.open(directory);
Document document = indexReader.document(internalId);
List<Fieldable> fields = document.getFields();
System.out.println(document.get("projectId"));
projectId = Integer.valueOf(document.get("projectId"));
}
storeInMemory(projectName, projectId);
return projectId;
}
}
private int tryGetProjectIdFromMemory(String projectName) {
String key = projectName;
Integer id = inMemoryIdHolder.get(key);
if (id == null) {
return -1;
} else {
return id.intValue();
}
}
private void storeInMemory(String projectName, int projectId) {
if (inMemoryIdHolder.size() > memoryCapacity) {
inMemoryIdHolder.clear();
}
String key = projectName;
inMemoryIdHolder.put(key, projectId);
}
private void indexMeta(int projectId, String projectName)
throws CorruptIndexException, IOException {
Document document = new Document();
Field idField = new Field("projectId", String.valueOf(projectId),
Store.NO, Index.ANALYZED);
document.add(idField);
Field nameField = new Field("projectName", projectName, Store.NO,
Index.ANALYZED);
document.add(nameField);
indexWriter.addDocument(document);
}
public void close() throws CorruptIndexException, IOException {
indexReader.close();
indexWriter.close();
}
}
更准确地说,如果出现以下所有问题:
if (docs.totalHits == 0) {
projectId = IDStore.getInstance().getProjectId();
indexMeta(projectId, projectName);
} else {
int internalId = docs.scoreDocs[0].doc;
Document document = indexReader.document(internalId);
List<Fieldable> fields = document.getFields();
System.out.println(document.get("projectId"));
projectId = Integer.valueOf(document.get("projectId"));
}
在其他分支上...... 我不知道出了什么问题。
答案 0 :(得分:1)
你是store各自的领域吗?如果不是,则字段“仅”存储在反向索引部分中,即字段值被映射到文档,但是文档本身不包含字段值。
保存文档的代码部分可能会有所帮助。
答案 1 :(得分:0)
我很难弄清楚如何索引/搜索数字,我只是想说下面的代码片段真的帮助了我:
projectId = Integer.valueOf(document.get("projectId"));
////////////
Field idField = new Field("projectId", String.valueOf(projectId),
Store.NO, Index.ANALYZED);
document.add(idField);
谢谢!