【问题标题】:Java Lucene IndexReader not working correctlyJava Lucene IndexReader 无法正常工作
【发布时间】:2025-12-14 21:10:02
【问题描述】:

故事是这样的。我想在 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"));
    }

在 else 分支上... 不知道怎么回事。

【问题讨论】:

    标签: java indexing lucene


    【解决方案1】:

    您是否store 各自的字段?如果不是,则字段“仅”存储在反向索引部分中,即字段值映射到文档,但文档本身不包含字段值。

    保存文档的代码部分可能会有所帮助。

    【讨论】:

    • 是的!就是这样。被太多索引弄糊涂了。谢谢!
    【解决方案2】:

    我很难弄清楚如何索引/搜索数字,我只想说下面的 sn-ps 代码真的帮助了我:

    projectId = Integer.valueOf(document.get("projectId"));
    

    ///////////

    Field idField = new Field("projectId", String.valueOf(projectId),
                Store.NO, Index.ANALYZED);
        document.add(idField);
    

    谢谢!

    【讨论】: