Pasar al contenido principal

Búsquedas de alto rendimiento con mapas en Drupal

Hoy vengo a hablar sobre mi SideProject Vabiso.com, que va a cumplir un año el próximo mes, y como está implementado el backend para poder soportar un volumen masivo de datos y mostrarlo todo en un mapa.

Voy a separar este artículo en los apartados que creo que son más relevantes desde el punto de vista de como montar un proyecto enfocado en las búsquedas.

Resumen del proyecto

Primero de todo he de hacer un resumen del proyecto para ponerte en situación y explicar para qué sirve el mapa.

Vabiso.com es un buscador de empleo. De forma automática se indexan ofertas de empleo de otras webs, se geolocalizan y se guardan en la base de datos del Drupal.

En el momento de indexar también se detectan automáticamente las categorías, entre ellas las de trabajos remotos. Los trabajos remotos no se muestran en el mapa sino en un listado/buscador independiente.

Cada cierto tiempo se van eliminando las ofertas de empleo antiguas, ya que no tiene sentido mostrar ofertas de empleo caducadas de hace meses.

La gracia de este proyecto es saber gestionar las múltiples importaciones automatizadas, saber gestionar el gran volumen de datos y tener una búsqueda geolocalizada con mapa de alto rendimiento.

Volumen de datos

Si has entrado en Vabiso.com habrás visto que tiene 60k ítems en el mapa y 17k ítems que no están en el mapa. Eso son 77k ítems que se muestran y filtran desde distintas páginas de búsqueda.

Esos 77k son sólo los empleos visibles, ya que hay muchos que están en cola para indexar, otros que se han dejado de publicar y luego se eliminan.

En su momento esta web llegó a tener más de 200k items visibles en el mapa y unos 30K empleos remotos.

El volumen de datos máximo indexado llegó a ser cerca de 2 millones de empleos, muchos de los cuales eran empleos antiguos. En su momento se mejoró el código de la web para permitir eliminar de forma automática todos esos empleos antiguos que no se han de mostrar.

Límite de la tecnología

De forma resumida, hay varias formas de enviar datos en un mapa y poder realizar cálculos de proximidad. Va a depender en gran medida de que hagas exactamente con los datos y con el mapa, pero te puede servir saber que tipos de tecnologías van a ser mejor que otras.

Te enumero de forma simplificada los límites de ítems del mapa que puede mostrar cada uno. El límite inferior es una aproximación de cuando ya empieza a notarse lentitud, el límite superior es que básicamente el mapa es inusable.

  • JSON u otros formatos y que el cálculo lo haga JS: El límite está entre 100 y 1000 puntos en el mapa.
  • PHP: El límite sería entre 500 y 1000 puntos.
  • Mysql: Empieza a ir lento sobre los 10k, es inviable usarlo con más de 100k
  • SOLR o ElasticSearch: Sinceramente no tienen límites, a mayor volumen más lenta es la respuesta, pero sigue siendo mucho más rápida que cualquiera de las otras.

Una par de cosas a aclarar:

  • Los límites superiores que comento arriba son que la lentitud del sistema es exponencial. Me refiero a que las consultas van a tardar mínimo 1s, pero se pueden disparar fácilmente hasta 10 segundos o más.
  • Esto depende mucho de qué datos evidencies en el mapa, como los muestres y qué tipo de cálculos hagas. No es lo mismo calcular proximidad que filtrar por zonas.

Rendimiento Drupal y MYSQL

Drupal, como supongo que sabes, funciona con MYSQL.

Uno de los mejores módulos que tiene es el módulo views, que te permite crear listados con filtros sin necesidad de saber programar.

Views por defecto trabaja con la base de datos de Drupal, lo que significa que trabaja con MYSQL.

Lo primero que has de saber es que las búsquedas geoespaciales en MYSQL no son nada óptimas en rendimiento.

Como ya te he comentado en el punto anterior, realizar cálculos con coordenadas espaciales y obtener la proximidad o poder filtrar por zonas del mapa son cálculos lentos, muy lentos en MYSQL, sobre todo si tienes entre 10-100k de resultados.

Módulo Search API

En Drupal tenemos el módulo Search API, que nos permite tener bases de datos externas al Drupal. Este módulo lo he utilizado en la mayoría de proyectos con alto volumen de datos en el que hace falta realizar búsquedas.

Podemos tener varios tipos de motores de búsqueda:

  • MYSQL: no tiene sentido con búsquedas geoespaciales, pero puede tener sentido si solo quieres realizar búsquedas por texto y tener filtros facetados.
  • SOLR: Es uno de los motores con mayor recorrido/antigüedad y permite las búsquedas geoespaciales, las de texto y tener filtros facetados.
  • ElasticSearch: mucho más nuevo que SOLR, permite hacer lo mismo que SOLR pero con una tecnología diferente.

ElasticSearch

Para Vabiso.com me decidí a usar ElasticSearch, pero sería factible usar SOLR. Mis motivos fueron:

  • Tengo mayor conocimiento de Elastic que no SOLR
  • Elastic es más moderno y creo que ofrece mayor rendimiento (servidor más pequeño = menor coste)
  • Varios ejemplos de código que encontré en la web usaban Elastic y no SOLR

Pero había un problema importante. Hace un año, cuando creé Vabiso, el módulo de Drupal “ElasticSearch Connector” (para que Drupal envíe los datos a un índice de ElasticSearch) no tenía soporte para los campos Drupal tipo “geolocation” .

Fue mi oportunidad para aprender más de Elastic, y crear un módulo contribuido que solucionase el problema: https://www.drupal.org/project/search_api_geolocation

Es un módulo que sigue en BETA, pero permite indexar los campos geolocation y realizar búsquedas geoespaciales.

Tips para mapas

Hay varias cosas a tener en cuenta que pueden mejorar el rendimiento de un mapa:

No cargar todos los puntos

Es una obviedad, pero poca gente piensa en ello.

En Vabiso estoy enviando a Elastic 5 datos que actúan como filtros:

  • Las 4 esquinas del mapa
  • El nivel de Zoom del mapa

Con esto Elastic me devuelve solo los puntos que están dentro de la zona que está viendo el usuario, y gracias al zoom elastic puede devolver ubicaciones aproximadas y agrupadas en cuanto a precisión.

La agrupación de zoom es muy importante. En Vabiso puedes ver que hay clusters (grupos de puntos) más grandes que otros, y cuando haces zoom esos clusters se recalculan. Esos cálculos los hace Elastic. Por tanto podemos tener un nivel de zoom muy bajo y que tengamos un cluster con 10k puntos, pero realmente lo que recibimos de elastic son las coordenadas de 1 cluster, no las de 10k puntos. ¡Esto quita mucho trabajo en el frontend en el momento de renderizar los clusters!

Ten en cuenta que con esta configuración se está haciendo una petición a ElasticSearch cada vez que el usuario se mueve por el mapa o cada vez que hace zoom. Osea, hay muchas muchas peticiones.

Ejemplos:

  • Si el usuario está viendo la ciudad de Madrid, no tiene sentido que en el mapa se estén cargando puntos de ciudades como Barcelona, París o New York. Solo se han de cargar puntos que se ven en el mapa actual.
  • Si el usuario tiene el mapa con un nivel de zoom alto (ver una calle), entonces se ha de mostrar el punto con una precisión alta para poder ver la ubicación exacta. Pero si estamos a nivel de zoom bajo (ver toda España o Europa) entonces no tiene sentido tener una precisión alta (el usuario va a ver lo mismo mientras el punto esté dentro de unos pocos km a la redonda).

No cargar toda la información de golpe

Es muy típico tener una views MYSQL normal (por ejemplo usar los módulos  OpenLayers o Leaflet) y cargar toda la información de la entidad Drupal de todos los puntos.

Si quieres un mapa y que se pueda hacer click en los puntos para abrir un popup con información … Eso debería ser una llamada AJAX para solicitar la info de ese único punto donde el usuario ha hecho click.

No tiene sentido hacer que Drupal cargue la información de 1000 nodos, si el usuario solo quiere hacer dos clicks en dos puntos y ver solo esos 2 nodos.

En Vabiso puedes ver que tengo los resultados en una barra lateral o inferior (depende de si lo miras con móvil o desktop). Esos resultados solo muestran los 5 primeros, el resto se cargan por ajax. Lo cual es independiente del mapa y hace la ilusión de que todo funciona fluido y rápido.

No usar los mapas de Google

No hay ningún problema de rendimiento en usar Google Maps en tus proyectos Drupal.

Pero has de ser consciente que los Mapas de Google son de pago. Si tienes muchas visitas te va a salir caro el asunto.

He estado en proyectos en los que mensualmente se estaban pagando cientos de euros por el uso de google maps.

La solución es simple, puedes usar Leaflet. Y si quieres un estilo visual parecido al de Google entonces puedes usar una capa de Google sin API key y que es gratis e ilimitada.

No es lo mismo usar la capa/layer de google encima de Leaflet, que usar un mapa con las librerías de Google Maps.

Vabiso usa justamente Leaflet + un Layer de Google gratuito y visualmente no queda mal, ¿no?

Conclusión

Se han de tener muchas cosas en cuenta cuando haces cosas con mapas.

Y no es lo mismo hacer un mapa que ha de mostrar 10 puntos a uno que ha de mostrar 10k puntos. El rendimiento afecta y mucho!!!

Si tienes cualquier duda sobre Drupal, búsquedas y mapas, me puedes contactar y hablamos.