E-Commerce Product Search
Build fast, relevant product search with Brinicle ItemSearchEngine
Overview
E-commerce platforms need search that understands both structured metadata (brand, category, price) and semantic intent (what the user actually means). Brinicle's ItemSearchEngine handles both in a single HNSW index, eliminating the need for separate lexical and vector search systems.
This is achieved through alpha-controlled scoring: structured lexical signals and optional semantic vectors are encoded into one numeric representation and searched through the same HNSW graph.
Setup
Lexical-Only Product Catalog
For pure structured search without embeddings:
import brinicle
engine = brinicle.ItemSearchEngine(
"products_index",
dim=96,
alpha=0.0, # lexical-only
)
engine.init(mode="build")
products = [
{
"id": "p1",
"title": "Apple iPhone 15 Pro Max 256GB Natural Titanium",
"category": "Electronics",
"subcategory": "Smartphones",
"attributes": {"brand": "Apple", "storage": "256GB", "color": "Natural Titanium"},
},
{
"id": "p2",
"title": "Samsung Galaxy S24 Ultra 512GB Black",
"category": "Electronics",
"subcategory": "Smartphones",
"attributes": {"brand": "Samsung", "storage": "512GB", "color": "Black"},
},
{
"id": "p3",
"title": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones",
"category": "Electronics",
"subcategory": "Headphones",
"attributes": {"brand": "Sony", "type": "Over-ear", "feature": "Noise Cancelling"},
},
]
for p in products:
engine.ingest(
external_id=p["id"],
title=p["title"],
category=p["category"],
subcategory=p["subcategory"],
attributes=p["attributes"],
)
engine.finalize()Hybrid Product Search with Embeddings
For combining structured filters with semantic understanding:
import numpy as np
import brinicle
VECTOR_DIM = 384
engine = brinicle.ItemSearchEngine(
"hybrid_products_index",
dim=96,
vector_dim=VECTOR_DIM,
alpha=0.95,
vector_normalized=True,
M=48,
ef_construction=1024,
ef_search=512,
)
engine.init(mode="build")
for p in products:
engine.ingest(
external_id=p["id"],
title=p["title"],
category=p["category"],
subcategory=p["subcategory"],
attributes=p["attributes"],
vector=np.random.randn(VECTOR_DIM).astype("float32"),
normalize=True,
)
engine.finalize()Searching
Basic Search
results = engine.search("iphone 15 pro max", k=10)Filtered Search with Metadata
results = engine.search(
"smartphone",
category="Electronics",
subcategory="Smartphones",
attributes={"brand": "Apple"},
k=10,
)Semantic Search with Vectors
query_vector = embed("best phone for photography") # your embedding function
results = engine.search(
"best phone for photography",
vector=query_vector,
normalize=True,
k=10,
)Autocomplete for Search Bar
Add typeahead suggestions using AutocompleteEngine:
ac = brinicle.AutocompleteEngine("suggestions_index", dim=48)
ac.init(mode="build")
ac.ingest("iphone 15 pro max", "iphone 15 pro max")
ac.ingest("iphone 15 case", "iphone 15 case")
ac.ingest("samsung galaxy s24", "samsung galaxy s24")
ac.ingest("wireless headphones", "wireless headphones")
ac.ingest("noise cancelling earbuds", "noise cancelling earbuds")
ac.finalize()
# As user types "iph"
suggestions = ac.search("iph", k=5)Performance
On 1.2 Million Amazon products, Brinicle achieved sub-millisecond p99 latency and 1,731 MB peak search memory, the lowest among Brinicle, Meilisearch, OpenSearch, Typesense, and Weaviate. It also achieved the best Hit@1 and nDCG@10 in that benchmark.