Ir al contenido

Búsqueda por palabras clave vs. búsqueda semántica con IA

·915 palabras·5 mins
Bases De Datos IA
Alejandro Duarte
Autor
Alejandro Duarte
Alejandro Duarte es Ingeniero de Software, escritor, Ingeniero de Relaciones con Desarrolladores en MariaDB y consultor en desarrollo de software. Ha programado computadores desde mediados de los 90s. Comenzando con BASIC, Alejandro transitó a C, C++ y Java durante sus años académicos en la Universidad Nacional de Colombia. Se mudó primero al Reino Unido y luego a Finlandia para profundizar su participación en la industria del código abierto. Alejandro es reconocido en círculos de Java y MariaDB.
Tabla de contenido

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:

  1. 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.
  2. Almacené esos vectores en MariaDB usando la integración para LangChain.
  3. 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 con langchain_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:

EnfoqueVentajasDesventajas
Búsqueda por palabra claveRápida de implementar, usa SQL directoLimitada a coincidencias literales
Búsqueda semánticaEntiende contexto e intención, más flexibleRequiere 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.

Relacionados

¿Qué es un vector en IA y RAG?
·926 palabras·5 mins
Bases De Datos IA
¿Qué son exactamente las incrustaciones vectoriales en aplicaciones de IA y cómo usarlas en arquitecturas RAG?
Construyendo aplicaciones con IA generativa localmente
·1278 palabras·6 mins
Bases De Datos IA
Aprende a configurar y ejecutar embedders y LLMs localmente para almacenar y consultar vectores de manera eficiente en MariaDB.
¿Qué puede salir mal al usar transacciones en una base de datos?
·614 palabras·3 mins
Bases De Datos
Los fenómenos de concurrencia son anomalías que todo desarrollador de software debe conocer.