Al implementar funcionalidad de búsqueda para una aplicación, normalmente hay dos enfoques generales:
- Búsqueda tradicional basada en palabras clave: Hace coincidir palabras exactas o variantes simples.
- Búsqueda semántica (o vectorial): Hace coincidir significado o contexto usando incrustaciones (embeddings) generadas por IA.
También existe un enfoque híbrido, pero eso lo dejaré para un artículo futuro. En este artículo mostraré cómo funcionan estos dos enfoques generales en Python usando MariaDB y un modelo de incrustación IA (embedder). También resaltaré sus diferencias y compartiré código que puedes adaptar.
Los componentes clave#
Para este ejercicio usé MariaDB Cloud e inicié una base de datos “serverless” gratuita. En cuestión de segundos ya tenía una instancia lista para usar. Copié los datos de host/usuario/contraseña, me conecté con VS Code, creé una base de datos llamada demo, una tabla products y cargué ~500 nombres de productos con LOAD DATA LOCAL INFILE. Es un conjunto de datos muy pequeño, pero suficiente para aprender y experimentar.
Luego construí una pequeña app en Python con FastAPI. Primero implementé un endpoint de búsqueda por palabra clave (por nombre de producto) usando un índice de texto completo (FULLTEXT) y luego implementé búsqueda semántica (vectorial) usando incrustaciones generadas por IA junto con el soporte vectorial de MariaDB. Puedes ver todo el proceso en este video (en Inglés).
Búsqueda por palabra clave: simple y familiar#
Para la búsqueda por palabra clave usé un índice de texto completo en la columna name de la tabla products. Con este índice, pude buscar por nombre de producto usando esta consulta SQL:
SELECT name
FROM products
ORDER BY MATCH(name) AGAINST(?)
LIMIT 10;
Expuse esta funcionalidad con FastAPI así:
@app.get("/products/text-search")
def text_search(query: str):
cursor = connection.cursor()
cursor.execute(
"SELECT name FROM products ORDER BY MATCH(name) AGAINST(?) LIMIT 10;", (query,)
)
return [name for (name,) in cursor]
Ventajas:
- Es rápida.
- Funciona bien si los usuarios escriben términos exactos o cercanos.
- Usa funciones nativas de SQL (no requiere modelo de IA externo).
Desventajas:
- No encuentra sinónimos, contexto o significado relacionado.
- No entiende la intención del usuario (si alguien escribe “zapatillas para correr”, una búsqueda estricta podría no devolver “tenis deportivos” o “sneakers”).
- La calidad depende mucho de las palabras exactas.
En mi demo, el endpoint devolvía varios productos irrelevantes para la búsqueda “running shoes” (el set de datos está en Inglés).
Búsqueda semántica (vectorial): coincidencia por significado#
Para ir más allá de las palabras clave implementé un segundo endpoint:
- Usé un modelo de incrustación (Google Generative AI vía LangChain) para convertir cada nombre de producto en un vector de alta dimensión.
- Almacené esos vectores en MariaDB usando la integración para LangChain.
- En tiempo de búsqueda, calculé una incrustación usando la frase de búsqueda del usuario con el mismo modelo, luego hice una búsqueda por similitud usando el algoritmo HNSW (muy eficiente) de MariaDB (por ejemplo, los 10 vectores más cercanos) y devolví los productos correspondientes.
Así es la implementación del endpoint de ingestión:
@app.post("/products/ingest")
def ingest_products():
cursor = connection.cursor()
cursor.execute("SELECT name FROM products;")
vector_store.add_texts([name for (name,) in cursor])
return "Products ingested successfully"
Y así se ve el endpoint de búsqueda semántica:
@app.get("/products/semantic-search")
def search_products(query: str):
results = vector_store.similarity_search(query, k=10)
return [doc.page_content for doc in results]
La integración LangChain + MariaDB hace que todo este proceso sea muy sencillo. La integración crea dos tablas:
langchain_collection: Cada fila representa un conjunto de vectores relacionados. En este demo sólo tengo uno, que corresponde a nombres de productos.langchain_embedding: Las incrustaciones vectoriales. Cada vector pertenece a una colección (relación muchos-a-uno conlangchain_collection).
Cuando ejecuté el endpoint de búsqueda semántica con la misma consulta “running shoes”, los resultados fueron mucho más relevantes: Incluían productos que no coincidían literalmente con “running” o “shoes” pero eran semánticamente cercanos.
Palabra clave vs. semántica — ¿cuándo usar cuál?#
Aquí una comparación rápida:
| Enfoque | Ventajas | Desventajas |
|---|---|---|
| Búsqueda por palabra clave | Rápida de implementar, usa SQL directo | Limitada a coincidencias literales |
| Búsqueda semántica | Entiende contexto e intención, más flexible | Requiere modelo de incrustación + soporte vectorial |
Usa búsqueda por palabra clave cuando:
- Tu dominio de búsqueda es pequeño y predecible, o necesitas coincidencias exactas.
- Los usuarios saben exactamente qué están buscando (códigos, nombres específicos).
- Quieres evitar dependencias externas y mantener la simplicidad.
Usa búsqueda semántica cuando:
- Necesitas manejar sinónimos, conceptos relacionados, o intención del usuario.
- Tu conjunto de datos o dominio tiene variaciones en lenguaje natural.
- Estás dispuesto a integrar un modelo de incrustación y gestionar vectores e índices. MariaDB facilita esto.
En muchas aplicaciones reales se usa un enfoque híbrido: Empezar con búsqueda por palabra clave y si no hay coincidencias o el valor de la consulta lo amerita, usar búsqueda semántica como respaldo. O incluso combinar ambas mediante búsqueda híbrida. MariaDB también permite esto.
Qué tan simple puede ser la integración#
En mi demo activé la ingestión de vectores con un endpoint POST (/ingest). Ese endpoint lee todos los nombres de productos, genera las incrustaciones y las guarda en MariaDB. Una sola línea de código (gracias a LangChain + integración con MariaDB) insertó alrededor de 500 vectores.
Una vez almacenados los vectores, agregar el endpoint de búsqueda semántica requirió solo unas pocas líneas. El soporte vectorial de MariaDB ocultó gran parte de la complejidad.
El código fuente#
Puedes encontrar el código en GitHub. Hay un programa muy simple y fácil de seguir en webinar-main.py y otro más elaborado con buenas prácticas en backend.py. Si lo deseas, clona el repositorio, modifícalo, experimenta con tus propios datos y cuéntanos si te gustaría ver algo más en la integración de LangChain con MariaDB.
¿Te gustó este artículo? Puedo ayudar a tu equipo a implementar soluciones similares. Contáctame para saber más.
