Motor de búsqueda Lucene (4): el proceso de creación de un índice
El proceso de creación de un índice es el siguiente:
La estructura del índice es la siguiente:
La estructura de IndexWriter:
IndexWriter es el almacenamiento del directorio de índice especificado para construir. Directorio) y analizador de documentos para construir, el directorio representa la ubicación del almacenamiento del índice; el analizador representa cómo analizar el contenido del documento; la similitud se usa para estandarizar documentos y calificar documentos. También se utilizan algunos objetos SegmentInfos en la clase IndexWriter; almacenar en la clase IndexWriter También hay algunos objetos SegmentInfos que se utilizan para almacenar información del segmento de índice, fallas de reversión y otra información.
Utilice el método addDocument() para agregar un documento, utilice el método deleteDocuments(Term) o deleteDocuments(Query) para eliminar un documento y utilice el método updateDocument() para actualizar un documento (simplemente elimine mientras realizar la operación de adición). Cuando haya terminado de agregar, eliminar o actualizar documentos, se debe llamar al método close.
Estos cambios se almacenan en la memoria y se descargan periódicamente en el directorio (durante la llamada al método anterior). Se activa una actualización cuando ha habido suficientes eliminaciones de caché (consulte setMaxBufferedDeleteTerms(int)) o suficientes documentos nuevos (consulte setMaxBufferedDocs(int)) desde la última operación de actualización, lo que ocurra primero. Para los documentos agregados, el tamaño del búfer de RAM del documento (setRAMBufferSizeMB) o la cantidad de documentos agregados activarán una actualización; el uso máximo de RAM predeterminado es 16 M, por lo que se debe usar un tamaño de búfer de RAM mayor para maximizar el índice de utilización. Cabe señalar que el proceso de vaciado solo mueve el estado del búfer interno en IndexWriter al índice, pero IndexReader no puede ver estos cambios hasta que se llamen a los métodos commit() y close(). La actualización puede desencadenar una o más fusiones de segmentos, lo que inicia un subproceso en segundo plano para procesarlos de modo que no interrumpan las llamadas a addDocument. Consulte MergeScheduler. Cualquier mensaje de confirmación enviado al índice después de su apertura no se verá hasta que se vuelva a abrir el índice.
Estructura de DocumentsWriter:
DocumentsWriter es una clase llamada por IndexWriter para procesar múltiples documentos. Funciona con la clase Directory, la clase Analyzer y la clase Scorer para extraer y descomponer el contenido del documento en A. conjunto de documentos. Extrae el contenido del documento trabajando con la clase Directorio y la clase Analizador, la clase Anotador, etc., lo divide en un conjunto de listas de términos y luego genera los archivos de datos necesarios para la segmentación individual, como la frecuencia y la posición de los términos. , vector de términos y otros archivos de índice para que SegmentMerger pueda fusionarlos en un segmento unificado.
Esta clase recibe múltiples documentos agregados y los escribe directamente en un único archivo segmentado. Esto es más eficiente que crear un segmento para cada documento (usando un DocumentWriter) y realizar coprocesamiento en esos segmentos.
Cada documento agregado se pasa a la clase DocConsumer, que procesa el documento e interactúa con otros consumidores en la cadena de índice. Los consumidores decididos (como StoredFieldWriter y TermVectorsTermsWriter) extraerán el resumen del documento e inmediatamente escribirán los bytes en el archivo "Document Store" (es decir, no consumen memoria RAM para cada documento).
Otros consumidores, como FreqProxTermsWriter y NormsWriter, almacenan bytes en caché en la memoria y solo los vacían en el disco cuando se crea un nuevo segmento.
Una vez que agotamos la caché de RAM asignada, o agregamos una cantidad suficiente de documentos (y luego los vaciamos según la cantidad de documentos agregados en lugar del uso de RAM), creamos un segmento real y lo escribimos. .
Cómo llamar a la creación de índices:
El objeto Directorio es una lista plana de archivos. Solo se puede escribir en un archivo una vez cuando se crea. Una vez creado, solo se puede volver a abrir para leerlo o eliminarlo. Se permite el acceso aleatorio tanto para lectura como para escritura.
La clase FSDirectory implementa directamente la clase abstracta Directorio como un directorio que contiene archivos. Los bloqueos de directorio utilizan la implementación predeterminada SimpleFSLockFactory, pero se pueden modificar de dos maneras: pasando una instancia de LockFactory a getLockFactory() o promulgando explícitamente la clase LockFactory llamando al método setLockFactory().
El directorio se almacenará en caché y el método getDirectory() normalmente devolverá la misma instancia de FSDirectory para una ruta canónica determinada. Esto permite la sincronización de directorios.
La clase RAMDirectory es una implementación de la clase abstracta del directorio residente en memoria. La implementación del bloqueo de directorio utiliza el SingleInstanceLockFactory predeterminado, pero se puede modificar mediante el método setLockFactory().
La clase IndexInput es una clase base abstracta diseñada para leer archivos de directorios y es un flujo de entrada de acceso aleatorio utilizado para todas las operaciones de Lucene que leen índices.
La clase IndexOutput es una clase base abstracta para escribir archivos en directorios y es el flujo de salida de acceso aleatorio utilizado para todas las operaciones de Lucene que escriben en índices. BufferedIndexOutput es una implementación básica de IndexOutput con capacidades de almacenamiento en búfer. RAMOuputStream es una clase de implementación de IndexOutput residente en memoria.
La opción de índice de campo controla si se puede buscar texto a través de un índice invertido.
Cuando lucene crea un índice invertido, de forma predeterminada guarda toda la información necesaria para implementar un modelo de espacio vectorial, que cuenta el número de términos que aparecen en un documento y las posiciones del texto en las que aparecen esos términos ( por ejemplo, en Esto es necesario cuando se busca por frase). Pero a veces estos campos solo se usan para búsquedas booleanas y no contribuyen a la puntuación relevante. Un ejemplo común es que estos campos solo se usan como filtros, como filtros de permisos y filtros de fechas. En este caso, puede hacer que Lucene omita la indexación de la frecuencia y la posición de las opciones modificadas llamando al método Field.setOmitTermFreqAndPositions(true). Este método ahorra algo de espacio de almacenamiento en disco para el índice y puede acelerar el proceso de búsqueda y filtrado, pero bloquea silenciosamente las búsquedas que requieren información de ubicación, como impedir que se ejecuten las clases PhraseQuery y SpanQuery.
La opción de almacenamiento de campos determina si es necesario almacenar el valor real del campo para que búsquedas posteriores puedan restaurar ese valor.
Lucene admite intentar escribir varios valores diferentes en un campo.
Este enfoque es completamente aceptable y recomendable porque es la forma natural de representar un dominio que lógicamente tiene múltiples valores de dominio. En Lucene, siempre que haya varios valores de campo con el mismo nombre en el documento, el índice invertido y el vector de términos agregarán lógicamente las unidades de expresión en el orden en que se agregan los campos.
La ponderación de documentos y dominios se puede realizar durante el proceso de indexación. La operación de ponderación durante la búsqueda será más dinámica, porque cada búsqueda puede elegir de forma independiente si se pondera o no en función de diferentes factores de ponderación, pero esta estrategia también consumirá más eficiencia de la CPU. La ponderación dinámica durante el proceso de búsqueda se puede controlar de forma más flexible.
De forma predeterminada, todos los documentos tienen un factor de ponderación de 1,0, pero al cambiar el factor de ponderación de un documento, puede afectar la importancia de ese documento en el índice. La API para ajustar la operación de ponderación es: setBoost(float);
Al igual que con la ponderación de documentos, puede realizar operaciones de ponderación en los documentos. Al ponderar un documento, Lucene ponderará los campos del documento utilizando el mismo factor de ponderación. API de ponderación de campos: Field.setBoost(fliat).
La clase de analizador construye un objeto TokenStream utilizado para analizar texto y, por lo tanto, representa una estrategia para extraer términos de índice del texto. Una implementación típica es crear primero un Tokenizer que descomponga el flujo de caracteres leído del objeto lector en Tokens sin formato. Luego se pueden aplicar uno o más TokenFilters a la salida del Tokenizer. Advertencia: debe anular un método definido en esta clase en una subclase; de lo contrario, el analizador entrará en un bucle infinito.
StandardAnalyzer:
La clase StandardAnalyzer utiliza la clase StandardTokenizer, los filtros StandardFilter y LowerCaseFilter y StopFilter para tokenizar palabras en el texto y utiliza una lista de palabras vacías en inglés.