Por qué necesitábamos un buscador
La Biblioteca de iconos de Jinero reúne 280.101 iconos SVG gratuitos y de código abierto en 237 paquetes: Lucide, Heroicons, Tabler, Material Symbols, Phosphor, IconPark, Bootstrap Icons y decenas más. Puedes filtrarlos, ver cualquier icono a tamaño completo, copiarlo como SVG, exportarlo como PNG en ocho tamaños, reunir una selección y llevártela como un único sprite, una fuente de iconos o un ZIP con el
Generador de fuentes de iconos / sprites. El mismo catálogo alimenta nuestra
API pública, el plugin de Figma y el
servidor MCP.
Esa escala es justo el problema.
Un paquete de 300 iconos no necesita buscador: basta con desplazarse por él. Con 280.000, el catálogo vale lo que vale la forma de llegar a lo que buscas. Y resulta que “la forma de llegar” son dos problemas completamente distintos que comparten el mismo campo de texto.
El primer problema es la velocidad. Escribes arrow y esperas ver resultados antes de terminar la palabra. Eso es una cuestión de base de datos.
El segundo problema es el vocabulario. Necesitas un icono para “el usuario cierra sesión”, y el icono que buscas se llama sign-out-alt en un paquete, logout en otro, exit_to_app en un tercero y door-open en un cuarto. No conoces ninguno de esos nombres. Y eso ya no es una cuestión de base de datos en absoluto.
Los resolvimos por separado, y lo interesante es por qué no se podían resolver juntos.
Método 1 — búsqueda por palabras clave, y por qué no es un simple LIKE
La búsqueda por defecto es instantánea y se ejecuta con cada pulsación de tecla. Tiene que ser una consulta a la base de datos: nada más responde en decenas de milisegundos sobre 280.000 filas.
La versión ingenua es WHERE name LIKE '%arrow%'. Y también es inútil: no puede ordenar por relevancia, no sabe manejar dos palabras y recorre toda la tabla.
Lo que realmente se ejecuta es una consulta FULLTEXT booleana de MySQL sobre una columna dedicada, search_keywords. Cada término de tres o más caracteres se convierte en una coincidencia de prefijo obligatoria:
"shopping cart" → +shopping* +cart*
Los términos de menos de tres caracteres pasan a un LIKE sobre el nombre, porque FULLTEXT los ignora. Limitamos la consulta a ocho términos: a partir de ahí, el usuario no está buscando, está pegando texto.
Medido en producción:
| Consulta | Tiempo | Resultados |
|---|---|---|
delete |
37 ms | 2.143 |
sign out |
41 ms | 420 |
shopping cart |
37 ms | 1.746 |
La columna que hace el trabajo de verdad
search_keywords no es el nombre del icono. Es un bloque de texto enriquecido con sinónimos que se genera al importar los iconos, y ahí está la mayor parte de la calidad.
Mantenemos 313 grupos de sinónimos; cada uno reúne un concepto con todas las palabras que los diseñadores usan de verdad para nombrarlo:
delete → trash → remove → bin → erase
edit → modify → pencil → pen → write
add → plus → create → new → insert
Escribe delete y obtendrás iconos llamados trash, bin y remove, porque al importarlos todas esas palabras se escribieron en el mismo bloque de búsqueda. No cuesta nada en el momento de la consulta: el trabajo se hizo una vez, por adelantado.
Hay un caso especial que vale la pena mencionar, porque falló de una forma que no esperábamos. Los iconos de banderas se llaman por su código ISO: Jp, Ua, De. Nadie busca “Jp”, sino “Japan”. Así que en los paquetes de banderas incorporamos a las palabras clave el nombre del país y sus alias.
Pero solo en los paquetes de banderas. La primera versión lo hacía en todo el catálogo, y el resultado fue absurdo: los códigos ISO in, it, is y no son palabras corrientes en inglés, así que al buscar “no entry” empezaron a salir banderas de Noruega e Italia. La solución no fue una coincidencia más inteligente, sino limitar el mapa de países a kind=flag y dejar en paz el resto del catálogo.
Dónde se detiene la búsqueda por palabras clave
Pídele algo que puedas describir pero no nombrar:
"something went wrong" → nothing found
No es un mal resultado. Es ningún resultado. No hay ningún icono entre 280.000 cuyas palabras clave contengan esa frase, ni lo habrá nunca, porque describe una situación, no un dibujo.
Ese es el muro. No se puede salir de ahí a base de sinónimos: haría falta un grupo de sinónimos para cada idea que pueda tener una persona. Aquí es donde empieza el segundo método.
Método 2 — búsqueda por el aspecto del icono
La segunda búsqueda no lee nombres. Mira la imagen.
La idea es la misma que hay detrás de nuestro Identificador de fuentes: convertir la cosa en un vector de números y luego comparar números. Pero mientras que el identificador compara imagen con imagen, aquí necesitamos comparar texto con imagen: tu frase con un dibujo.
Eso es exactamente lo que hace un modelo de visión y lenguaje. Representa imágenes y textos en un mismo espacio compartido, de modo que “una papelera con tapa” y el dibujo real de una papelera quedan muy cerca.
El modelo que no entrenamos
Para el Identificador de fuentes entrenamos nuestro propio modelo, y superó a todas las opciones ya hechas. Así que aquí el primer instinto fue el mismo: entrenar un modelo contrastivo con nuestros propios iconos.
Empezamos, y luego paramos.
Las fuentes y los iconos son problemas distintos. Las fuentes se diferencian por detalles finísimos (la forma de un terminal, el eje de una panza) y ningún modelo de uso general está entrenado para fijarse en eso. Los iconos son lo contrario: son dibujos de cosas corrientes. Una papelera, una flecha, un carrito de compra. Los modelos de visión y lenguaje de uso general han visto millones.
Así que usamos SigLIP2 (so400m-patch16-384) tal cual. Entrenar el nuestro nos habría costado semanas para acabar por detrás de él. La respuesta de ingeniería honesta era no construirlo.
Es la imagen invertida de la historia del identificador de fuentes, y ambas decisiones salieron de la misma pregunta: ¿de verdad el modelo general es malo en esto? Con las fuentes, lo era. Con los iconos, no.
Qué funciona en producción
Cada icono del índice pasó una vez por SigLIP, por adelantado, y generó un vector de 1.152 números:
siglip_index.npz 259,301 × 1152, float16 586 MB
service RAM ~1.2 GB
Un contenedor aparte, siempre encendido, mantiene en memoria el modelo y todo el índice. Una consulta convierte tu texto en un vector (es la única llamada al modelo) y luego todo se reduce a un producto escalar contra un cuarto de millón de filas.
| Endpoint | Tiempo |
|---|---|
/search (texto → icono) |
257–343 ms |
/similar (icono → icono) |
35 ms |
La búsqueda por texto es un orden de magnitud más lenta porque codificar tu frase es la parte cara; comparar vectores después sale casi gratis. Por eso también “Similares” es tan rápido: el vector ya existe, así que no hay ninguna llamada al modelo.
Por eso la búsqueda profunda es un botón y no la opción por defecto. 300 ms están bien cuando lo pulsas a propósito, pero mientras escribes resultaría inutilizable. La búsqueda por palabras clave sigue siendo instantánea y la profunda se activa solo si quieres.
Le da igual en qué idioma preguntes
Esta es la parte que sorprende a la gente, y no es una función que hayamos creado nosotros. Viene de serie con el modelo, porque SigLIP aprendió texto e imágenes a la vez en muchos idiomas.
La misma pregunta, en tres idiomas, con resultados reales de producción:
| Consulta | Tiempo | Primeros resultados |
|---|---|---|
throw it away |
257 ms | Reuse · Garbage Throw · Litter In Bin Sign · Bin |
викинути у смітник |
302 ms | Garbage Throw · Litter In Bin Sign · Bin |
ゴミ箱に捨てる |
343 ms | Delete · Delete Sweep · Trash · Trashcan |
Ninguno de esos iconos tiene una sola palabra en ucraniano o japonés en sus metadatos. El catálogo está íntegramente en inglés. El modelo no compara palabras: relaciona el significado con la imagen.
Las dos búsquedas no se sustituyen — se combinan
La búsqueda profunda no descarta los resultados por palabras clave. Ejecuta ambas y une los resultados: primero los semánticos y después los de palabras clave, con los filtros aplicados sin alterar ese orden y en caché durante cinco minutos para que la paginación no vuelva a ejecutar el modelo.
Y si el servicio de búsqueda no está disponible, el interruptor vuelve sin avisar a la búsqueda por palabras clave. Una búsqueda más lenta es una función; una búsqueda rota es una caída del servicio.
Buscar similares — el mismo índice, en la otra dirección
La vista de detalle de cada icono tiene un botón Similares. Toma el vector de ese icono, que ya está en el índice, y devuelve sus vecinos más cercanos entre los 280.000, en 35 ms. Sirve para encontrar un estilo a juego o una versión mejor dibujada del icono que has encontrado.
También nos enseñó algo que conviene decir sin rodeos, porque es la limitación más clara de todo el sistema.
Pide iconos similares a una papelera llena y obtendrás:
Pail · Accumulation Precipitation · Glas Water · Specific Gravity
Un cubo. Un recipiente con agua. No tienen relación semántica con borrar cosas, pero son absoluta e innegablemente parecidos a la vista. Una papelera y un cubo tienen la misma forma.
Eso es lo que significa la similitud de imagen a imagen, y conviene dejarlo claro: “Similares” encuentra iconos que se parecen, no iconos que significan lo mismo. Cuando buscas un estilo visual a juego, es exactamente lo que necesitas. Cuando esperas “más iconos de borrar”, no.
En qué todavía se equivoca
La búsqueda profunda no es magia, y su forma de fallar es muy concreta: es buena con las cosas y mala con las situaciones.
"something went wrong" → Compass South West · Compass West Arrow · Roadmap · Phone Off
Aquí la búsqueda por palabras clave no devuelve nada; la profunda devuelve cuatro respuestas erróneas con total seguridad. Cuál de las dos cosas es peor es una auténtica cuestión de UX. Un resultado vacío te dice que reformules. Un resultado erróneo te dice que el catálogo no tiene lo que buscas, y eso es mentira.
Los objetos concretos funcionan: a bin with a lid, bicycle, wifi off. Las abstracciones se desvían: estados de error, emociones, “de aspecto profesional”.
También hay una propiedad estructural que conviene entender, porque explica las diferencias ocasionales entre las dos búsquedas.
Un índice vectorial describe el recurso tal como era cuando se construyó el índice, no como es ahora. La búsqueda por palabras clave lee la base de datos, así que un paquete recién importado se puede buscar en cuanto llega. La búsqueda profunda lee un archivo de vectores precalculados, así que los iconos nuevos se incorporan en la siguiente reconstrucción. Es el precio de responder en 300 ms en lugar de en 300 segundos.
Aprendimos por las malas hasta qué punto es literal. En un momento dado, 616 iconos de IconPark se mostraban como formas negras sólidas por un error de máscaras en los SVG originales. Los dibujos se repararon, y cualquiera que explore la biblioteca los ve correctamente. Pero un embedding calculado a partir del renderizado defectuoso codifica exactamente eso: un rectángulo negro. La imagen y su descripción de la imagen son dos artefactos distintos, y arreglar uno no arregla el otro. Precisamente por eso, recalcular los embeddings cuando cambia un paquete forma parte de la rutina de importación.
Dónde se usa cada una
No en todas partes, y es a propósito.
La API pública, el plugin de Figma y el servidor MCP solo usan palabras clave. Están pensados para máquinas: una integración quiere una respuesta rápida, predecible y barata, y normalmente ya sabe qué palabra busca. La búsqueda semántica cuesta ~300 ms y un modelo siempre cargado en memoria; la activaremos ahí cuando alguien la necesite de verdad, con sus propios límites de solicitudes.
La búsqueda profunda y Similares están en la biblioteca web, donde una persona mira una cuadrícula y piensa “eso no, algo más parecido a esto”.
La conclusión
Dos búsquedas, porque hay dos preguntas.
Cuando sabes la palabra, gana la base de datos: 37 ms, resultados ordenados por relevancia y se ejecuta con cada pulsación de tecla. La mayoría de las búsquedas son así. El trabajo que la hace buena se hizo por adelantado, en una tabla de sinónimos, no en el momento de la consulta.
Cuando solo sabes el significado, gana el modelo, y responde en un idioma al que el catálogo nunca se ha traducido.
La decisión de ingeniería de la que estamos más satisfechos es aquella en la que no escribimos ningún modelo. Con las fuentes, entrenar el nuestro superó todo lo disponible. Con los iconos, el mejor modelo disponible ya era mejor que lo que habríamos construido. Saber en qué situación estás es la mayor parte del trabajo.
Comentarios 0
Inicia sesión para dejar el primer comentario.