SemiLayerDocs

Search — Filters & mode

Vector search answers "closest to my query." Two knobs widen its reach: the mode parameter (semantic vs keyword vs hybrid) and — for predicate-based narrowing — the query() primitive that pairs naturally with search.

searchproducts
products: {
  source: 'main',
  table: 'products',
  fields: {
    id:          { type: 'number',  primaryKey: true },
    name:        { type: 'text',    searchable: { weight: 2 } },
    description: { type: 'text',    searchable: true },
    category:    { type: 'enum',    values: ['footwear', 'apparel', 'accessories'] },
    in_stock:    { type: 'boolean' },
  },
  grants: { search: 'public' },
}

The three modes

ModeWhen to useBehavior
semanticNatural-language queries, discovery, chat groundingPure vector similarity
keywordExact tokens matter: SKUs, slugs, brand namesFull-text scoring only
hybridMixed intent: "nike running shoes", "react hooks tutorial"Blends both scores

Mode is a per-call choice — pass mode: 'keyword' | 'hybrid' on the request, or reach for the sugar methods beam.<lens>.searchKeyword(...) and beam.<lens>.searchHybrid(...). Default is semantic.

Narrowing with a predicate pre-query

Need to restrict candidates to "footwear that's in stock" before ranking? Run a query() on the same lens to get matching IDs, then filter search results client-side.

import { beam } from './beam'

// Step 1: narrow via structured predicate
const { rows } = await beam.products.query({
  where: { category: 'footwear', in_stock: true },
  select: ['sourceRowId'],
  limit: 1000,
})

// Step 2: rank with hybrid mode
const { results } = await beam.products.search({
  query: 'running shoes',
  mode: 'hybrid',
  limit: 10,
})

// Step 3: intersect
const allowed = new Set(rows.map((r) => r.sourceRowId))
const filtered = results.filter((r) => allowed.has(r.sourceRowId))
ℹ️

A single-call where predicate inside search() is on the roadmap — for now combine query() + search(), or narrow via a joined lens using include: { relationName: { where: ... } }.