Table of contents :

Your First Semantic Product Search

100-days-of-weaviate-016

Table of contents :

Semantic product search lets shoppers describe what they need in natural language instead of matching only the exact words stored in a product title. A shopper searching for “a lightweight jacket for rainy city commutes” can discover products described as “packable waterproof shell” even when the wording is different.

For a WooCommerce agency, the first implementation should be narrow and measurable: index a useful product representation, run a near_text query, return product IDs, and let WooCommerce remain the source of truth for price, stock, and checkout data.

Choose the product data to index

Do not send an entire rendered product page to the vectorizer. Build a clean text representation from fields that describe the product’s meaning and intended use.

  • Product name: Include the customer-facing name.
  • Short description: Include the primary use case and key benefits.
  • Categories and attributes: Include values such as “waterproof,” “running,” “organic cotton,” or “USB-C.”
  • Brand: Include the brand when it helps customers distinguish products.
  • Product ID and URL: Store these as ordinary properties for retrieval and linking. They are identifiers, not semantic text.

A practical representation might look like this:

Product: Alpine Shell Jacket
Brand: North Ridge
Category: Men's outerwear, rain jackets
Description: Lightweight waterproof jacket for commuting, hiking, and travel.
Features: Packable, breathable membrane, adjustable hood, sealed seams.

Keep operational values such as stock quantity, regular price, sale price, and SKU in separate properties. These values are usually better handled with filters or a live WooCommerce lookup than by relying on vector similarity.

Create a Product collection

The exact vectorizer depends on your Weaviate deployment. The following example uses the Python client and an OpenAI-backed vectorizer configuration. Use the vectorizer available in your cluster, and configure its credentials through environment variables rather than committing them to a plugin or repository.

import weaviate
from weaviate.classes.config import Configure, DataType, Property

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=WEAVIATE_URL,
    auth_credentials=weaviate.auth.Auth.api_key(WEAVIATE_API_KEY),
)

products = client.collections.create(
    name="Product",
    vector_config=Configure.Vectors.text2vec_openai(),
    properties=[
        Property(name="productId", data_type=DataType.TEXT),
        Property(name="name", data_type=DataType.TEXT),
        Property(name="description", data_type=DataType.TEXT),
        Property(name="category", data_type=DataType.TEXT),
        Property(name="attributes", data_type=DataType.TEXT_ARRAY),
        Property(name="url", data_type=DataType.TEXT),
        Property(name="searchText", data_type=DataType.TEXT),
        Property(name="stockStatus", data_type=DataType.TEXT),
    ],
)

Collection configuration is normally run once during deployment rather than every time the WooCommerce search endpoint receives a request. In a production integration, check whether the collection exists before creating it, or manage the schema through a deployment script.

Import WooCommerce products

Generate one consistent searchText value for each published product. Exclude private notes, customer-specific pricing, internal procurement data, and duplicated boilerplate. For variable products, decide whether shoppers search the parent product or individual variations. Index variations separately only when size, material, color, or another variation attribute changes search relevance.

from weaviate.util import generate_uuid5

product = {
    "productId": "8421",
    "name": "Alpine Shell Jacket",
    "description": "Lightweight waterproof jacket for commuting, hiking, and travel.",
    "category": "Men's outerwear, rain jackets",
    "attributes": ["packable", "breathable", "sealed seams"],
    "url": "https://shop.example.com/product/alpine-shell-jacket/",
    "stockStatus": "instock",
    "searchText": (
        "Product: Alpine Shell Jacket. Brand: North Ridge. "
        "Category: Men's outerwear, rain jackets. "
        "Lightweight waterproof jacket for commuting, hiking, and travel. "
        "Features: packable, breathable membrane, adjustable hood, sealed seams."
    ),
}

products.data.insert(
    properties=product,
    uuid=generate_uuid5(product["productId"]),
)

Use a deterministic UUID derived from the WooCommerce product ID. That makes retries idempotent and allows an update job to replace the correct object instead of creating duplicates. For a catalog import, batch objects and record failures so one malformed product does not stop the entire synchronization.

Run the first semantic query

The simplest query accepts natural-language input and returns the nearest product vectors. Request only the properties needed to render search results.

from weaviate.classes.query import MetadataQuery

response = products.query.near_text(
    query="lightweight waterproof jacket for rainy bike commutes",
    limit=8,
    return_properties=["productId", "name", "description", "url"],
    return_metadata=MetadataQuery(distance=True),
)

for item in response.objects:
    print(item.properties["productId"], item.properties["name"], item.metadata.distance)

The distance is useful for diagnostics, but it is not automatically a customer-facing relevance score. Test several queries and inspect where useful results stop. A minimum-distance threshold can prevent unrelated products from appearing when a query has no strong match, but choose that threshold from evaluation data rather than guessing.

Combine semantic relevance with WooCommerce constraints

Semantic similarity should not replace commerce rules. A customer asking for “black running shoes under $120” expects both conceptual relevance and enforceable constraints. Store filterable fields in Weaviate when they are stable and needed during retrieval, or run a second WooCommerce lookup when price and stock must be authoritative at request time.

from weaviate.classes.query import Filter

response = products.query.near_text(
    query="supportive shoes for long-distance running",
    filters=Filter.by_property("stockStatus").equal("instock"),
    limit=12,
    return_properties=["productId", "name", "url"],
)

For price, a common architecture is to retrieve a wider semantic candidate set, collect the returned product IDs, and ask WooCommerce for current prices and inventory. Apply the customer’s price and availability rules there before rendering results. This avoids serving stale stock or sale information from the vector index.

Use hybrid search for SKU and product-name queries

Pure semantic search is not ideal for every query. Exact identifiers such as SKUs, model numbers, technical standards, and distinctive product names often perform better with lexical matching. Weaviate’s hybrid search combines keyword and vector signals.

response = products.query.hybrid(
    query="NR-ALPINE-8421 waterproof jacket",
    alpha=0.35,
    limit=8,
    return_properties=["productId", "name", "description", "url"],
)

The alpha value controls the balance between vector and keyword relevance. A lower value gives more weight to keyword matching; a higher value gives more weight to semantic similarity. Validate the setting against real search logs. You can also route queries that contain a known SKU pattern directly to an exact WooCommerce lookup.

Expose results through a WordPress endpoint

Keep Weaviate credentials on the server. A WordPress REST endpoint or a WooCommerce-side application service should accept the search phrase, validate pagination and limits, query Weaviate, and return product IDs or sanitized result objects. The browser should never receive the Weaviate API key.

When the endpoint receives the result IDs, fetch or verify the current WooCommerce data before displaying price, stock, add-to-cart controls, and variation selectors. Cache repeated queries briefly, but use an invalidation mechanism when products are unpublished or their searchable content changes.

Evaluate before expanding the feature

Create a small test set from real customer language rather than relying on a few impressive examples. Include broad use-case queries, exact product names, misspellings, attribute combinations, out-of-stock products, and queries with price constraints. For each query, record whether the first few results are relevant and whether the result can be purchased.

  1. Export a representative set of WooCommerce products.
  2. Generate search text with the same code used in production.
  3. Run at least 20 to 50 realistic queries.
  4. Inspect the top five results and label relevance.
  5. Compare semantic, keyword, and hybrid retrieval.
  6. Measure latency separately for Weaviate retrieval and WooCommerce data hydration.

Start with a read-only search experience and log anonymous query, returned product IDs, click-through, and add-to-cart events according to the store’s privacy requirements. These signals will show whether the semantic index improves discovery and which product fields need better content.

Trending posts
You might also like