Cómo implementar un buscador Elasticsearch

Este tutorial te explica cómo implementar un buscador Elasticsearch para indexar y mostrar el contenido de los artículos de tu sitio.

Publicado: Martes 26 de enero de 2021 por Adriano Varoli Piazza
Última modificación: Miercoles 10 de agosto de 2022

El buscador de Prontus Elasticsearch es un indexador y buscador de texto completo (full text) integrado a Prontus, que puede ser utilizado para buscar contenidos dentro de instancias de Prontus. El uso de este buscador requiere instalar el servicio elasticsearch en el servidor del sitio web, o disponer de un servidor elasticsearch asociado.

Para implementar la indexación y búsqueda con el buscador Prontus Elasticsearch debes seguir los siguientes pasos:

Configuración

Visita la página Administrar → Configuración → Elasticsearch.

Defines los parámetros básicos (Host, Protocolo, Puerto, Índice)

Si tienes problemas durante la indexación porque el contenido es muy complejo o denso, puedes intentar reducir los valores de las variables ELASTICSEARCH_BATCH_CHUNK y/o ELASTICSEARCH_MAXCARS.

Agrega los tipos de artículo que necesitas indexar en el panel "FIDS".

Define las variables Prontus a indexar, y la importancia relativa. Recuerda que el titular y bajada se indexarán siempre. La Potencia es un número entero entre 1 y 4, y a mayor valor, mayor relevancia tendrá ese campo para determinar el orden de los resultados de búsqueda. Para el ejemplo de la imagen, si un usuario buscara el término "elasticsearch", un artículo con la palabra "elasticsearch" en el campo autor tendría menos relevancia que otro artículo con esa palabra en el campo cuerpo.

Puedes definir además las variables ELASTICSEARCH_SEARCH_META para implementar filtros de búsqueda:

En este caso deberás especificar el nombre y tipo. Por ahora, la implementación cubre variables con formato numérico y de fecha/hora. Nota: la marca _fechap se  indexa para filtros siempre, no debes agregarla.

Puedes además definir una marca de imagen a usar en los resultados de búsqueda con la variable ELASTICSEARCH_METADATA_IMG. Si la defines, y los artículos contienen una imagen en esa marca, se desplegará en las búsquedas.

Además de la imagen, puedes especificar otras marcas Prontus a usar para mostrar en los resultados de búsqueda (pero no para filtrar o restringir las búsquedas) en las marcas ELASTICSEARCH_METADATA1 a 10.

Puedes implementar un sistema de promociones con la funcionalidad Artículos Promocionados.

El funcionamiento es el siguiente: si ingresas un término de búsqueda, y el timestamp de creación de un artículo específico, un usuario que busque ese término verá en primer lugar, y posiblemente destacado, el artículo con ese timestamp. Por ejemplo, si en Término 1 pusieras "elasticsearch" y en timestamp 1 pusieras "20210126122305" para este sitio, al buscar "elasticsearch" verías en primer lugar, promocionado, este artículo.

Editar plantillas de búsqueda

Es importante que exista (y en caso de que no, debes crearla) la plantilla de búsqueda en la cual se mostrará el resultado que la búsqueda arroje. La ubicación de las plantillas de busqueda es la siguiente:

/[prontus_id]/plantillas/extra/search_custom/pags/

Una vez allí debes editar el siguiente archivo: search.html

Ejemplo de código de plantilla de Buscador:


<!DOCTYPE HTML>
<html lang="es-CL">
<head>
    <meta charset="utf-8">
    <!-- inicio metatags-->
    <title>Mi Sitio</title>
    <!-- MSG server_busy = Servidor ocupado. Intente más tarde… -->
    <!-- MSG no_results = No se encontraron resultados. -->
    <!-- MSG order_cron = en orden cronológico. -->
    <!-- MSG order_rel = en orden de relevancia. -->
    <!-- MSG results = Resultados -->
    <!-- MSG to = al -->
    <!-- MSG of = de -->
    <meta charset="utf-8">
    <title>Buscador</title>
    <script src="/%%_prontus_id%%/js-local/jquery/jquery-1.7.1.min.js"></script>
    <script src="/%%_prontus_id%%/js-local/jquery-ui/jquery-ui.min.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_secc.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_tem.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_subtem.js"></script>
    <script src="/%%_prontus_id%%/js-local/Taxonomia.class.js"></script>
    <script src="/%%_prontus_id%%/js-local/jquery/plugins/datepicker/js/i18n/jquery.ui.datepicker-es.js"></script>
    <script>
        $(document).ready(function(){
                $('.fecha').datepicker({
                    dateFormat: 'dd/mm/yy',
                buttonImage: '/%%_prontus_id%%/js-local/jquery/plugins/datepicker/imag/calendar.gif',
                buttonImageOnly: true,
                showOn: 'both'
            });
            Taxonomia.init();
        });
    </script>


</head>

<body class="articulo">
    <!--HEADER-->
    <!--#include virtual="/%%_prontus_id%%/site/edic/base/port/_m_header.html"-->
    <!--/HEADER-->
    <!--CONTENIDO-->
    <div id="main" class="span-12 lg-12">
        <div class="auxi">
            <div class="row">
                <div class="col span-9 xs-12 sm-12 md-9 lg-9">
                    USTED ESTÁ EN:
                    <ul class="breadcrumbs">
                        <li><a href="/%%_prontus_id%%/site/edic/base/port/inicio.html">INICIO</a></li>
                        <li><a href="/%%_prontus_id%%/stat/search_custom/">BUSCADOR</a></li>
                    </ul>
                    <h1 class="titular">Buscador</h1>
                    <p class="bajada">Usted buscó por: "%%search_texto%%". %%resultados_totales%% resultados
                        encontrados. Mostrando resultados de %%start%% a %%end%%.<br>
                        <!--PAGS-->
                        <div class="paginas">Ver más en: %%pags%%</div>
                        <!--/PAGS-->
                        <span class="mensaje">%%msg%%</span>
                    </p>

                    <!--PROMOTED_LOOP-->
                    <div class="tax_box col esp span-4 xs-12 sm-4 md-4 lg-4">
                        <div class="content">
                            <h2>Promoted: 
                                <a href="%%link%%">%%titular%%</a>
                            </h2>
                            <p>%%descripcion%%…</p>
                        </div>
                    </div>
                    <!--/PROMOTED_LOOP-->

                    <!--RESULT_LOOP-->
                    <div class="tax_box col esp span-4 xs-12 sm-4 md-4 lg-4">
                        %%if(metadata_img)%%
                        <div class="img_cont">
                            <a href="%%link%%">
                                <img src="%%metadata_img%%" alt="" class="fullwidth">
                            </a>
                        </div>
                        %%/if%%
                        %%nif(metadata_img)%%
                        <div class="img_cont">
                            <a href="%%link%%">
                                <img src="/%%_prontus_id%%/imag/v1/default/default_870x515.jpg" alt=""
                                    class="fullwidth">
                            </a>
                        </div>
                        %%/nif%%
                        <div class="content">
                            <h2>
                                <a href="%%link%%">%%titular%%</a>
                            </h2>
                            <p>%%descripcion%%…</p></
                            %%if(metadata1)%%<p>Metadata 1: %%metadata1%%</p>%%/if%%
                            %%nif(metadata1)%%NO HAY METADATA1%%/nif%%

                            %%if(search_meta1)%%<p>Search_meta 1: %%search_meta1%%</p>%%/if%%
                            %%nif(search_meta1)%%NO HAY METASEARCH1%%/nif%%

                            %%if(metadata2)%%<p>Metadata 2: %%metadata2%%</p>%%/if%%
                            %%nif(metadata2)%%NO HAY METADATA2%%/nif%%

                            %%if(search_meta2)%%<p>Search_meta 2: %%search_meta2%%</p>%%/if%%
                            %%nif(search_meta2)%%NO HAY METASEARCH2%%/nif%%
                        </div>
                    </div>
                    <!--/RESULT_LOOP-->

                    <div class="separa"></div>
                </div>
                <div class="separa"></div>
            </div>
            <div class="separa"></div>
        </div>
    <!--/CONTENIDO-->
    <!--FOOTER-->
    <!--#include virtual="/%%_prontus_id%%/site/edic/base/port/_m_footer.html"-->
    <!--/FOOTER-->
</body>

</html>
 

En el  ejemplo cabe destacar

  • la variable %%msg%% en el área del resultado, la cual muestra la lista de archivos encontrados y links a otras páginas si la cantidad de resultados excede el máximo por página.
  • las marcas %%search_texto%%, %%resultados_totales%%, %%start%%, %%end%%, y %%pags%%, que permiten desplegar información sobre la búsqueda.
  • Los bloques PROMOTED_LOOP y RESULT_LOOP. Ambos serán procesados por Prontus al generar los resultados, y el primero contendrá, si aplica, los eventuales artículos promocionados. El segundo es el bloque de resultados generales.
  • En el bloque RESULT_LOOP puedes usar las marcas %%link%%, %%titular%%, %%descripcion%%, %%metadata_img%%, %%metadata[1/10]%% y %%search_meta[1/5]%%. Las marcas "metadata" contendrán los valores ingresados en la configuración más arriba, en ELASTICSEARCH_METADATA, y las marcas search_meta contendrán los valores ingresados en la configuración en el apartado ELASTICSEARCH_SEARCH_META.
Paginación Personalizada

Las siguientes marcas permiten definir una paginación personalizada o custom a los resultados de búsqueda, aplicando un diseño particular a cada enlace del paginado, mediante la aplicación de alguna estilo definido CSS o class.

Por ejemplo en la plantilla del buscador se puede agregar:

<!-- CONFIG HTML_PREVLINK= <a href='%%link%%' class='paglink' style='margin: 5px;'>%%pag%%</a> -->
<!-- CONFIG HTML_NEXTLINK= <a href='%%link%%' class='paglink' style='margin: 5px;'>%%pag%%</a> -->
<!-- CONFIG HTML_PAGELINK= <a href='%%link%%' class='paglink' style='margin: 5px;'>%%pag%%</a> -->
<!-- CONFIG HTML_CURRENTPAGE= <i class='current_page'>%%pag%%</i> -->

Definición de las variables de configuración:

  • HTML_PREVLINK: Plantilla del link a la página previa.
  • HTML_NEXTLINK: Plantilla del link a la página siguiente.
  • HTML_PAGELINK: Plantilla del link a la página (número).
  • HTML_CURRENTPAGE: Plantilla de la página actual.
Indexar

Puedes iniciar manualmente el proceso de indexado haciendo click en Administrar → Mantenimiento → Regenerar Indice ElasticSearch.

Una vez allí, haz click en "Ejecutar el proceso".

Al hacer click sobre "Ejecutar el proceso" aparecerá una ventana mostrando el progreso del proceso de indexado, y eventuales errores. Este proceso no solamente reindexa, sino que

  • Elimina el índice actual con todos los datos y lo recrea
  • Aplica eventuales cambios a la definición del índice
  • Reindexa

Esto solamente es necesario si haces cambios a la definición del índice. El proceso de indexación posterior corre cada vez que se crea, modifica o borra un artículo, y no necesita ejecuciones manuales o por cron.

Invocar el buscador

El proceso de búsqueda se realiza por medio de la siguiente CGI Prontus

http://[dominio]/cgi-bin/prontus_search_advanced.cgi

Una forma sencilla de ejecutar la anterior CGI es por medio de un elemento <form> en el código fuente de alguna Plantilla de Portada, agregando el siguiente código:

<form class="search-cont" action="/cgi-bin/prontus_search_advanced.cgi">
<input type="hidden" name="search_prontus" value="cms">
<input type="hidden" name="search_tmp" value="search.html">
<input type="hidden" name="search_idx" value="miprontus">
<input type="hidden" name="search_modo" value="and">
<input type="hidden" name="search_orden" value="rel">
<input type="hidden" name="search_resxpag" value="3">
<input type="hidden" name="search_maxpags" value="20">
<input type="hidden" name="search_form" value="no">
<input type="text" name="search_texto" id="search_texto" class="search-input" placeholder="Ingresa tu búsqueda">
<button type="submit" class="search-icon btn">Enviar/button>
</div>
</form>

Como ves en el código de arriba, puedes personalizar el funcionamiento del buscador enviando parámetros en tu solicitud de búsqueda. En particular, en el ejemplo anterior se define un formulario de búsqueda cuyos resultados serán reflejados por medio de la plantilla search.html. De haberse configurado otra plantilla, se debe especificar el nombre de la misma en la etiqueta input con atributo name "search_tmp", por ejemplo:

<input name="search_tmp" value="search_adv.html" type="hidden">

Esto es útil en caso necesites implementar una búsqueda avanzada, por ejemplo con filtros por fecha de publicación.

El campo search_prontus debe contener el nombre del Prontus, por ejemplo el contenido de la marca %%_prontus_id%%. El campo search_idx debe contener el nombre del índice de búsqueda configurado para ElasticSearch. Estos dos valores muchas veces pueden ser iguales, pero depende de la definición del sitio.

El campo search_modo puede contener los valores "and" u "or". El primer caso especifica solamente devolver resultados de búsqueda con todas las palabras ingresadas, en cambio "or" permite devolver resultados que contengan cualquier palabra de las ingresadas.

El campo search_form especifica  con "yes" o "no" si mostrar o no un formulario de búsqueda en la página de resultados. Ese formulario tendrá la forma básica del ejemplo de arriba, y debe estar en la plantilla de resultados dentro de un bloque

<!--FORMULARIO-->
<!--/FORMULARIO-->

<p">Y debe encontrarse en tu plantilla antes de un comentario <!--SEPARADOR-->. Los resultados de búsqueda deben venir después de ese comentario.

El campo search_orden puede contener los valores "rel" o "cro" según deseemos mostrar resultados ordenados por relevancia o en orden cronológico de publicación.

Búsqueda Avanzada

Es posible implementar filtros de búsqueda, y este es un ejemplo de plantilla:


<!DOCTYPE HTML>
<html lang="es-CL">

<head>
    <meta charset="utf-8">
    <!-- inicio metatags-->
    <title>Mi Sitio</title>
    <!-- MSG server_busy = Servidor ocupado. Intente más tarde… -->
    <!-- MSG no_results = No se encontraron resultados. -->
    <!-- MSG order_cron = en orden cronológico. -->
    <!-- MSG order_rel = en orden de relevancia. -->
    <!-- MSG results = Resultados -->
    <!-- MSG to = al -->
    <!-- MSG of = de -->
    <meta charset="utf-8">
    <title>Buscador</title>
    <script src="/%%_prontus_id%%/js-local/jquery/jquery.min.js"></script>
    <script src="/%%_prontus_id%%/js-local/jquery-ui/jquery-ui.min.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_secc.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_tem.js"></script>
    <script src="/%%_prontus_id%%/site/extra/mapa/pags/tax_subtem.js"></script>
    <script src="/%%_prontus_id%%/js-local/Taxonomia.class.js"></script>
    <script src="/%%_prontus_id%%/js-local/jquery/plugins/datepicker/js/i18n/jquery.ui.datepicker-es.js"></script>
    <script>
    $(document).ready(function(){
            $('.fecha').datepicker({
                dateFormat: 'dd/mm/yy',
            buttonImage: '/%%_prontus_id%%/js-local/jquery/plugins/datepicker/imag/calendar.gif',
            buttonImageOnly: true,
            showOn: 'both'
        });
        Taxonomia.init();
    });
    </script>

</head>

<body class="articulo">
    <!--HEADER-->
    <!--#include virtual="/%%_prontus_id%%/site/edic/base/port/_m_header.html"-->
    <!--/HEADER-->
    <!--CONTENIDO-->
    <div id="main" class="span-12 lg-12">
        <div class="auxi">
            <!--FORMULARIO-->
            <div class="row">
                <div class="col span-9 xs-12 sm-12 md-9 lg-9">
                    <form id="form_buscar" method="get" action="/cgi-bin/prontus_search_advanced.cgi"
                    class="navbar-form navbar-right search-desktop">
                    <input id="search_prontus" name="search_prontus" value="%%_prontus_id%%" type="hidden">
                    <input name="search_idx" value="%%_prontus_id%%" type="hidden">
                    <input name="search_template" value="search_adv.html" type="hidden">
                    <input name="search_form" value="yes" type="hidden">
                    <input name="search_modo" value="AND" type="hidden">
                    <input name="search_orden" value="" type="hidden">
                    <div class="search">
                        <input id="search" name="search_texto" placeholder="Buscar" aria-label="Búsqueda" autocomplete="off"
                            class="campo-search" type="text">
                        <button class="lupa aleft" type="submit">
                            <img src="/%%_prontus_id%%/imag/v1/auxi/lupa.png" alt="Buscar">
                        </button>
                    
                        <input type="hidden" name="search_nom_seccion" id="NOM_SECCION1">
                        <input type="hidden" name="search_nom_tema" id="NOM_TEMA1">
                        <input type="hidden" name="search_nom_subtema" id="NOM_SUBTEMA1">
                        <input type="hidden" name="search_nom_seccion_excluir" id="NOM_SECCION1_EXCLUIR">
                        <input type="hidden" name="search_nom_tema_excluir" id="NOM_TEMA1_EXCLUIR">
                        <input type="hidden" name="search_nom_subtema_excluir" id="NOM_SUBTEMA1_EXCLUIR">
                        Secciones: <select name="search_secciones" id="SECCION1" multiple></select>
                    
                        Temas: <select name="search_temas" id="TEMA1" multiple></select>
                    
                        Subtemas: <select name="search_subtemas" id="SUBTEMA1" multiple></select>
                    
                        Excluir Secciones: <select name="search_secciones_excluir" id="SECCION1_EXCLUIR" multiple></select>
                    
                        Excluir Temas: <select name="search_temas_excluir" id="TEMA1_EXCLUIR" multiple></select>
                    
                        Excluir Subtemas: <select name="search_subtemas_excluir" id="SUBTEMA1_EXCLUIR" multiple></select>
                    
                        Desde: <input type="date" name="search_desde" value="" class=".fecha">
                        Hasta: <input type="date" name="search_hasta" value="" class=".fecha">
                    </div>
                </form>
                </div>
            </div>
            <!--/FORMULARIO-->
        </div>
        <!--SEPARADOR-->
        <div class="auxi">
            <div class="row">
                <div class="col span-9 xs-12 sm-12 md-9 lg-9">
                    USTED ESTÁ EN:
                    <ul class="breadcrumbs">
                        <li><a href="/%%_prontus_id%%/site/edic/base/port/inicio.html">INICIO</a></li>
                        <li><a href="/%%_prontus_id%%/stat/search_advanced/">BUSCADOR AVANZADO</a></li>
                    </ul>
                    <h1 class="titular">Buscador</h1>
                    <p class="bajada">Usted buscó por: "%%search_texto%%". %%resultados_totales%% resultados
                        encontrados. Mostrando resultados de %%start%% a %%end%%.<br>
                        <!--PAGS-->
                        <div class="paginas">Ver más en: %%pags%%</div>
                        <!--/PAGS-->
                        <span class="mensaje">%%msg%%</span>
                    </p>

                    <!--PROMOTED_LOOP-->
                    <div class="tax_box col esp span-4 xs-12 sm-4 md-4 lg-4">
                        <div class="content">
                            <h2>Promoted: 
                                <a href="%%link%%">%%titular%%</a>
                            </h2>
                            <p>%%descripcion%%…</p>
                        </div>
                    </div>
                    <!--/PROMOTED_LOOP-->

                    <!--RESULT_LOOP-->
                    <div class="tax_box col esp span-4 xs-12 sm-4 md-4 lg-4">
                        %%if(metadata_img)%%
                        <div class="img_cont">
                            <a href="%%link%%">
                                <img src="%%metadata_img%%" alt="" class="fullwidth">
                            </a>
                        </div>
                        %%/if%%
                        %%nif(metadata_img)%%
                        <div class="img_cont">
                            <a href="%%link%%">
                                <img src="/%%_prontus_id%%/imag/v1/default/default_870x515.jpg" alt=""
                                    class="fullwidth">
                            </a>
                        </div>
                        %%/nif%%
                        <div class="content">
                            <h2>
                                <a href="%%link%%">%%titular%%</a>
                            </h2>
                            <p>%%descripcion%%…</p>
                            %%if(metadata1)%%<p>Metadata 1: %%metadata1%%</p>%%/if%%
                            %%nif(metadata1)%%NO HAY METADATA1%%/nif%%

                            %%if(search_meta1)%%<p>Search_meta 1: %%search_meta1%%</p>%%/if%%
                            %%nif(search_meta1)%%NO HAY METASEARCH1%%/nif%%

                            %%if(metadata2)%%<p>Metadata 2: %%metadata2%%</p>%%/if%%
                            %%nif(metadata2)%%NO HAY METADATA2%%/nif%%

                            %%if(search_meta2)%%<p>Search_meta 2: %%search_meta2%%</p>%%/if%%

                            %%nif(search_meta2)%%NO HAY METASEARCH2%%/nif%%
                        </div>
                    </div>
                    <!--/RESULT_LOOP-->
                </div>
            </div>
        </div>
        <!--/CONTENIDO-->
        <!--FOOTER-->
        <!--#include virtual="/%%_prontus_id%%/site/edic/base/port/_m_footer.html"-->
        <!--/FOOTER-->
</body>

</html>
Variables

El Buscador Prontus puede ser utilizado con un mínimo de variables de invocación, con todas ellas o con un conjunto escogido de acuerdo a las características del sitio web.

Invocación mínima

Luego de insertar el formulario en la plantilla de resultados, basta ejecutar una request GET como la siguiente:

/cgi-bin/prontus_search_advanced.cgi?search_prontus=[prontus_id]&search_idx=[indice]&search_texto=[texto a buscar]
Invocación mínima con cambio de plantilla

Si se desea especificar la plantilla a mostrar, entonces la request cambia a:

/cgi-bin/prontus_search_advanced.cgi?search_prontus=[prontus_id]&search_idx=[indice]&search_tmp=[plantilla de buscador]&search_texto=[texto a buscar]