TigerZF
🌐Español

61.3. Búsqueda en un índice

61.3.1. Construcción de consultas

Hay dos formas de buscar en el índice. El primer método utiliza el analizador de consultas para construir una consulta a partir de una cadena. El segundo consiste en crear sus propias consultas de forma programática a través de la API de Zend_Search_Lucene.

Antes de decidir usar el analizador de consultas proporcionado, considere lo siguiente:

  1. Si está creando una cadena de consulta de forma programática y luego la analiza con el analizador de consultas, debería considerar construir sus consultas directamente con la API de consultas. En términos generales, el analizador de consultas está diseñado para texto introducido por personas, no para texto generado por programas.

  2. Los campos no tokenizados se agregan mejor directamente a las consultas y no a través del analizador de consultas. Si los valores de un campo son generados de forma programática por la aplicación, entonces las cláusulas de consulta para ese campo también deberían construirse de forma programática. Un analizador, que es utilizado por el analizador de consultas, está diseñado para convertir texto introducido por personas en términos. Los valores generados por programas, como fechas, palabras clave, etc., deberían agregarse con la API de consultas.

  3. En un formulario de consulta, los campos que son texto general deberían usar el analizador de consultas. Todos los demás, como rangos de fechas, palabras clave, etc., se agregan mejor directamente a través de la API de consultas. Un campo con un conjunto limitado de valores que pueda especificarse mediante un menú desplegable no debería agregarse a una cadena de consulta que se analice posteriormente, sino que debería agregarse como una cláusula TermQuery.

  4. Las consultas booleanas permiten al programador combinar lógicamente dos o más consultas en una nueva. Por lo tanto, es la mejor forma de agregar criterios adicionales a una búsqueda definida por una cadena de consulta.

Ambas formas usan el mismo método de la API para buscar en el índice:

$index = Zend_Search_Lucene::open('/data/my_index');

$index->find($query);

También puede buscar en varios índices simultáneamente usando MultiSearcher, que funciona usando la misma API que la búsqueda en un solo índice:

$multi = new Zend_Search_Lucene_MultiSearcher();
$multi->addIndex(Zend_Search_Lucene::open('/data/my_index_one');
$multi->addIndex(Zend_Search_Lucene::open('/data/my_index_two');

$multi->find($query);

El método Zend_Search_Lucene::find() determina el tipo de entrada automáticamente y utiliza el analizador de consultas para construir un objeto Zend_Search_Lucene_Search_Query adecuado a partir de una entrada de tipo string.

Es importante señalar que el analizador de consultas utiliza el analizador estándar para tokenizar partes separadas de la cadena de consulta. Por lo tanto, todas las transformaciones que se aplican al texto indexado también se aplican a las cadenas de consulta.

El analizador estándar puede transformar la cadena de consulta a minúsculas para insensibilidad a mayúsculas y minúsculas, eliminar palabras vacías, y aplicar stemming, entre otras transformaciones.

El método de la API no transforma ni filtra los términos de entrada de ninguna forma. Por lo tanto, es más adecuado para campos generados por computadora o no tokenizados.

61.3.1.1. Análisis de consultas

El método Zend_Search_Lucene_Search_QueryParser::parse() puede usarse para analizar cadenas de consulta y convertirlas en objetos de consulta.

Este objeto de consulta puede usarse en los métodos de la API de construcción de consultas para combinar consultas introducidas por el usuario con consultas generadas de forma programática.

De hecho, en algunos casos es la única forma de buscar valores dentro de campos no tokenizados:

$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);

$pathTerm  = new Zend_Search_Lucene_Index_Term(
                     '/data/doc_dir/' . $filename, 'path'
                 );
$pathQuery = new Zend_Search_Lucene_Search_Query_Term($pathTerm);

$query = new Zend_Search_Lucene_Search_Query_Boolean();
$query->addSubquery($userQuery, true /* required */);
$query->addSubquery($pathQuery, true /* required */);

$hits = $index->find($query);

El método Zend_Search_Lucene_Search_QueryParser::parse() también acepta un parámetro opcional de codificación, que puede especificar la codificación de la cadena de consulta:

$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr,
                                                          'iso-8859-5');

Si se omite el parámetro de codificación, se utiliza la configuración regional actual.

También es posible especificar la codificación de cadena de consulta predeterminada con el método Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding():

Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-5');
...
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);

Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding() devuelve la codificación de cadena de consulta predeterminada actual (la cadena vacía significa "configuración regional actual").

61.3.2. Resultados de búsqueda

El resultado de la búsqueda es un array de objetos Zend_Search_Lucene_Search_QueryHit. Cada uno de estos tiene dos propiedades: $hit->id es un número de documento dentro del índice y $hit->score es la puntuación del resultado en un resultado de búsqueda. Los resultados están ordenados por puntuación (descendente desde la puntuación más alta).

El objeto Zend_Search_Lucene_Search_QueryHit también expone cada campo del Zend_Search_Lucene_Document encontrado en la búsqueda como una propiedad del resultado. En el siguiente ejemplo, se devuelve un resultado con dos campos del documento correspondiente: title y author.

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index->find($query);

foreach ($hits as $hit) {
    echo $hit->score;
    echo $hit->title;
    echo $hit->author;
}

Los campos almacenados siempre se devuelven en codificación UTF-8.

Opcionalmente, el objeto original Zend_Search_Lucene_Document puede devolverse desde el Zend_Search_Lucene_Search_QueryHit. Puede recuperar las partes almacenadas del documento usando el método getDocument() del objeto índice y luego obtenerlas mediante el método getFieldValue():

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index->find($query);
foreach ($hits as $hit) {
    // return Zend_Search_Lucene_Document object for this hit
    echo $document = $hit->getDocument();

    // return a Zend_Search_Lucene_Field object
    // from the Zend_Search_Lucene_Document
    echo $document->getField('title');

    // return the string value of the Zend_Search_Lucene_Field object
    echo $document->getFieldValue('title');

    // same as getFieldValue()
    echo $document->title;
}

Los campos disponibles desde el objeto Zend_Search_Lucene_Document se determinan en el momento de la indexación. Los campos del documento están indexados, o indexados y almacenados, en el documento por la aplicación de indexación (por ejemplo, LuceneIndexCreation.jar).

Tenga en cuenta que la identidad del documento ('path' en nuestro ejemplo) también se almacena en el índice y debe recuperarse de él.

61.3.3. Limitación del conjunto de resultados

La parte más costosa computacionalmente de la búsqueda es el cálculo de la puntuación. Puede tardar varios segundos para conjuntos de resultados grandes (decenas de miles de resultados).

Zend_Search_Lucene ofrece la posibilidad de limitar el tamaño del conjunto de resultados con los métodos getResultSetLimit() y setResultSetLimit():

$currentResultSetLimit = Zend_Search_Lucene::getResultSetLimit();

Zend_Search_Lucene::setResultSetLimit($newLimit);

El valor predeterminado de 0 significa 'sin límite'.

No proporciona los 'mejores N' resultados, sino solo los 'primeros N' [11].

61.3.4. Puntuación de resultados

Zend_Search_Lucene utiliza los mismos algoritmos de puntuación que Java Lucene. Todos los resultados en el resultado de búsqueda se ordenan por puntuación de forma predeterminada. Los resultados con mayor puntuación aparecen primero, y los documentos con puntuaciones más altas deberían coincidir con la consulta con más precisión que los documentos con puntuaciones más bajas.

En términos generales, los resultados de búsqueda que contienen el término o frase buscada con más frecuencia tendrán una puntuación más alta.

La puntuación de un resultado puede recuperarse accediendo a la propiedad score del resultado:

$hits = $index->find($query);

foreach ($hits as $hit) {
    echo $hit->id;
    echo $hit->score;
}

La clase Zend_Search_Lucene_Search_Similarity se utiliza para calcular la puntuación de cada resultado. Consulte la sección Extensibilidad. Algoritmos de puntuación para más detalles.

61.3.5. Ordenación de resultados de búsqueda

De forma predeterminada, los resultados de búsqueda se ordenan por puntuación. El programador puede cambiar este comportamiento estableciendo un campo de ordenación (o una lista de campos), tipo de ordenación y orden de ordenación como parámetros.

La llamada a $index->find() puede aceptar varios parámetros opcionales:

$index->find($query [, $sortField [, $sortType [, $sortOrder]]]
                    [, $sortField2 [, $sortType [, $sortOrder]]]
             ...);

Un nombre de campo almacenado por el cual ordenar el resultado debe pasarse como el parámetro $sortField.

$sortType puede omitirse o tomar los siguientes valores enumerados: SORT_REGULAR (comparar los elementos normalmente, valor predeterminado), SORT_NUMERIC (comparar los elementos numéricamente), SORT_STRING (comparar los elementos como cadenas).

$sortOrder puede omitirse o tomar los siguientes valores enumerados: SORT_ASC (ordenar en orden ascendente, valor predeterminado), SORT_DESC (ordenar en orden descendente).

Ejemplos:

$index->find($query, 'quantity', SORT_NUMERIC, SORT_DESC);
$index->find($query, 'fname', SORT_STRING, 'lname', SORT_STRING);
$index->find($query, 'name', SORT_STRING, 'quantity', SORT_NUMERIC, SORT_DESC);

Utilice con precaución un orden de búsqueda que no sea el predeterminado; la consulta necesita recuperar documentos completamente desde un índice, lo que puede reducir drásticamente el rendimiento de la búsqueda.

61.3.6. Resaltado de resultados de búsqueda

Zend_Search_Lucene ofrece dos opciones para el resaltado de resultados de búsqueda.

La primera consiste en utilizar la clase Zend_Search_Lucene_Document_Html (consulte la sección Documentos HTML para más detalles) usando los siguientes métodos:

/**
 * Highlight text with specified color
 *
 * @param string|array $words
 * @param string $colour
 * @return string
 */
public function highlight($words, $colour = '#66ffff');
/**
 * Highlight text using specified View helper or callback function.
 *
 * @param string|array $words  Words to highlight. Words could be organized
                               using the array or string.
 * @param callback $callback   Callback method, used to transform
                               (highlighting) text.
 * @param array    $params     Array of additionall callback parameters passed
                               through into it (first non-optional parameter
                               is an HTML fragment for highlighting)
 * @return string
 * @throws Zend_Search_Lucene_Exception
 */
public function highlightExtended($words, $callback, $params = array())

Para personalizar el comportamiento del resaltado use el método highlightExtended() con una devolución de llamada específica, que acepta uno o más parámetros [12] , o extienda la clase Zend_Search_Lucene_Document_Html y redefina el método applyColour($stringToHighlight, $colour) usado como función de resaltado predeterminada. [13]

Los ayudantes de vista también pueden usarse como devoluciones de llamada en el contexto de un script de vista:

$doc->highlightExtended('word1 word2 word3...', array($this, 'myViewHelper'));

El resultado de la operación de resaltado se obtiene mediante el método Zend_Search_Lucene_Document_Html->getHTML().

[Note] Nota

El resaltado se realiza en función del analizador actual. Por lo tanto, se resaltan todas las formas de la(s) palabra(s) reconocidas por el analizador.

Por ejemplo, si el analizador actual no distingue entre mayúsculas y minúsculas y solicitamos resaltar la palabra 'text', entonces se resaltarán 'text', 'Text', 'TEXT' y otras combinaciones de mayúsculas y minúsculas.

De la misma forma, si el analizador actual admite stemming y solicitamos resaltar 'indexed', entonces se resaltarán 'index', 'indexing', 'indices' y otras formas de la palabra.

Por otro lado, si una palabra es omitida por el analizador actual (por ejemplo, si se aplica un filtro de palabras cortas al analizador), entonces no se resaltará nada.

La segunda opción es usar el método Zend_Search_Lucene_Search_Query->highlightMatches(string $inputHTML[, $defaultEncoding = 'UTF-8'[, Zend_Search_Lucene_Search_Highlighter_Interface $highlighter]]):

$query = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$highlightedHTML = $query->highlightMatches($sourceHTML);

El segundo parámetro opcional es una codificación de documento HTML predeterminada. Se utiliza si no se especifica la codificación mediante la etiqueta meta HTTP-EQUIV Content-type.

El tercer parámetro opcional es un objeto resaltador que debe implementar la interfaz Zend_Search_Lucene_Search_Highlighter_Interface:

interface Zend_Search_Lucene_Search_Highlighter_Interface
{
    /**
     * Set document for highlighting.
     *
     * @param Zend_Search_Lucene_Document_Html $document
     */
    public function setDocument(Zend_Search_Lucene_Document_Html $document);

    /**
     * Get document for highlighting.
     *
     * @return Zend_Search_Lucene_Document_Html $document
     */
    public function getDocument();

    /**
     * Highlight specified words (method is invoked once per subquery)
     *
     * @param string|array $words  Words to highlight. They could be
                                   organized using the array or string.
     */
    public function highlight($words);
}

Donde el objeto Zend_Search_Lucene_Document_Html es un objeto construido a partir del HTML de origen proporcionado al método Zend_Search_Lucene_Search_Query->highlightMatches().

Si se omite el parámetro $highlighter, entonces se instancia y utiliza un objeto Zend_Search_Lucene_Search_Highlighter_Default.

El método highlight() del resaltador se invoca una vez por subconsulta, por lo que tiene la capacidad de diferenciar el resaltado entre ellas.

De hecho, el resaltador predeterminado hace esto recorriendo una tabla de colores predefinida. Por lo tanto puede implementar su propio resaltador o simplemente extender el predeterminado y redefinir la tabla de colores.

Zend_Search_Lucene_Search_Query->htmlFragmentHighlightMatches() tiene un comportamiento similar. La única diferencia es que recibe como entrada y devuelve un fragmento HTML sin las etiquetas <>HTML>, <HEAD>, <BODY>. Sin embargo, el fragmento se transforma automáticamente en XHTML válido.



[11] Los resultados devueltos siguen ordenándose por puntuación o por el orden especificado, si se indicó alguno.

[12] El primero es un fragmento HTML para resaltar y los demás dependen del comportamiento de la devolución de llamada. El valor devuelto es un fragmento HTML resaltado.

[13] En ambos casos, el HTML devuelto se transforma automáticamente en XHTML válido.