Zwei Wege, ein Icon unter 280.000 zu finden

Zwei Wege, ein Icon unter 280.000 zu finden

Warum wir überhaupt eine Suche brauchten

Die Icon-Bibliothek von Jinero umfasst 280.101 kostenlose Open-Source-SVG-Icons in 237 Paketen – Lucide, Heroicons, Tabler, Material Symbols, Phosphor, IconPark, Bootstrap Icons und Dutzende weitere. Du kannst sie filtern, jedes Icon in voller Größe ansehen, als SVG kopieren, als PNG in acht Größen exportieren, eine Auswahl zusammenstellen und sie mit dem Icon-Font- & Sprite-Generator als ein Sprite, einen Icon-Font oder ein ZIP ausliefern. Derselbe Katalog speist unsere öffentliche API, das Figma-Plugin und den MCP-Server.

Genau diese Größe ist das Problem.

Ein Paket mit 300 Icons braucht keine Suche – da scrollst du einfach durch. Bei 280.000 ist der Katalog nur so gut wie der Weg hinein. Und dieser „Weg hinein“ entpuppt sich als zwei völlig unterschiedliche Probleme, die sich ein Eingabefeld teilen.

Das erste Problem ist Geschwindigkeit. Du tippst arrow und erwartest Ergebnisse, bevor du das Wort zu Ende geschrieben hast. Das ist eine Frage für die Datenbank.

Das zweite Problem ist der Wortschatz. Du brauchst ein Icon für „der Nutzer meldet sich ab“, und das gesuchte Icon heißt in einem Paket sign-out-alt, im zweiten logout, im dritten exit_to_app und im vierten door-open. Keinen dieser Namen kennst du. Das ist überhaupt keine Frage für die Datenbank.

Wir haben beide getrennt gelöst – und das Spannende ist, warum sie sich nicht gemeinsam lösen ließen.


Methode 1 – Stichwortsuche, und warum sie mehr ist als LIKE

Die Standardsuche reagiert sofort und läuft bei jedem Tastendruck. Sie muss eine Datenbankabfrage sein – nichts anderes antwortet bei 280.000 Zeilen innerhalb weniger Dutzend Millisekunden.

Die naive Variante ist WHERE name LIKE '%arrow%'. Sie ist allerdings nutzlos: Sie kann nicht ranken, kommt mit zwei Wörtern nicht klar und durchsucht die ganze Tabelle.

Tatsächlich läuft eine boolesche FULLTEXT-Abfrage in MySQL gegen eine eigene Spalte, search_keywords. Jedes Token ab drei Zeichen wird zu einem Pflicht-Präfixtreffer:

"shopping cart"  →  +shopping* +cart*

Kürzere Tokens fallen auf ein LIKE über den Namen zurück, weil FULLTEXT sie ignoriert. Wir begrenzen die Abfrage auf acht Tokens – wer mehr eingibt, sucht nicht mehr, sondern fügt einen Text ein.

Gemessen in der Produktion:

Anfrage Zeit Ergebnisse
delete 37 ms 2.143
sign out 41 ms 420
shopping cart 37 ms 1.746

Die Spalte, die die eigentliche Arbeit macht

search_keywords ist nicht der Name des Icons. Es ist ein mit Synonymen angereicherter Blob, der beim Import erstellt wird – und hier steckt der Großteil der Qualität.

Wir pflegen 313 Synonymgruppen; jede fasst einen Begriff mit allen Wörtern zusammen, die Designer tatsächlich dafür verwenden:

delete → trash → remove → bin → erase
edit   → modify → pencil → pen → write
add    → plus → create → new → insert

Tippst du delete, bekommst du Icons namens trash, bin und remove, weil beim Import all diese Wörter in denselben durchsuchbaren Blob geschrieben wurden. Zur Abfragezeit kostet das nichts – die Arbeit wurde einmal erledigt, offline.

Ein Sonderfall ist erwähnenswert, weil er auf eine Weise kaputtging, mit der wir nicht gerechnet hatten. Flaggen-Icons sind nach ISO-Code benannt: Jp, Ua, De. Niemand sucht nach „Jp“ – man sucht nach „Japan“. Deshalb schreiben wir bei Flaggen-Paketen den Ländernamen und seine Aliasse in die Stichwörter.

Aber nur bei Flaggen-Paketen. Die erste Version machte das global, und das Ergebnis war absurd: Die ISO-Codes in, it, is und no sind gewöhnliche englische Wörter, also lieferte die Suche nach „no entry“ plötzlich norwegische und italienische Flaggen. Die Lösung war kein schlaueres Matching – sondern die Länderzuordnung auf kind=flag zu beschränken und den Rest des Katalogs in Ruhe zu lassen.

Wo die Stichwortsuche an ihre Grenzen stößt

Frag sie nach etwas, das du beschreiben, aber nicht benennen kannst:

"something went wrong"   →   nothing found

Kein schlechtes Ergebnis. Gar kein Ergebnis. Unter 280.000 Icons gibt es keines, dessen Stichwörter diese Phrase enthalten, und es wird nie eines geben, weil sie eine Situation beschreibt und kein Bild.

Das ist die Wand. Mit Synonymen kommst du da nicht heraus – du bräuchtest eine Synonymgruppe für jeden Gedanken, den ein Mensch haben kann. Hier beginnt die zweite Methode.


Methode 2 – Suche danach, wie das Icon aussieht

Die zweite Suche liest keine Namen. Sie schaut sich das Bild an.

Die Idee ist dieselbe wie bei unserer Schrifterkennung: das Ding in einen Zahlenvektor verwandeln und dann Zahlen vergleichen. Doch während die Schrifterkennung Bild mit Bild vergleicht, müssen wir hier Text mit Bild vergleichen – deinen Satz mit einer Zeichnung.

Genau das macht ein Vision-Language-Modell. Es bettet Bilder und Text in einen gemeinsamen Raum ein, sodass „ein Mülleimer mit Deckel“ und die tatsächliche Zeichnung eines Mülleimers nah beieinander landen.

Das Modell, das wir nicht trainiert haben

Für die Schrifterkennung haben wir ein eigenes Modell trainiert, und es schlug jede fertige Lösung. Also war der erste Impuls hier derselbe: ein kontrastives Modell auf unseren eigenen Icons trainieren.

Wir haben angefangen – und dann aufgehört.

Schriften und Icons sind unterschiedliche Probleme. Schriften unterscheiden sich in haarfeinen Details – der Form eines Endstrichs, der Achse einer Rundung –, und kein Allzweckmodell ist darauf trainiert, darauf zu achten. Bei Icons ist es umgekehrt: Sie sind Bilder alltäglicher Dinge. Ein Mülleimer, ein Pfeil, ein Einkaufswagen. Allzweck-Vision-Language-Modelle haben Millionen davon gesehen.

Deshalb nutzen wir SigLIP2 (so400m-patch16-384) unverändert. Ein eigenes Training hätte Wochen gekostet, nur um irgendwo dahinter zu landen. Die ehrliche Antwort aus Engineering-Sicht war, das Ding nicht zu bauen.

Das ist das Spiegelbild der Geschichte unserer Schrifterkennung, und beide Entscheidungen gingen auf dieselbe Frage zurück: Ist das allgemeine Modell darin wirklich schlecht? Bei Schriften war es das. Bei Icons ist es das nicht.

Was in der Produktion läuft

Jedes Icon im Index wurde einmal offline durch SigLIP geschickt, was jeweils einen Vektor aus 1.152 Zahlen ergab:

siglip_index.npz     259,301 × 1152, float16     586 MB
service RAM          ~1.2 GB

Ein separater, ständig laufender Container hält das Modell und den gesamten Index im Arbeitsspeicher. Eine Anfrage bettet deinen Text ein – das ist der einzige Modellaufruf –, danach folgt nur noch ein Skalarprodukt gegen eine Viertelmillion Zeilen.

Endpunkt Zeit
/search (Text → Icon) 257–343 ms
/similar (Icon → Icon) 35 ms

Die Textsuche ist eine Größenordnung langsamer, weil das Kodieren deines Satzes der teure Teil ist; der anschließende Vektorvergleich kostet fast nichts. Deshalb ist auch „Ähnliche“ so schnell: Der Vektor existiert bereits, es gibt also gar keinen Modellaufruf.

Deshalb ist die Deep-Suche ein Button und nicht der Standard. 300 ms sind in Ordnung, wenn du bewusst darauf klickst; als Suche beim Tippen wäre das unbrauchbar. Die Stichwortsuche bleibt sofort da, Deep schaltest du bei Bedarf zu.

Welche Sprache du nutzt, ist ihr egal

Dieser Teil überrascht die Leute – und wir haben ihn nicht einmal gebaut. Er kommt gratis mit dem Modell, weil SigLIP Text und Bilder gemeinsam in vielen Sprachen gelernt hat.

Dieselbe Frage, drei Sprachen, echte Ergebnisse aus der Produktion:

Anfrage Zeit Top-Ergebnisse
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

Keines dieser Icons hat irgendwo in seinen Metadaten ein ukrainisches oder japanisches Wort. Der Katalog ist komplett englisch. Das Modell gleicht keine Wörter ab – es ordnet einem Bild eine Bedeutung zu.

Die beiden Suchen ersetzen sich nicht – sie werden zusammengeführt

Die Deep-Suche verwirft die Stichworttreffer nicht. Sie führt beide Suchen aus und vereinigt die Ergebnisse: zuerst semantische Treffer, danach Stichworttreffer; Filter werden unter Beibehaltung dieser Reihenfolge angewendet, und alles wird fünf Minuten zwischengespeichert, damit beim Blättern das Modell nicht erneut läuft.

Und wenn der Suchdienst ausfällt, fällt der Schalter stillschweigend auf die Stichwortsuche zurück. Eine langsamere Suche ist eine Funktion; eine kaputte Suche ist ein Ausfall.


Ähnliche finden – derselbe Index, andere Richtung

In der Detailansicht jedes Icons gibt es einen Button Ähnliche. Er nimmt den Vektor dieses Icons – der schon im Index liegt – und liefert in 35 ms seine nächsten Nachbarn aus allen 280.000. Praktisch, um einen passenden Stil zu finden oder eine besser gezeichnete Version des gefundenen Icons.

Er hat uns auch etwas gelehrt, das man klar aussprechen sollte, weil es die deutlichste Grenze des ganzen Systems ist.

Frag nach Icons, die einem vollen Mülleimer ähneln, und du bekommst:

Pail · Accumulation Precipitation · Glas Water · Specific Gravity

Einen Eimer. Ein Gefäß mit Wasser. Mit dem Löschen von Dingen haben sie inhaltlich nichts zu tun – aber sie sehen absolut und unbestreitbar ähnlich aus. Ein Mülleimer und ein Eimer haben dieselbe Form.

Genau das bedeutet Bild-zu-Bild-Ähnlichkeit, und das sollte man klar sagen: „Ähnliche“ findet Icons, die gleich aussehen, nicht Icons, die das Gleiche bedeuten. Wenn du einen visuellen Stil treffen willst, ist das genau richtig. Wenn du „mehr Löschen-Icons“ erwartest, nicht.


Was noch nicht klappt

Die Deep-Suche ist keine Magie, und ihre Schwäche ist ganz konkret: Sie ist gut bei Dingen und schlecht bei Situationen.

"something went wrong"  →  Compass South West · Compass West Arrow · Roadmap · Phone Off

Die Stichwortsuche liefert hier nichts; Deep liefert vier selbstbewusste falsche Antworten. Was davon schlimmer ist, ist eine echte UX-Frage. Ein leeres Ergebnis sagt dir, dass du anders formulieren sollst. Ein falsches Ergebnis sagt dir, dass der Katalog nicht hat, was du suchst – und das ist eine Lüge.

Konkrete Objekte funktionieren: a bin with a lid, bicycle, wifi off. Abstraktes driftet ab: Fehlerzustände, Emotionen, „professionell aussehend“.

Es gibt außerdem eine strukturelle Eigenschaft, die man verstehen sollte, weil sie gelegentliche Unterschiede zwischen den beiden Suchen erklärt.

Ein Vektorindex beschreibt ein Asset so, wie es beim Erstellen des Index war, nicht wie es jetzt ist. Die Stichwortsuche liest die Datenbank, ein neu importiertes Paket ist also sofort durchsuchbar. Die Deep-Suche liest eine Datei mit vorab berechneten Vektoren, neue Icons kommen also erst beim nächsten Neuaufbau dazu. Das ist der Preis dafür, in 300 ms statt in 300 Sekunden zu antworten.

Wie wörtlich das gemeint ist, haben wir auf die harte Tour gelernt. Eine Zeit lang wurden 616 IconPark-Icons als massive schwarze Formen gerendert – ein Masken-Bug in den Quell-SVGs. Die Zeichnungen wurden repariert, und wer die Bibliothek durchstöbert, sieht sie korrekt. Doch ein Embedding, das aus dem kaputten Rendering berechnet wurde, kodiert genau das: ein schwarzes Rechteck. Das Bild und seine Beschreibung des Bildes sind zwei verschiedene Artefakte, und wer das eine repariert, hat das andere noch nicht repariert. Genau deshalb gehört das erneute Einbetten nach Änderungen an einem Paket zur Import-Routine.


Wo welche Suche eingebaut ist

Nicht überall – mit Absicht.

Die öffentliche API, das Figma-Plugin und der MCP-Server nutzen nur die Stichwortsuche. Sie richten sich an Maschinen: Eine Integration will eine schnelle, vorhersehbare, günstige Antwort und kennt meist schon das Wort, nach dem sie sucht. Semantische Suche kostet ~300 ms und ein ständig laufendes Modell im Arbeitsspeicher; dort schalten wir sie frei, wenn sie wirklich jemand braucht – mit eigenen Rate-Limits.

Deep-Suche und „Ähnliche“ gibt es in der Web-Bibliothek, wo ein Mensch auf ein Raster schaut und denkt: „Nicht das – eher so etwas wie das hier.“


Das Fazit

Zwei Suchen, weil es zwei Fragen gibt.

Wenn du das Wort kennst, gewinnt die Datenbank – 37 ms, mit Ranking, bei jedem Tastendruck. Die meisten Suchen sind so. Die Arbeit, die sie gut macht, passierte offline in einer Synonymtabelle, nicht zur Abfragezeit.

Wenn du nur die Bedeutung kennst, gewinnt das Modell – und es antwortet in einer Sprache, in die der Katalog nie übersetzt wurde.

Die technische Entscheidung, mit der wir am zufriedensten sind, ist die, bei der wir gar kein Modell gebaut haben. Bei Schriften schlug unser eigenes Training alles Verfügbare. Bei Icons war das beste verfügbare Modell bereits besser als alles, was wir selbst gebaut hätten. Zu erkennen, in welcher Situation man steckt, ist der Großteil der Arbeit.


239 Aufrufe 0 Kommentare

Kommentare 0

Melde dich an, um den ersten Kommentar zu schreiben.