Blomma Vector Search
2025-10-08
Blomma needed a way to find visually similar plants. Not just "same genus" similar, but "these would look good planted together" similar. I built it using Voyage AI embeddings at 1024 dimensions, stored in Postgres with pgvector and queried through HNSW indexes. The index parameters landed at m=16 and ef_construction=64 after testing, which gives a good balance between recall accuracy and index build time for a catalog of a few thousand plants.
The embedding approach matters here. I generate vectors from plant images, which captures visual features like leaf shape, flower color, and growth habit. A text-based embedding would group plants by their botanical descriptions, which correlates with taxonomy more than aesthetics. Image embeddings let a trailing rosemary show up as similar to a cascading sedum because they share that same draping, textured look, even though they're botanically unrelated. That's the kind of connection a gardener actually wants when browsing.
The harder problem is combining vector similarity with relational filters. A user searching for plants similar to a Japanese maple but filtered to hardiness zone 5 and partial shade needs both systems working together. Pure vector search returns the nearest neighbors in embedding space, but those neighbors might be zone 9 tropicals. I handle this with a hybrid query: first filter by relational constraints (zone, sun exposure, water needs), then run the vector similarity search within that filtered set. The alternative, running vector search first and filtering after, risks returning too few results when the constraints are tight. Pre-filtering keeps the result count predictable.
The interesting tension is that "similar" is genuinely ambiguous in this domain. A landscape designer wants aesthetic similarity: color palette, texture, form. A botanist wants phylogenetic similarity: genus, family, growth characteristics. A home gardener wants care similarity: same watering schedule, same sun needs. I chose to optimize for the aesthetic case because that's the gap no plant database fills well. Care requirements are already structured data you can filter on. Visual harmony is the thing that's hard to search for without embeddings, and it's the thing that makes a garden feel intentional rather than assembled.