Red de conocimiento informático - Material del sitio web - Cómo construir un motor de búsqueda usando Node.js y Elasticsearch

Cómo construir un motor de búsqueda usando Node.js y Elasticsearch

Instalación de Elasticsearch

Elasticsearch está cubierto por la licencia Apache 2 y se puede descargar, usar y modificar de forma gratuita. Antes de instalar Elasticsearch, debe asegurarse de que Java Runtime Environment (JRE) esté instalado en su computadora. Elasticsearch se implementa en Java y requiere bibliotecas de Java para ejecutarse. Puede comprobar si Java está instalado utilizando la siguiente línea de comando

. Se recomienda utilizar la última versión estable de Java (1.8 en el momento de escribir este artículo). Puede encontrar instrucciones para instalar Java en su sistema en la siguiente URL.

El siguiente paso es descargar la última versión de Elasticsearch (2.3.5 en el momento de escribir este artículo) y abrir el archivo zip. Elasticsearch no requiere instalación y un único archivo zip contiene archivos que se ejecutan en todos los sistemas compatibles. Descomprime el archivo descargado y listo. Hay varias otras formas de ejecutar Elasticsearch, como obtener archivos o paquetes TAR para diferentes distribuciones de Linux.

Si estás utilizando un sistema operativo Mac y lo tienes instalado, Homebrew agregará automáticamente el archivo ejecutable al sistema e instalará los servicios requeridos. Homebrew agregará automáticamente el ejecutable al sistema e instalará los servicios necesarios.

Para ejecutar Elasticsearch en Windows, puede ejecutar el comando bin\elasticsearch.bat desde la línea de comando en la carpeta descomprimida. Para otros sistemas, puede ejecutar ./bin/elasticsearch. En este punto, Elasticsearch debería estar ejecutándose en su sistema.

Como mencioné antes, puedes hacer casi cualquier cosa con Elasticsearch a través de la API RESTful. Para asegurarse de que está ejecutando Elasticsearch correctamente, ábralo en su navegador. Abra http://localhost:9200/ en el navegador y se mostrará información básica sobre la instancia en ejecución.

Interfaz gráfica de usuario

Elasticsearch no requiere una GUI, proporciona casi todas las funciones a través de una API REST. Sin embargo, si no cubrí cómo realizar todas las operaciones necesarias a través de API y Node.js, puedes realizar estas operaciones a través de varias herramientas GUI que brindan información visual sobre el índice y los datos, e incluso incluyen algunos análisis avanzados.

Kibana es una herramienta desarrollada por la misma empresa que proporciona resúmenes de datos en tiempo real con algunas opciones de personalización y análisis de visualización.

También hay herramientas desarrolladas por la comunidad como...,...e incluso extensiones del navegador Google Chrome. Estas herramientas lo ayudan a ver su índice y datos en un navegador e incluso probar diferentes consultas de búsqueda y agregación. Todas estas herramientas proporcionan instrucciones de instalación y uso.

Crear un entorno Node.js

Elasticsearch proporciona un módulo oficial llamado elasticsearch para Node.js. Primero, debe agregar el módulo al directorio de su proyecto y guardar las dependencias para su uso posterior.

Luego puede importar el módulo en su script de la siguiente manera:

Finalmente, necesita crear el cliente para manejar la comunicación con elasticsearch.

En este ejemplo, supongo que su computadora local que ejecuta Elastic Search tiene una dirección IP 127.0.0.1 y un puerto 9200 (la configuración predeterminada).

Nota: Todo el código fuente de esta guía se puede descargar y ver en GitHub. La forma más sencilla de verlos es clonar el repositorio en su PC y ejecutar el código de ejemplo en él:

Importación de datos

En este tutorial usaré el contenido del artículo. se genera uno por uno según un algoritmo aleatorio y se proporciona en formato JSON. El formato de datos es el siguiente:

Cada campo en formato JSON es coherente con el significado literal y no requiere explicación, pero. Vale la pena tener en cuenta que el contiene todo el contenido del artículo generado aleatoriamente (aproximadamente de 100 a 200 párrafos) y, por lo tanto, no se muestra.

Aunque Elasticsearch proporciona una forma de importar datos individuales, utilizamos interfaces para importar datos porque las interfaces por lotes son más eficientes cuando se opera con grandes conjuntos de datos.

Aquí llamamos a la función BulkIndex para crear el índice y pasarle tres parámetros: biblioteca de nombres de índice, biblioteca de nombres de tipo y artículo de variable de formato de datos JSON. La primera entidad es un objeto de tipo de operación con formato JSON, donde las propiedades del índice determinan el tipo de operación (en este caso, un índice de archivo), el nombre del índice y el ID del archivo, y la segunda entidad es el objeto de archivo en sí.

Tenga en cuenta que posteriormente podrá indexar otros tipos de archivos (como libros o informes) utilizando el mismo método. También podemos optar por asignar una ID única a cada archivo o, si no necesitamos una ID única, Elasticsearch asignará de forma proactiva una ID única aleatoria a cada archivo.

Suponiendo que haya descargado el código del proyecto Elasticsearch del repositorio, puede importar los datos al proyecto Elasticsearch ejecutando el siguiente comando en el directorio raíz del proyecto Elasticsearch:

Inspeccionar los datos Si se ha indexado con precisión

La característica más importante de Elasticsearch es la recuperación casi en tiempo real, lo que significa que una vez que el documento está indexado, se puede recuperar en menos de 1 segundo (ver). Una vez creado el índice, puede verificar la precisión de la información del índice ejecutando index.js():

El método del objeto cat en el cliente proporciona diversa información sobre la instancia que se está ejecutando actualmente. El método de índices enumera todos los índices, incluido el estado de salud de cada índice y el tamaño de su huella en el disco. La opción v agrega una respuesta de encabezado al método cat.

Cuando ejecute el fragmento de código anterior, verá el estado de salud del clúster marcado en diferentes colores. El rojo significa que el clúster se está ejecutando normalmente, pero hay problemas; el amarillo significa que el clúster se está ejecutando, pero hay alertas; el verde significa que el clúster se está ejecutando normalmente. Al ejecutar el fragmento anterior localmente, lo más probable es que (dependiendo de su configuración) vea el color amarillo del estado de salud del clúster, esto se debe a que la configuración predeterminada del clúster contiene 5 nodos pero solo 1 instancia está activa y ejecutándose cuando se ejecuta localmente. Dado que el propósito de este tutorial se limita al aprendizaje guiado de Elasticsearch, el amarillo está bien. Sin embargo, en un entorno en línea, debe asegurarse de que el color del estado de salud del clúster sea verde.

Asignaciones dinámicas y personalizadas

Como se mencionó anteriormente, Elasticsearch no tiene esquema, lo que significa que no necesita definir la estructura de sus datos antes de importarlos (similar a cómo las bases de datos SQL requieren Defina la estructura de la tabla), y Elasticsearch lo detecta de forma proactiva. Aunque Elasticsearch se define como sin esquema, existen algunas limitaciones cuando se trata de estructuras de datos.

Elasticsearch hace referencia a estructuras de datos como mapas.

Al indexar datos, si no existe ninguna asignación, Elasticsearch recupera cada campo de los datos JSON por turno y genera automáticamente una asignación basada en el tipo de campo al que se hace referencia. Si hay una asignación para el campo, garantizará que los datos se agreguen de acuerdo con las mismas reglas de asignación. De lo contrario, el error se informará directamente.

Por ejemplo, si {"key1":12} ya existe, Elasticsearch asignará automáticamente el campo key1 a un entero largo. Ahora, si intenta pasar {"key1":"value1", "key2":"value2"}, obtendrá un error porque el sistema espera que el campo key1 sea un número entero largo. Al mismo tiempo, si pasa {"key1": 13, "key2": "value2"}, no se informará ningún error y se agregará un nuevo tipo de cadena al campo key2.

Las asignaciones no deben extenderse más allá del texto; las asignaciones generadas automáticamente funcionarán bien en la mayoría de los casos.

Construyendo el motor de búsqueda

Una vez indexados los datos, podemos empezar a implementar el motor de búsqueda. Elasticsearch proporciona una estructura intuitiva basada en JSON para consultas de búsqueda completas (la consulta DSL) que define la consulta. Hay muchos tipos de consultas de búsqueda útiles, pero en este artículo solo veremos algunos tipos comunes. Consulte el artículo completo sobre cómo consultar DSL.

Recuerde que proporciono enlaces de código fuente para cada ejemplo. Una vez que haya configurado su entorno e indexado sus datos de prueba, puede ejecutar cualquiera de los ejemplos en su máquina descargando el código fuente y ejecutándolo. Puede ejecutar el nodo filename.js desde la línea de comando.

Devuelve todos los registros de uno o más índices

Para realizar la búsqueda utilizaremos los distintos métodos de búsqueda proporcionados por el cliente. La consulta más sencilla es match_all, que devuelve todos los registros en uno o más índices. El siguiente ejemplo muestra cómo podemos almacenar todos los registros en index().

La consulta de búsqueda principal está contenida en el objeto de consulta. Como veremos a continuación, podemos agregar diferentes tipos de consultas de búsqueda a este objeto. Podemos agregar una palabra clave de tipo de consulta (como match_all) a cada Consulta para convertir la Consulta en un objeto que contenga opciones de búsqueda. Como queremos devolver todas las filas del índice, no hay opciones de consulta en este ejemplo.

Además del objeto de consulta, el cuerpo de búsqueda también puede contener propiedades para otras opciones, como tamaño y desde. Si el valor no existe, se devuelven 10 registros de forma predeterminada. El atributo from determina el índice inicial de los registros devueltos, lo cual es útil para la paginación.

Comprensión de los resultados de retorno de la API de búsqueda

Si imprime el registro de resultados de retorno de la API de búsqueda (los resultados en el ejemplo anterior). Debido a que hay tanta información, al principio puede parecer abrumador.

En la salida del registro de nivel superior, el resultado devuelto contiene el atributo tok, cuyo valor representa el número de milisegundos que tomó encontrar el resultado. timed_out es verdadero solo si el resultado no se encuentra dentro del máximo; tiempo permitido; _shards es la información del estado de diferentes nodos (si se implementa como un grupo de nodos, son los resultados de la consulta);

El valor del atributo de visitas es un objeto que contiene los siguientes atributos:

total: representa el número total de entradas coincidentes

max_score: la puntuación máxima del entradas encontradas

p>

visitas: conjunto de entradas encontradas. Una matriz de entradas que contiene el índice, tipo, documento, ID, puntuación y el registro en sí (en el elemento _source) para cada día en la matriz de visitas.

Es muy complicado, pero la buena noticia es que una vez que implementas un método para extraer los resultados, puedes usar el mismo formato para obtener los resultados sin importar cuáles sean los resultados de tu consulta de búsqueda.

También es importante tener en cuenta que una de las ventajas de Elasticsearch es que asigna automáticamente a cada resultado una puntuación que cuantifica la relevancia del archivo y devuelve los resultados en orden inverso a la puntuación predeterminada del botón. En nuestro ejemplo, donde se utiliza match_all para recuperar todos los registros, las puntuaciones no tienen sentido y todas las puntuaciones se evalúan como 1,0.

Coincidencia de documentos utilizando valores de campo especificados

Ahora, veamos algunos ejemplos más interesantes. Podemos usar la palabra clave match para consultar si un documento coincide con un valor de campo específico. El código más simple para recuperar el cuerpo usando la palabra clave match es el siguiente:

Como se mencionó anteriormente, primero agregue una nueva entrada en el objeto de consulta y especifique el tipo de recuperación. En el ejemplo anterior, el tipo de recuperación que debe coincidir. Luego declare el objeto de documento que se recuperará dentro del objeto de tipo de recuperación, en este caso el objeto de documento de título. Luego proporcione datos de recuperación relevantes y propiedades de consulta en el objeto del documento. Con suerte, cuando pruebe los ejemplos anteriores, se sorprenderá de lo eficiente que puede ser Elasticsearch.

Cuando se ejecuta correctamente, el ejemplo anterior devolverá todos los documentos cuyo campo de título coincida con cualquiera de las condiciones del atributo de consulta. También puede consultar el siguiente ejemplo para agregar una condición de número mínimo de coincidencias a su consulta:

Los documentos que coinciden con la consulta tienen campos de título que contienen al menos 3 de las palabras clave especificadas en la apelación. Si la consulta contiene menos de 3 palabras clave, el campo de título del documento coincidente debe contener todos los términos de la consulta. Otra característica útil de Elasticsearch es la borrosidad. Esto es útil si el usuario ingresa el término de consulta incorrecto, ya que Fuzzy detectará el error ortográfico y le dará al usuario la palabra más cercana para elegir. Para los tipos de cadena, el valor de concordancia aproximada de cada palabra clave se calcula según el algoritmo para calcular el valor máximo permitido. Un ejemplo de una coincidencia aproximada se ve así:

Búsqueda multicampo

Si desea buscar en varios campos, puede utilizar el tipo de búsqueda multi_match. Es algo similar a coincidir excepto que el atributo de campo en el objeto de consulta es la colección de campos a buscar. Aquí buscaremos en los campos Título, Nombre del autor y Nombre del autor.

La consulta multi_match admite propiedades de búsqueda adicionales como minimal_should_match y fuzziness. Elasticsearch admite campos coincidentes que utilizan comodines (como *), por lo que podemos acortar el ejemplo anterior usando ['título', 'autores.*nombre'].

Relacionar una oración completa

Elasticsearch también admite la comparación exacta de una oración de entrada, en lugar de hacerlo a nivel de palabra. A continuación se muestra un ejemplo de match_phrase

Combinación de varias consultas

Hasta ahora solo hemos utilizado una consulta por solicitud en nuestros ejemplos. Sin embargo, Elasticsearch le permite combinar múltiples consultas. La consulta compuesta más utilizada es bool, que acepta cuatro tipos de claves: must, must, must_not y filter. Como sugiere el nombre, los datos en los resultados de la consulta deben coincidir con la consulta en must y no deben coincidir con la consulta en must_not. Si algún dato coincide con la consulta en must, obtendrá una puntuación alta. Cada elemento mencionado puede aceptar múltiples consultas de búsqueda utilizando el formato de matriz de consultas.

A continuación, usaremos consultas bool y un nuevo tipo de consulta llamado query_string. Le permite escribir algunas consultas más avanzadas usando AND u OR. Además, hemos utilizado consultas de rango que nos permiten limitar un campo por un rango determinado.

En el ejemplo anterior, si la consulta devuelve datos en los que el nombre del autor contiene el término 1 o el apellido contiene el término 2 y el título contiene el término 3 y no se publicó en 2011, 2012 o 2013, y en Si el campo de texto contiene los datos de la oración dada, entonces la consulta recibirá una puntuación alta y se clasificará en la parte superior de los resultados (esto se debe a que la cláusula debería está incluida en la cláusula debería en la consulta coincidente) .

Filtrado, agregación y recomendaciones

Además de capacidades de búsqueda avanzada, Elasticsearch ofrece otras funciones. A continuación, veamos otras tres funciones más utilizadas.

Filtro

Quizás a menudo desee utilizar criterios específicos para condensar los resultados de la consulta. En los datos de nuestros artículos, digamos que su consulta devuelve varios artículos que seleccionó para publicarse en 5 años específicos. Sólo necesita filtrar los artículos que no cumplen con sus criterios de los resultados de búsqueda sin cambiar el orden de los resultados de la consulta.

La diferencia entre filtrar en la cláusula must de una consulta bool y la misma consulta es que el filtrado no afecta la puntuación de la búsqueda, mientras que una consulta must sí. Cuando los resultados de la consulta se devuelven y filtran utilizando criterios determinados, el usuario no desea cambiar el orden de los resultados, solo desea eliminar datos irrelevantes de los resultados. El formato de los filtros es el mismo que el de las búsquedas, pero generalmente los filtros se definen en campos con valores explícitos en lugar de en cadenas de texto. Elasticsearch recomienda agregar filtros mediante la cláusula de filtro bool de consultas compuestas.

Continuando con el ejemplo anterior, digamos que queremos limitar los resultados de búsqueda a artículos publicados entre 2011 y 2015. Para hacer esto, simplemente agregamos una consulta RANGO en la sección FILTRO de la consulta de búsqueda normal. Esto eliminará aquellos que no coincidan de los resultados. El siguiente es un ejemplo de una consulta de filtro

Agregación

El marco de agregación proporcionará varios datos y estadísticas agregados basados ​​en una única consulta de búsqueda. Los dos tipos principales de agregación son métrica y de bloque, donde la agregación de métricas rastreará una colección de documentos y calculará métricas, mientras que la agregación de bloques creará bloques, cada uno de los cuales está asociado con palabras clave y criterios de consulta de documentos. Ejemplos de agregaciones de métricas son promedio, mínimo, máximo, suma y recuento. Ejemplos de agregaciones fragmentadas incluyen rangos, rangos de fechas, histogramas y temas. Para obtener una descripción más detallada de los agregadores, consulte ?find.

Las agregaciones se pueden colocar en objetos agregados y los propios objetos agregados se colocan directamente en el cuerpo del objeto de búsqueda. En un objeto agregado, el usuario asigna a cada clave un nombre de agregador. El tipo de agregador y otras opciones deben usarse como valor de esta clave. A continuación, aprenderemos sobre dos tipos diferentes de agregadores, uno es un agregador de métricas y el otro es un agregador de bloques. Usaremos el agregador de métricas para intentar encontrar el valor de año más pequeño en el conjunto de datos (es decir, el artículo más antiguo), y con el agregador de bloques, todo lo que tengo que hacer es intentar encontrar la cantidad de veces que cada palabra clave aparece sola.

En el ejemplo anterior, denominamos al agregador de medidas min_year (u otro nombre), que es el tipo mínimo del campo año. El agregador de bloques se llama palabras clave y es el tipo de términos del campo de palabras clave. Los resultados de las operaciones de agregación están contenidos en el elemento de agregación del mensaje de respuesta, y si profundiza un poco más, encontrará que contiene los resultados de cada agregador (en este caso, min_year y palabras clave) y su operación de agregación. . Lo siguiente es parte del mensaje de respuesta en este ejemplo.

De forma predeterminada, se devuelven un máximo de 10 fragmentos de datos en el mensaje de respuesta. Puede especificar la cantidad máxima de fragmentos a devolver agregando una clave de tamaño en el lado de envío de la solicitud.

Recomendaciones

Elasticsearch proporciona varios recomendadores de términos asociados que proporcionan reemplazo y finalización de entradas (ver ). A continuación se presentan recomendadores de términos y frases.

El recomendador de términos proporciona recomendaciones asociadas para cada término en el texto de entrada (si corresponde), mientras que el recomendador de frases trata todo el texto de entrada como una frase (en lugar de dividirlo en términos) y luego proporciona recomendaciones para otras frases (si las hay). recomendaciones. Para utilizar la API de recomendación, debe llamar al método de sugerencia del cliente Node.js. A continuación se muestra un ejemplo de un recomendador de términos.

Al igual que con otros métodos de cliente, incluya un campo de índice en el cuerpo de la solicitud que indique el índice a utilizar. El texto recomendado por la consulta se agregará al campo del cuerpo y a cada recomendador se le asignará un nombre (que contiene el objeto agregado) (en este caso, titleSuggester). Su valor especifica el tipo y la configuración del recomendador. Aquí, el campo de título utiliza el término recomendador y el número máximo de recomendaciones por etiqueta está limitado a 5 (tamaño: 5).

Los datos devueltos por la API de Recomendaciones contienen la clave para cada recomendador en la solicitud correspondiente, y su valor es una matriz que consta de la misma cantidad de términos que en el texto que ingresó. Cada elemento de la matriz contiene una serie de opciones y el campo de texto de cada objeto contiene texto recomendado. Estos son algunos de los datos devueltos en el ejemplo anterior.

Para obtener recomendaciones de frases, simplemente utilice el mismo formato anterior y reemplace el campo Tipo de recomendador. En el siguiente ejemplo, los datos devueltos tienen el mismo formato que el ejemplo anterior.