Java Lucene IndexReader no funciona correctamente

La historia es esta. Quiero imitar el comportamiento de una base de datos relacional usando un índice de Lucene en java. Necesito poder buscar (leer) y escribir al mismo tiempo.

Por ejemplo, quiero guardar la información del proyecto en un índice. Para simplificar, digamos que el proyecto tiene 2 campos: id y nombre. Ahora, antes de agregar un nuevo proyecto al índice, estoy buscando si ya está presente un proyecto con una identificación determinada. Para esto estoy usando un IndexSearcher. Esta operación se completa con éxito (es decir, IndexSearcher devuelve el ID de documento interno para el documento que contiene el ID del proyecto que estoy buscando). Ahora quiero leer el valor de este ID de proyecto, así que ahora estoy usando un IndexReader para obtener el documento de Lucene indexado del cual puedo extraer el campo de ID del proyecto. El problema es que IndexReader devuelve un documento que tiene todos los campos NULL. Entonces, para repetir que IndexSearcher funciona correctamente, IndexReader devuelve cosas falsas.

Estoy pensando que de alguna manera esto tiene que ver con el hecho de que los datos de los campos del documento no se guardan en el disco duro cuando se vacía el IndexWriter. El caso es que la primera vez que hago esta operación de indexación, IndexReader funciona bien. Sin embargo, después de reiniciar mi aplicación, ocurre la situación mencionada anteriormente. Entonces, estoy pensando que la primera vez que los datos flotan en la RAM, pero no se vacían correctamente (o totalmente desde que IndexSearcher funciona) en el disco duro.

Tal vez ayude si le doy el código fuente, así que aquí está (puede ignorar con seguridad la parte tryGetIdFromMemory, lo estoy usando como un truco de optimización de velocidad):

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();
}

}

Para ser más precisos, todos los problemas ocurren en esto si:

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"));
    }

En la rama else ... no sé qué está mal.

preguntado el 16 de mayo de 11 a las 20:05

2 Respuestas

¿Manejas tienda los campos respectivos? De lo contrario, los campos se almacenan "sólo" en la parte del índice inverso, es decir, el valor del campo se asigna al documento, pero el documento en sí no contiene el valor del campo.

La parte del código donde guarda el documento puede resultar útil.

contestado el 17 de mayo de 11 a las 00:05

¡Si! Eso fue todo. Me confundí por tanta indexación. ¡Gracias! - Víctor Blaga

Me costó descubrir cómo indexar / buscar números y solo quería decir que los siguientes fragmentos de código realmente me ayudaron:

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

////////////

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

¡Gracias!

respondido 02 nov., 11:19

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.