Getting Started with Unified Search Engine

Enable the module, configure which collections to index, set up semantic search (optional), test queries — 4 steps to enterprise search.

1

Enable Search Module

Admin → Modules → Search → Enable:

``` Module enabled. Search API: /search Default mode: hybrid

Collections to index: None configured yet. Semantic search: Not configured. ```

Verify search is working:

``` GET /api/search?q=test

Response: { "data": { "results": [], "meta": { "query": "test", "mode": "hybrid", "timing": 2, // 2ms "totalResults": 0 } } } ```

Test with content:

1. Create a product: "Wireless Bluetooth Headphones" 2. Wait for indexing (automatic, same-transaction) 3. Search: GET /api/search?q=wireless 4. Result: product found, highlighted

2

Configure Collections to Index

Admin → Search → Index Configuration:

Full-text indexing (automatic on all collections):

``` All collections with text fields are auto-indexed for full-text.

Collections detected: ✅ products (title, description, tags) ✅ pages (title, content, metaDescription) ✅ contacts (name, email, company) ✅ companies (name, description, industry) ✅ blog posts (title, content, tags) ✅ helpdesk tickets (subject, body) ... (all collections with text fields)

You don't need to configure anything. Full-text works automatically. ```

Column weights (optional):

javascript // Admin → Search → Index Config → Column Weights { "products": { "title": 3, // A weight — most important "description": 2, // B weight — secondary "tags": 1, // C weight — tertiary "specs": 1, }, "pages": { "title": 3, "metaDescription": 2, "content": 1, }, "contacts": { "name": 3, "email": 2, "company": 1, } }

Fields to exclude:

```javascript // Some fields should not be searched: // • Large text blocks (body, content) — only index first 1000 chars // • System fields (id, timestamps, internal notes) // • Sensitive data (SSN, credit card numbers)

{ "orders": { "excludeFromIndex": ["notes", "internalComments", "creditCardLast4"], "maxCharsPerField": 1000 } } ```

3

Enable Semantic Search (Optional)

Semantic search uses AI embeddings to understand meaning, not just keywords.

Prerequisite: OpenAI or Anthropic API key

``` Admin → Search → Semantic Search → Configure

AI Provider: OpenAI API Key: sk-... (your key) Model: text-embedding-3-small (1536 dims, $0.02/1M tokens) ```

Any embedding-capable provider configured on your tenant's AI settings can back semantic search (OpenAI, Voyage, Cohere, Mistral, Google, and others) — pick the one your tenant already uses for embeddings.

Enable semantic on collections:

``` Admin → Search → Semantic Search → Collections

Select collections to vectorize: ✅ products (product name, description, tags) ✅ blog posts (title, content, tags) ❌ pages (use full-text only — changing content) ❌ contacts (privacy concerns with embeddings)

Click "Generate Embeddings" → Background job starts → Progress: 0% → 100% → Embeddings stored in pgvector ```

Index status:

``` Admin → Search → Vector Index

Collections indexed: products: Status: ✅ Complete Documents: 10,000 Avg tokens/doc: 127 Total cost: $0.13 Last updated: 2024-01-15 14:32

blog posts: Status: ✅ Complete Documents: 500 Avg tokens/doc: 89 Total cost: $0.01 Last updated: 2024-01-15 14:30 ```

Incremental updates:

``` When you create/update a product: 1. Save product to PostgreSQL (normal) 2. Search module detects change 3. Generate embedding for changed fields 4. Upsert to embeddings table 5. Product is semantically searchable immediately

No manual re-indexing needed. ```

4

Test Queries and Monitor Analytics

Test search modes:

Full-text:

``` GET /api/search

{ "query": "wireless headphones noise cancelling", "mode": "fulltext", "collections": ["products"], "limit": 10 }

Response: { "data": { "results": [ { "collection": "products", "id": "p_123", "title": "Wireless Bluetooth Headphones Pro", "highlight": "<em>Wireless</em> <em>Bluetooth</em> <em>Headphones</em> <em>Pro</em> with active <em>noise</em> <em>cancelling</em>", "score": 0.95, "route": "/admin/commerce/products/p_123" } ], "meta": { "mode": "fulltext", "timing": 8, "totalResults": 15 } } } ```

Semantic (concept-based):

``` GET /api/search

{ "query": "something to listen to music while exercising", "mode": "semantic", "collections": ["products"], "limit": 10 }

Response: { "data": { "results": [ { "collection": "products", "id": "p_123", "title": "Sport Wireless Earbuds", "score": 0.91, "route": "/admin/commerce/products/p_123" } // ← "Sport Wireless Earbuds" wasn't in the query // but semantically similar → returned by meaning, not keyword ] } } ```

Hybrid (RRF fusion):

``` GET /api/search

{ "query": "best laptop for video editing", "mode": "hybrid", "collections": ["products"], "limit": 10 }

Response: { "data": { "results": [ { "collection": "products", "id": "p_456", "title": "MacBook Pro 16 — Video Editing Powerhouse", "score": 0.94, "sources": { "fulltext": 1, "semantic": 1 }, // ↑ Rank 1 in BOTH engines → RRF fusion boosted it "route": "/admin/commerce/products/p_456" } ], "meta": { "mode": "hybrid", "fulltextResults": 20, "semanticResults": 18, "fusionTiming": 3, "totalTiming": 28 } } } ```

Monitor search analytics:

``` Admin → Search → Analytics

Top queries today: 1. "wireless headphones" — 1,247 searches 2. "iphone case" — 892 searches 3. "laptop stand" — 654 searches

Queries with no results (opportunities): 1. "hdmi cable 6ft" — 234 searches, 0 results 2. "water bottle metal" — 156 searches, 0 results → Action: Create products for these searches ```

Each query's timing (db, embedding, total) is recorded per-search, so you can spot slow queries or modes from the raw search_queries log.

Setup FAQ

No. The moment the module is enabled, every collection with text fields is auto-indexed — products, pages, contacts, tickets, and the rest work immediately. Column weights and field exclusions are optional refinements, not prerequisites.

No. Full-text and hybrid both work out of the box. Semantic search is opt-in — it needs an embedding-capable provider key on your tenant's AI settings, and you enable it per collection when you want meaning-based matching rather than keyword matching.

hybrid. It runs the full-text and semantic queries in parallel and blends them with Reciprocal Rank Fusion, so a result can win on keywords, on meaning, or both. You can override it per query with `mode: "fulltext"` or `mode: "semantic"`.

No. Full-text updates in the same transaction as the write. For semantic collections, the changed fields are re-embedded and upserted automatically in the background — there's no manual re-indexing job to run.

You bring your own embedding provider and pay their rate with zero platform markup. For example, `text-embedding-3-small` is $0.02 per 1M tokens, so tens of thousands of typical documents index for only cents.