Cómo optimicé la búsqueda en mi SaaS con PostgreSQL Full-Text Search - Episodio 22

Optimizar la búsqueda con PostgreSQL con Full-Text search era la clave para poder seguir avanzando en el proyecto.
Ya que responde a uno de los retos más importantes en mi SaaS...
Ya sabes cómo permitir a los usuarios encontrar piezas de forma eficiente.
Esto es clave porque con miles de registros en la base de datos, usar consultas tradicionales con ILIKE o LIKE era demasiado lento y poco preciso.
🚀 Haciendo que las búsquedas sean rápidas y precisas.📅 Diario de un SaaS:
La solución: Full-Text Search en PostgreSQL con índices GIN. 🔥
Este sistema permite búsquedas mucho más rápidas y relevantes, optimizando la experiencia del usuario sin sacrificar rendimiento.
Por eso este este post, lo voy a dedicar a explicar cómo lo implementé, los errores que encontré y cómo los solucioné.
🔍 Problema: Búsquedas lentas y poco precisas
Antes de optimizar, el sistema de búsqueda tenía dos grandes problemas:
🔴 1. ILIKE y LIKE no son escalables
Cuando un usuario realizaba una búsqueda, PostgreSQL tenía que recorrer toda la base de datos para encontrar coincidencias.
Es decir, que generaba tiempos de respuesta altos y un consumo de recursos innecesario.
Ejemplo de una consulta típica con ILIKE:
SELECT * FROM piezas WHERE titulo ILIKE '%marca referencia%';
Esto funciona bien con pocos registros, pero cuando tienes miles o millones de filas, la base de datos se vuelve cada vez más lenta.
Y ojo, mi obsesisón pasa por tener un muy buen rendimiento en el sistema ya que esto va a garantizar una buena experiencia de usuario.
🔴 2. Los resultados no eran relevantes
Con ILIKE, una consulta devolvía cualquier coincidencia exacta, sin considerar sinónimos, errores tipográficos o términos más relevantes.
Así que un usuario que buscara "tipo de pieza" podía no encontrar una pieza cuyo título era "Tipo de pieza con sistema automático".
Necesitaba una forma de hacer las búsquedas más rápidas y precisas.
Y por eso aquí es donde entra Full-Text Search.
🛠️ Implementando Full-Text Search con PostgreSQL
✅ 1. Crear un search_vector en PostgreSQL
Lo primero fue añadir una columna search_vector, que convierte el texto en un formato optimizado para búsqueda de texto completo.
ALTER TABLE piezas ADD COLUMN search_vector tsvector;
Luego, actualizamos esta columna para que almacene los títulos y descripciones indexados:
UPDATE piezas SET search_vector = to_tsvector('spanish', titulo || ' ' || descripcion);
¿Qué hace esto?
Convierte el título y la descripción en un índice de búsqueda optimizado...
Es decir, eliminando palabras irrelevantes y permitiendo encontrar términos similares de manera eficiente.
✅ 2. Crear un índice GIN para acelerar las búsquedas
Sin un índice, PostgreSQL tendría que analizar todas las filas cada vez que se realiza una búsqueda.
En ese caso, para evitarlo, añadí un índice GIN:
CREATE INDEX idx_piezas_search ON piezas USING GIN(search_vector);
¿Por qué GIN?
Los índices GIN (Generalized Inverted Index) permiten buscar texto sin recorrer la base de datos completa, mejorando enormemente la velocidad de respuesta.
✅ 3. Modificar la API para usar Full-Text Search
En lugar de usar ILIKE, ahora la API usa to_tsquery(), lo que permite búsquedas más rápidas y relevantes:
@app.route('/buscar')
def buscar():
query = request.args.get('q')
sql = """
SELECT * FROM piezas
WHERE search_vector @@ to_tsquery('spanish', %s)
ORDER BY ts_rank(search_vector, to_tsquery('spanish', %s)) DESC;
"""
cursor.execute(sql, (query, query))
resultados = cursor.fetchall()
return jsonify(resultados)
🔹 ¿Qué mejoras introduce esto?
- Búsquedas más rápidas, ya que PostgreSQL usa el índice GIN en lugar de recorrer la base de datos.
- Mayor precisión, priorizando coincidencias más relevantes.
- Compatibilidad con sinónimos y errores tipográficos, gracias a la normalización de texto en
to_tsvector().
❌ Errores encontrados y cómo los solucioné
🔴 ERROR: No existe el tipo de dato «tsvector» en la consulta
Solución:
- Verificar que la columna
search_vectorexiste. - Si se omitió, crear la columna manualmente antes de indexar los datos.
🔴 No se devuelven resultados en la búsqueda
Solución:
- Asegurar que
to_tsvector('spanish', campo)yto_tsquery('spanish', %s)usan el mismo idioma. - Convertir los términos de búsqueda a minúsculas para evitar problemas de coincidencia.

💡 Aprendizajes del proceso
🔹 Full-Text Search es hasta 100 veces más rápido que ILIKE
Pasamos de consultas que tardaban varios segundos a respuestas en milisegundos. 🚀
🔹 Un buen índice GIN hace toda la diferencia
Sin él, PostgreSQL haría escaneos completos de la base de datos en cada búsqueda. Con él, las respuestas son instantáneas.
🔹 Rankear los resultados mejora la experiencia del usuario
Ordenar con ts_rank() hace que las coincidencias más relevantes aparezcan primero, algo que antes no ocurría.
🔹 PostgreSQL tiene herramientas avanzadas que muchos ignoran
PostgreSQL no solo almacena datos, también ofrece optimizaciones de alto nivel para búsquedas y rendimiento.
🚀 Próximos pasos
Con las búsquedas optimizadas, el siguiente paso es cargar imágenes en AWS S3 para mejorar la gestión de medios en el SaaS. 📦🔥
➡️ ¿Has usado Full-Text Search en PostgreSQL?
¿Cómo optimizas las búsquedas en tu proyecto?
Cuéntamelo en los comentarios.
Si quieres conocer otros artículos parecidos a Cómo optimicé la búsqueda en mi SaaS con PostgreSQL Full-Text Search - Episodio 22 puedes visitar la categoría Proyecto-IA.

Deja una respuesta