Implementing AI-Powered Semantic Search for Website Content

Ordinary site search only returns articles if they contain the exact query words. A user searches for "how to pay" but doesn't find the article "payment methods". **Semantic search** solves this: it understands meaning, not strings. We implement such systems for online stores, documentation, and por

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1281
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1237
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    977
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1026
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1103
  • image_website-_0.webp
    Website development for Red Pear
    550

Ordinary site search only returns articles if they contain the exact query words. A user searches for "how to pay" but doesn't find the article "payment methods". Semantic search solves this: it understands meaning, not strings. We implement such systems for online stores, documentation, and portals. Our experience: over 10 projects with AI search, certified solutions based on PostgreSQL and Qdrant. Contact us to discuss your scenario. One client achieved a 300% ROI within 6 months by reducing support tickets and decreasing page bounce rate.

Why Semantic Search Outperforms Full-Text Search?

Full-text search (PostgreSQL tsvector, Elasticsearch) matches words. Semantic search matches meaning. It converts text into a vector—a numeric array of 768–3072 numbers. Texts with close vectors are semantically similar. In our benchmarks, hybrid search delivers 3x better coverage than full-text search and 2x better precision than vector alone. This improves relevant result accuracy, especially for long and conversational queries.

How We Do It: Stack and Case Study

For an online store with 50,000 products, we implemented Hybrid search using OpenAI embeddings and pgvector. Result: average response time 0.3 seconds, accuracy 92%.

Model selection. We use text-embedding-3-small (1536 dimensions)—the optimal balance of speed and quality. For Russian it delivers excellent results.

Vector database. PostgreSQL with pgvector extension and HNSW index:

CREATE EXTENSION vector; CREATE TABLE content_chunks ( id BIGSERIAL PRIMARY KEY, content_id BIGINT REFERENCES content(id), chunk_text TEXT NOT NULL, chunk_index INT, embedding vector(1536), metadata JSONB ); CREATE INDEX ON content_chunks USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); 

Indexing. We split text into chunks of 400 tokens with 50-word overlap, get embeddings via OpenAI API, and save to the table:

import OpenAI from 'openai'; const openai = new OpenAI(); async function indexContent(contentItem) { const chunks = chunkText(contentItem.body, { maxTokens: 400, overlap: 50 }); const { data: embeddings } = await openai.embeddings.create({ model: 'text-embedding-3-small', input: chunks, }); // Save to pgvector in batches of 100 for (let i = 0; i < chunks.length; i += 100) { const batchChunks = chunks.slice(i, i + 100); const batchEmbeds = embeddings.slice(i, i + 100); await db.query(` INSERT INTO content_chunks (content_id, chunk_text, chunk_index, embedding, metadata) VALUES ($1, $2, $3, $4::vector, $5) `, [contentItem.id, batchChunks, /* ... */]); } } 

Search. We combine vector and full-text search via RRF (Reciprocal Rank Fusion):

async function semanticSearch(query, { limit = 10, threshold = 0.7 } = {}) { const { data: [{ embedding }] } = await openai.embeddings.create({ model: 'text-embedding-3-small', input: query, }); const results = await db.query(` WITH semantic AS ( SELECT content_id, chunk_text, 1 - (embedding <=> $1::vector) AS score, ROW_NUMBER() OVER (ORDER BY embedding <=> $1::vector) AS rank FROM content_chunks ORDER BY embedding <=> $1::vector LIMIT 20 ), fulltext AS ( SELECT id AS content_id, body AS chunk_text, ts_rank(to_tsvector('russian', body), plainto_tsquery('russian', $2)) AS score, ROW_NUMBER() OVER (ORDER BY ts_rank(...) DESC) AS rank FROM content WHERE to_tsvector('russian', body) @@ plainto_tsquery('russian', $2) LIMIT 20 ) SELECT COALESCE(s.content_id, f.content_id) AS id, COALESCE(s.chunk_text, f.chunk_text) AS text, (COALESCE(1.0 / (60 + s.rank), 0) + COALESCE(1.0 / (60 + f.rank), 0)) AS rrf_score FROM semantic s FULL OUTER JOIN fulltext f ON s.content_id = f.content_id ORDER BY rrf_score DESC LIMIT $3 `, [`[${embedding.join(',')}]`, query, limit]); return results.rows; } 

What Is Hybrid Search and Why Do You Need It?

Hybrid search combines vector and full-text results via RRF. This compensates for each method's weaknesses: vector search finds by meaning but may miss exact terms; full-text does the opposite. Together they ensure high relevance even for complex queries. We use this approach in all projects. Important: quality implementation requires experience—our engineers guarantee results.

How to Choose an Embedding Model for Russian?

Model choice is critical. Multilingual models (e.g., Cohere) often underperform compared to Russian-specialized ones. We tested several options and recommend:

Model Dimensions Russian Quality Speed Cost
OpenAI text-embedding-3-small 1536 excellent high low
OpenAI text-embedding-3-large 3072 outstanding medium medium
Cohere embed-multilingual-v3 1024 good high medium
BGE-M3 (self-hosted) 1024 good GPU-dependent free

Source: OpenAI Embeddings documentation

Process of Work

  1. Content audit — identify text types, size, update frequency.
  2. Model and vector DB selection — determine trade-off between quality and budget.
  3. Content indexing and chunking — setup for optimal retrieval.
  4. Search API development — endpoint with parameters: query, filters, pagination.
  5. UI creation — search bar, snippets with highlighting, progressive loading.
  6. Testing — A/B test with current search, metric monitoring.
  7. Deployment and monitoring — alerts on latency, queries without results.

Example of incremental reindexing: To avoid reindexing all documents on every change, we use triggers on the content table and a task queue (Bull/PGBoss). On insert or update, a reindex task is created for that document only. A background worker picks up the task, gets embeddings, and updates the corresponding chunk. This keeps data current without full reindexing even with thousands of daily changes.

Estimated Timelines

Stage Duration (days)
Semantic search for 10K documents (pgvector) 4–5
Hybrid search (vector + full-text) +1–2
Reranking via Cohere Rerank +1
UI with highlighting and analytics +2–3
Incremental reindexing +1–2

Implementation cost: from $3,000 depending on data volume.

What's Included

  • Complete architecture documentation (DB schema, API spec, deployment guide).
  • Turnkey source code with CI/CD.
  • Access to repository, data dump, monitoring dashboard.
  • Team training (2–3 hours).
  • 3 months of technical support.

Common mistakes: improper chunking (optimal 300-500 tokens with 50-100 overlap), choosing a model without considering language (multilingual models often perform worse on Russian), and missing reranking (cross-encoder rerank fixes this).

Want to implement meaning-based search? Contact us to discuss your project. Get a consultation for your use case.