Symfony 4. Integrando el servicio de búsquedas Algolia

Todo lo que debes saber para integrar Algolia en un proyecto desarrollado con Symfony 4

Image for post
Image for post
Integrando Algolia en un proyecto con Symony 4

Recientemente he tenido que integrar el servicio de búsquedas Algolia en un proyecto desarrollado con Symfony 4 y he visto bastante interesante escribir un pequeño manual donde contar todo lo que he ido haciendo y las “peculiaridades” que he descubierto a medida que avanzaba.

Para los que no conozcáis Algolia deciros que es un servicio de búsquedas similar a Elastic Search que optimiza las búsquedas por texto de cara a que sean resueltas en apenas pocos milisegundos. Esto permite que funcionalidades como el autocompletado funcionen de forma muy rápida lo cual mejora la experiencia de usuario.

Así que en este manual encontraréis todo lo necesario para integrar Algolia con Symfony y algunos consejos y recomendaciones para que decidáis si este servicio se adecúa a vuestras necesidades ya que por desgracia tiene algunas limitaciones frente a Elastic Search.

¡Vamos allá!

Cosas interesantes

Antes de empezar he decidido hacer un pequeño glosario de terminología que emplea Algoria de cara a entender qué es cada elemento que emplearemos y su función dentro del servicio.

¿Cuanto cuesta Algolia?

Algolia tiene diferentes planes de precios que empiezan desde el más básico que es gratuito hasta soluciones más personalizadas para empresas grandes cuyos precios varían en función del volumen de búsquedas y del nivel de personalización y de estadísticas que necesitemos. Así que si queréis probar este servicio basta con que creéis una cuenta de forma gratuita y escojáis el plan Community el cual os servirá para vuestros side-projects.

¿Qué es un índice y un registro?

Un registro (record) representa un elemento dentro un resultado de búsqueda. Por ejemplo, un libro, una película… Los registros poseen atributos (attributes) los cuales son pares clave/valor, por ejemplo, el título de los libros o la puntuación de la película.

Por otra parte un índice (index) es una colección de registros y dónde se realizarán las búsquedas de cara a localizar los resultados correspondientes.

Normalizer

Antes de que nuestras entidades sean enviadas a Algoria es necesario que sean convertidas en “arrays”. Esto se puede realizar de forma automática si tenemos habilitado el serializador por defecto de Symfony (lo cual recomiendo si vamos a trabajar con este bundle). La forma en que nuestras entidades son normalizadas puede personalizarse de distintas formas:

Recordad que el serializer de Symfony podéis instalarlo mediante composer :

composer require symfony/serializer

Y para activarlo deberéis añadir la siguiente línea en config/packages/framework.yml :

serializer: { enable: true }

Instalación

La instalación del bundle de Algolia se lleva a cabo de la forma habitual mediante composer:

composer require algolia/search-bundle

Esto ejecutará la “recipe” que trae consigo el bundle y añadirá a nuestro archivo bundles.php la línea que activa AlgoliaSearchBundle :

...Algolia\SearchBundle\AlgoliaSearchBundle::class => [‘all’ => true]

Configuración

Una vez instalado el bundle lo siguiente será añadir las claves que nos proporciona Algoria de forma gratuita en nuestro archivo env.local. Si os fijáis en el archivo .env tras instalar AlgoriaSearchBundle se habrán añadido dos nuevas variables:

  • ALGOLIA_APP_ID
  • ALGOLIA_API_KEY

Para obtener sus valores crearemos una cuenta en www.algolia.com y tras acceder al Dashboard iremos a la sección API Keys donde podremos obtener el valor de Application ID que se lo asignaremos a ALGOLIA_APP_ID y de Admin API Key que se lo asignaremos a ALGOLIA_API_KEY .

A continuación procederemos a configurar el bundle para lo cual abriremos el archivo config/packages/algolia_search.yml . Es aquí donde podremos definir entre otras cosas los índices y configurar otros aspectos de la búsqueda como el número de resultados devueltos por defecto o el prefijo que acompañará a nuestros índices.

Inicialmente este archivo tiene el siguiente aspecto:

algolia_search:    prefix: '%env(APP_ENV)%_'

y lo usaremos para definir nuestros indices como veremos a continuación.

Indexando los primeros datos

Si queremos comenzar a indexar datos en Algoria lo primero que tendremos que hacer es definir un nuevo índice.

De cara a este artículo supondremos que estamos desarrollando un blog, por lo que nuestro índice almacenará los artículos publicados dentro del mismo.

Para ello, añadiremos lo siguiente:

algolia_search:
indices:
- name: posts
class: App\Entity\Post
enable_serializer_groups: true
  • name define el nombre del índice
  • class la entidad asociada al índice
  • enable_serializer_groups. Este parámetro es el que tiene algo más de “miga”. Para enviar los datos a Algoria es necesario convertirlos previamente en “arrays”, algo que se puede hacer de forma automática mediante el serializador que trae consigo Symfony o empleando alguna librería de terceros como JMSSerializer. En el caso de que estemos empleando el serializador por defecto podremos añadir esta configuración a nuestro índice de cara a poder emplear la anotación @Groups({"searchable"}) en los campos de nuestras entidades y así indicar al bundle que los queremos mandar a Algolia como atributos.

En el caso de que queráis usar la librería JMSSerializer esto es posible desde la versión 3.2 del bundle:

If you’d rather use the JMS Serializer instead of the default Symfony serializer, you can set serializer: jms_serializer in config/packages/algolia_search.yaml. Note that the @Groups annotation isn't supported.

Sabiendo esto, iremos a nuestra entidad src/Entity/Post.php y añadiremos la anotación @Groups({"searchable"}) en los “getters” de los campos que queremos enviar a Algolia, en este caso al body y al title :

<?php

namespace App\Entity;

use Symfony\Component\Serializer\Annotation\Groups;

class Post
{

/**
* @Groups({"searchable"})
*/
public function getTitle(): ?string
{
return $this->title;
}

/**
* @Groups({"searchable"})
*/
public function getBody(): ?string
{
return $this->body;
}

}

Hecho esto, podremos emplear el comando search:import para enviar todos los datos que se encuentren en los índices que hayamos definido:

php bin/console search:import

y el comando search:clear para vaciar los índices:

php bin/console search:clear

Si todo ha ido bien en nuestro dashboard de Algolia podremos ver el índice posts creado y nuestros artículos dentro de él con los campos body y title .

Realizando búsquedas

Pasamos a la parte divertida: realizar búsquedas en Algoria. Para realizar búsquedas en este servicio, AlgoriaSearchBundle nos provee del servicio IndexManager el cual podemos inyectar donde necesitemos realizar búsquedas.

Por ejemplo, supongamos que tenemos el controlador de Symfony SearchController y queremos realizar búsquedas sobre los artículos de nuestro blog.

En primer lugar inyectaremos IndexManagerInterface en la acción de nuestro controlador:

Image for post
Image for post

Y a continuación añadiremos el siguiente código:

Image for post
Image for post

Es decir, obtenemos el “manager de Doctrine” para nuestra clase Post y a continuación realizamos la búsqueda mediante el $indexManager empleando como primer argumento el valor pasado mediante query en la URL en el parámetro s (de ahí la línea $request->get('s' ) .

AlgoriaSearchBundle también permite recibir los resultados de búsqueda tal cual son recibidos desde Algolia (es decir, sin ser procesados por Doctrine) lo cual nos permite obtener información sobre el ranking o los elementos destacados:

$posts = $this->indexManager->rawSearch('query', Post::class);

Indexando automáticamente

El bundle por defecto escucha los siguientes eventos: postPersist , postUpdate , preRemove de modo que cada vez que se añade, modifica o elimina un dato se sincronizará automáticamente con Algolia. Sin embargo, es posible configurar los eventos que se escuchan por si necesitamos algo más de personalización en la forma en que AlgoriaSearchBundle indexa nuestros datos:

algolia_search:
doctrineSubscribedEvents: ['postPersist']

Trucos

Modificar el número de elementos enviados o borrados

Por defecto, las llamadas a Algolia para crear o borrar elementos se realizan de 500 en 500 elementos. Sin embargo, podemos modificar este número directamente desde la configuración añadiendo lo siguiente en nuestro archivo config/packages/algolia_search.yml :

algolia_search:
batchSize: 250

Algo que es muy útil si al ejecutar los comandos de indexación o borrado estamos teniendo problema de memoria (este número se emplea también en las consultas a base de datos mediante Doctrine que por debajo usa Algolia).

Trabajando en local

Es posible configurar el bundle para que no se envíen llamadas a Algolia empleando el NullEngine :

o cancelando la suscripción del bundle a los eventos de Doctrine añadiendo lo siguiente al archivo config/packages/algolia_search.yml :

algolia_search:
doctrineSubscribedEvents: []

Indexando de forma condicional

Muchas veces no queremos indexar todos los elementos que se encuentran en nuestra base de dato, sino aquellos que cumplan una serie de condiciones como por ejemplo que se encuentren publicados.

Esto podemos configurarlo directamente desde la definición de nuestro índice en el archivo algolia_search.yml añadiendo la clave index_if a la cual podemos pasarle el nombre de un método, de una propiedad o incluso claves anidadas gracias a la “magia” del componente PropertyAccessor de Symfony:

algolia_search:
indices:
- name: posts
class: App\Entity\Post
index_if: isPublished

Paginar resultados

En el caso de que queramos paginar los resultados de una consulta, podemos emplear los dos últimos argumentos del método search de IndexManager del siguiente modo:

$posts = $this->indexManager->search('text to search', Post::class, $em, $pageNumber, $numberOfResults);

Conclusión

Tras probar Algolia durante la última semana me gustaría comentaros mis propias conclusiones en torno a este servicio.

Me ha gustado mucho la facilidad con la que podemos integrarlo con Symfony (apenas tardé 30 minutos en tener todo el sistema funcionando) y el dashboard que proporciona desde su propia página web, el cual permite ver el estado de nuestros índices, configurar de forma visual algunas características de los mismos e incluso realizar búsquedas dentro de los mismos. La verdad es que si necesitas integrar un servicio de búsquedas en tu aplicación sin romperte la cabeza Algolia es probable que se ajuste perfectamente a lo que necesitas.

Sin embargo… es menos potente que Elastic Search y tiene una limitación demasiado grande como para no tenerla en cuenta. La he extraído de su propia documentación:

Since Algolia only supports prefix search, what you need to do to is add an attribute that contains all the possible suffixes for product_reference, as an array:

Es decir, sólo es capaz de realizar búsquedas mediante prefijo. ¿Ésto que quiere decir? Que si por ejemplo tenéis indexado un artículo con el título “El último libro de Harry Potter” y tratáis de buscar “otter” la búsqueda no arrojará resultados, pues Algolia no realiza búsquedas por infijo o sufijo. Esto a la larga puede ser una restricción muy importante por lo que conviene tenerla en cuenta por si la aplicación que estamos desarrollando contempla ese tipo de búsquedas. En ese caso os recomiendo que optéis por Elastic Search, servicio que es algo más complejo de integrar y que no cuenta de primeras con un dashboard (tenéis que configurarlo vosotros) pero que sí permite realizar cualquier tipo de búsqueda.

¿Quieres recibir más artículos como este?

Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇

Written by

Entre paseo y paseo con Simba desarrollo en Symfony y React

Get the Medium app