Algunos apuntes sobre Lucene en el mundo de Alfresco

En este artículo quiero hablaros de Lucene. Aunque en la versión 4.0 de Alfresco ya se incorpora SOLR como motor de indexación alternativo y escalable, también se puede seguir usando Lucene. Además, existen multitud de instalaciones que utilizan Lucene y que posiblemente seguirán utilizándolo. Voy a ampliar algunos conceptos al respecto para intentar ayudaros a comprender cómo funciona y cómo solucionar posibles problemas que nos podemos encontrar.
  • NOTA/DISCLAIMER: Lo que aprendas en este artículo no lo uses en producción salvo que sepas realmente lo que estás haciendo. No me hago responsable de los problemas que puedas tener derivados de este artículo ;)
Empecemos por el principio, el documento. Hay dos partes de un documento en Alfresco, la primera es el documento por si mismo y su contenido, la segunda son los metadatos asociados a ese documento. Por defecto, se indexan esas dos partes de un documento, por eso podemos buscarlos y localizarlos. Esta es una explicación simple ya que por debajo hay una serie de tareas automáticas y un poco más complejas que la descripción anterior. Vamos a verlo.
  • En Alfresco puedes buscar información mediante las interfaces web Share o Explorer y también mediante las diferentes APIs disponibles. Las búsquedas pueden ser por palabras clave o búsquedas booleanas, Alfresco las traduce a formato Lucene Query y las ejecuta sobre los índices en su instancia de Alfresco.
  • ¿Cómo puedo saber que hay realmente en los índices de Alfresco? Los índices por defecto se almacenan en un directorio llamado “lucene-indexes” dentro del directorio “alf_data“. Dentro del directorio principal de índices hay más carpetas y ficheros que están relacionados con los índices de los que no podemos ver su contenido directamente ya que son binarios y de los que hablaremos más adelante.
  • Puedes ver el contenido de esos ficheros con una herramienta de debug muy útil y multiplataforma llamada Luke. Para abrir los índices por ejemplo del workspace/Spacestore, en el browser de Luke navega hasta alf_data/lucene-indexes/workspace/SpacesStore y selecciona el fichero IndexInfo. Luke te permite abrir los índices con la opción “Open in Read Only mode”, úsala. Ya que con Luke puedes hacer tareas de lectura sobre los índices y también ¡borrados! Lee bien la documentación antes de aventurarte a hacer alguna fechoría con esta herramienta. No es el objetivo de este artículo hacer un manual de Luke, simplemente darlo a conocer si no lo conocías ya. Si lo usas y lo dominas puedes escribir un artículo que será muy útil para todos.

Sigamos con los índices. Veamos qué hace Alfresco de forma genérica cuando se sube un documento o se actualiza:
Como vemos en la imagen anterior, a ese diagrama global podríamos añadir el siguiente resumen del proceso de indexación:
  • 1º Se transforma el contenido a texto
  • 2º Se usa un analizador basado en el idioma del documento para extraer cadenas derivadas de plurales, mayúsculas, etc. Dependiendo del idioma, estos analizadores serán más o menos complejos.
  • 3º Lucene indexa los metadatos que están marcados para ser indexados.
  • 4º Lucene indexa el contenido, que sea susceptible de indexar (por ejemplo un documento, si se trata de un binario como una imagen no se indexa el contenido). La indexación del contenido se podría desactivar.
  • 5º Si se trata de una actualización, la versión anterior se mueve a otro directorio (interno de los índices) y la nueva versión se crea en el índice activo (live index).
Hay tres directorios que afectan a los índices y que se pueden configurar en alfresco-global.properties mediante las siguientes propiedades (recuerda que se configuraría usando propiedad=valor y todas las opciones está disponibles en el fichero alfresco/WEB-INF/classes/alfresco/repository.properties):
  • dir.idexes y dir.indexes.lock que necesitan estar en los discos locales donde se instala el repositorio (alfresco.war), ya que se hace un uso intensivo de I/O de disco.
  • dir.indexes.backup podemos ubicarlo donde queramos siempre que esté accesible por el servidor, ahí se almacenan los backups automáticos nocturnos a las 3AM cada día. Aunque también se puede ejecutar manualmente mediante JMX en la versión Enterprise. Si quieres saber qué procesos nocturnos afectan a los índices y cómo, lee este artículo. No tener controlados los backups de los índices te pueden llevar a tener que reindexar todo un repositorio completo, que puede llevar varios días dependiendo de la cantidad de contenidos.
Dentro del directorio dir.indexes hay una serie de directorios que corresponden a cada uno de los stores de Alfresco (más info aquí). Cada directorio o subdirectorio contiene un fichero llamado IndexInfo que nos da información sobre los índices de cada uno de los stores.
La indexación de los contenidos se gestionan mediante el modelo de datos, por defecto se utiliza el siguiente fichero alfresco/WEB-INF/classes/alfresco/model/contentModel.xml. Y las opciones para todos los contenidos, si no tenemos ningún tipo adicional es como sigue:
     <type name="cm:content">
        <title>Content</title>
        <parent>cm:cmobject</parent>
        <properties>
           <property name="cm:content">
              <type>d:content</type>
              <mandatory>false</mandatory>
              <index enabled="true">
                 <atomic>false</atomic>
                 <stored>false</stored>
                 <tokenised>true</tokenised>
              </index>
           </property>
        </properties>
     </type>
A este respecto, cuando un documento se sube a Alfresco, los metadatos se extraen y se indexan en el acto, pero el contenido no tiene por que ser indexado en ese momento (depende). Veremos más abajo que significan estas opciones y qué nos aportan.
Como vemos en la parte <index enabled=”true”>, hay diferentes opciones en cuanto a los índices de las propiedades o de los contenidos:
  • Enabled=”false”: Si está a “false” no se indexará esa propiedad.
  • Atomic=”true”: Si está a “true”, esa propiedad (metadato) es indexada en el momento de la transacción, si está a “false”, se indexará en background. La indexación de contenidos que necesitan transformación antes de ser indexados (p. ej. PDF), solo serán “atomic=true” si la transformación tarda menos tiempo que el valor especificado en el atributo lucene.maxAtomicTransformationTime. Todos los transformadores por defecto están aquí alfresco/WEB-INF/classes/alfresco/services-context.xml.
  • Stored=”true”: Si está a “true”, el valor de la propiedad se almacenará en el índice y debe ser consultado mediante la API de bajo nivel de Lucene. Esto es útil para debugging si queremos saber qué es exactamente lo que se está indexando, pero no está recomendado en absoluto para producción ya que escribe mucha más información en disco. Recomendado “false”.
  • Tokenised=”true”: Si está “true”, el valor de la cadena de la propiedad se tokeniza antes de ser indexado. Si está a “false”, se indexará como una única cadena, si está a “both” se harán las dos opciones. Valor recomendado “true”.
Recuerda que por defecto todo el contenido, si se indexa, es “not stored”, indexed y tokenized.
  • Si quieres cambiar el comportamiento por defecto puedes hacerlo pero deberás reindexar todos los contenidos tras hacer el cambio. No te recomiendo tocar el modelo por defecto, es mejor hacer el tuyo propio y heredar valores o no, dependiendo de las necesidades que tengas. Recuerda que si haces un tipo que herede del tipo raíz “cm:content” no podrás desactivar el indexado del contenido.
  • Por defecto, las versiones de un documento (que se almacenan en el store workspace://version2Store) no se indexan. Ese comportamiento se podría modificar modificando el fichero core-services-context.xml como se puede ver aquí, referenciando la entrada version2Store al bean avmLuceneIndexerAndSearcherFactory igual que se pueden ver el workspace y el avm. Si lo haces recuerda que tendrás un consumo mucho más elevado de disco en los índices (dependerá del número de versiones que tengas por contenido, si no lo controlas bien no lo hagas, puede ser una bomba). Aunque actives la indexación del store de versiones, los formularios de búsqueda de Share o Explorer no buscarán en version2Store, pero se puede usar la API para realizar la búsqueda.
En cuanto a la recuperación de índices, es importante saber que existen cuatro modos FULL, AUTO, VALIDATE y NONE, que se usan en alfresco-global.properties mediante el atributo index.recovery.mode.
  • index.recovery.mode=FULL: Borra todos los índices actuales y genera un nuevo índice de todo el contenido (reindexa), durante este proceso el servidor no estará disponible.
  • index.recovery.mode=AUTO: Comprueba los primeros y últimos 1000 identificadores de transacción (txn) son válidos en cada store (información en la BBDD y en los índices coincide). Si no son válidos, se realizará una indexación FULL. En un cluster es importante tener sincronizados horariamente los servidores porque de lo contrario se lanzarán las reindexaciones al no coincidir la BBDD con los índices y la hora del servidor.
  • index.recovery.mode=VALIDATE: Comprueba los primeros y últimos 1000 identificadores de transacción (txn) son válidos en cada store (información en la BBDD y en los índices coincide). Si no son válidos, simplente devolverá una excepción.
  • index.recovery.mode=NONE: No se hace ningún tipo de validación en los índices.
Como vemos, los índices son muy importantes para Alfresco, tanto que si al arrancar encuentra algún problema grave en ellos, que no se solucione reindexando, el servidor se parará automáticamente. Este comportamiento se controla mediante el valor system.bootstrap.config_check.strict que por defecto está a “true”, podríamos ponerlo a “false” para poder analizar mejor algún problema concreto del que no tenemos mucha información en los logs (úsalo sólo para debug, afecta a otras opciones de configuración) y que evita que Alfresco arranque totalmente.
Al principio decía que los índices deben estar en discos locales (lo más rápidos disponibles y dedicados si es posible) para garantizar el máximo rendimiento de la aplicación. Para evitar problemas de lentitud es recomendable tener el doble del tamaño del índice total como espacio libre, para evitar problemas en caso de reindexación y sobre todo para el merge de los índices que se realiza a menudo. De hecho si compruebas que la subida de ficheros es muy lenta comprueba que tienes suficiente espacio libre en la partición o disco de los índices y que tienes correctamente configurados los file descriptors del sistema operativo (ver este artículo).
En caso de reindexación FULL podrás ver en los logs trazas como las siguientes:
20:33:02,502 INFO [node.index.FullIndexRecoveryComponent] 100 % complete.
20:33:55,753 INFO [node.index.FullIndexRecoveryComponent] Index recovery completed.
Eso no significa que se hayan reindexado todos los contenidos, sólo nos indica que se han reindexado todas las propiedades (metadatos). A partir de ese momento Alfresco se pondrá a reindexar el contenido de los documentos. ¿Como podemos comprobar que está ocurriendo eso? Viendo la actividad en la CPU que puede provocar OpenOffice, ya que éste es utilizado para transformar ficheros MS Word a texto para poder ser indexados, por ejemplo.
Aunque ya lo comenté un poco en este artículo, quiero recordaros que existe el “Adminstrador de índices” o “Index Checker Console” disponible en la versión Enterprise desde la 3.1, puedes encontrarlo aquí: http://localhost:8080/alfresco/service/enterprise/admin/indexcheck. Esta consola te permite:
  • a) Comprobar los índices: por ejemplo, comprobar que cada transacción realizada por el repositorio está contemplada en los índices. Se puede comprobar por rangos de tiempo o rangos de transacciones.
  • b) Comprobar que un nodeRef específico o los nodos de una transacción específica están en el índice.
  • c) Reindexar desde un punto concreto hacia delante.
  • d) Comprobar el estado de sincronización de los índices entre transacciones y identificadores.
Bueno, esto ha sido todo, seguro que se quedan muchas cosas en el tintero pero espero que estos tips os resulten útiles e interesantes.

8 thoughts to “Algunos apuntes sobre Lucene en el mundo de Alfresco”

  1. Hola, muy buen articulo.

    Con respecto al tiempo que tardan las transformaciones a texto para realizar la indexación del contenido, una cosa curiosa es que cuando heredas de la clase “org.alfresco.repo.content.transform.AbstractContentTransformer2” para crear un transformador esta clase va realizando un calculo de la media de ejecución del transformador (este valor se pierde al reiniciar Alfresco), este valor es el pasado al manejador de indexación para que decida si se ejecuta el transformador en segundo plano o no. Bueno hasta allí bien sin embargo, si se sube un contenido desde Share y se contenido lanza un transformador con una media de ejecución menor a 30 segundos la subida termina con un mensaje de error. El mensaje da a entender que el contenido no se pudo subir, pero es falso el contenido se sube correctamente, lo que ocurre es que la indexación del contenido se ejecuta en segundo plano. Por eso mi recomendación es que si se crea un transformador que se sabe que puede tardar mucho (un transformador que utilice un OCR) se sobreescriba el método “getTransformationTime” para que retorne un valor superior a 30 segundos.

    Bueno este mi grano de arena, espero que le sirva alguien.

  2. Hola Toni,

    Mi pequeño aporte es acerca de los analizadores a los que te refieres brevemente en el punto 2º, es uno de los puntos que mas confusión crean ya que al usar el interfaz web en un idioma (digamos en español) cuando subes un documento en inglés este no es reconocido como inglés y sera analizado con el analizador español (en nuestro caso spanish snowball). Y cuando realices una búsqueda de un termino en el contenido del fichero se indexara con el analizador en español.

    Echadle un ojo a vuestra configuracion en webapps\alfresco\WEB-INF\classes\alfresco\model\dataTypeAnalyzers_es.properties

    sera algo como esto:

    d_dictionary.datatype.d_text.analyzer=org.alfresco.repo.search.impl.lucene.analysis.SpanishSnowballAnalyser
    d_dictionary.datatype.d_content.analyzer=org.alfresco.repo.search.impl.lucene.analysis.SpanishSnowballAnalyser

    Podeis hacer la prueba de cambiar las lineas por esto:

    d_dictionary.datatype.d_text.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
    d_dictionary.datatype.d_content.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser

    Esto eliminara el “stemming” (acortado de palabras españolas o verbos españoles a la raiz del infinitivo) pero hara las busquedas un poco mas estrictas.

    Como dicen los yankies … ahi van mis dos centimos.

    Un saludo desde Maidenhead compi!

  3. Muchas gracias por el comentario Jesús. Has comentado ese comportamiento en el Jira? Puede ser interesante darlo de alta en issues.alfresco.com

    Saludos.

  4. Genial Antonio, muchas gracias por ampliar este punto. Así queda mas claro para todo el mundo y como dices suele ser algo que se pregunta mucho.

    Saludos!!

  5. Nosotros finalmente optamos por quitar todos los analizadores y dejar solo el estandar de Alfresco. Pierdes algunas cosillas pero por lo menos el comportamiento es predecible, sino no hay quien se aclare porque el documento se indexa en el idioma en el que se sube pero este no tiene por que ser el lenguaje del documento. Ademas cuando lo subes vía Ftp se utiliza el lenguaje en el que se ejecuta Tomcat, etc… Un cristo

    Respecto a lo de la lentitud subiendo archivos lo que si he notado es que con muchos archivos muy pequeños el ritmo de subida que se logra es bastante malo debido a que parece que Alfresco provoca un patrón de escritura a disco que hace que la Cpu este todo el rato esperando a la E/S. ¿Será Lucene quien cause estos lags entre fichero y fichero? En sistemas normalitos que pueden escribir a 5MB/s la cosa ouede caer con ficheris pequeños hasta los 400KB/s.

  6. Hola Toni, cómo siempre que tengo un problema, encuentro algún artículo tuyo, menos mal.

    Estoy teniendo un problema con los indices de lucene también y mi duda es si hay qué hacer algo más que poner el valor que necesitemos, por ejemplo AUTO, en la variable “index.recovery.mode=” del alfresco-global.properties y reiniciar Alfresco para completar este proceso de recuperación de índices.

    Muchas gracias de antemano.
    Saludos. Angelmb.

  7. Si usas lucene es que usas una versión bastante antigua de Alfresco, te recomiendo que actualices. Y para reindexar debes ponerlo en AUTO pero borrar los indices existentes para que se regeneren, ojo, si tienes un contentstore y DB muy grandes, tardará mucho y puede dejarte el sistema inservible durante horas.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.