AI ML

๐Ÿ” Semantic Search

Building search that understands what you mean, not just what you type

โฑ๏ธ 3+ Years
๐Ÿ“ฆ 8+ Projects
โœ“ Available for new projects
Experience at: Anaquaโ€ข Sparrow Intelligenceโ€ข FinanceBuzz

๐ŸŽฏ What I Offer

Semantic Search Implementation

Build search systems that understand meaning and context using AI embeddings.

Deliverables
  • Embedding pipeline design
  • Vector database setup
  • Query processing
  • Result ranking and scoring
  • Relevance tuning

Hybrid Search Systems

Combine semantic and keyword search for optimal results.

Deliverables
  • BM25 + vector hybrid
  • Re-ranking strategies
  • Filter and faceting
  • Typo tolerance
  • Performance optimization

Enterprise Search Upgrade

Modernize existing search with AI capabilities.

Deliverables
  • Search audit and assessment
  • Incremental migration
  • A/B testing framework
  • Analytics integration
  • User feedback loop

๐Ÿ”ง Technical Deep Dive

Why Semantic Search Matters

Traditional keyword search fails when:

  • Synonyms: “car” doesn’t match “automobile”
  • Intent: “how to fix a bug” vs “insect problems”
  • Context: “apple” the fruit vs “Apple” the company
  • Natural language: “documents from last quarter about revenue”

Semantic search understands meaning:

1
2
3
4
5
6
7
8
# Keyword search: no results
query = "automobile maintenance schedule"
# No documents contain "automobile"

# Semantic search: finds relevant results
query_embedding = embed("automobile maintenance schedule")
results = vector_store.similarity_search(query_embedding)
# Returns: "Car service intervals", "Vehicle maintenance guide"

Hybrid Search Architecture

Pure semantic search has limitations. Hybrid combines best of both:

Keyword (BM25):

  • Exact matches (product IDs, names)
  • Boolean filters
  • Fast and efficient

Semantic (Vector):

  • Conceptual understanding
  • Natural language queries
  • Synonym handling

Hybrid Approach:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def hybrid_search(query: str) -> list[Result]:
    # Get semantic results
    semantic = vector_store.search(embed(query), k=50)
    
    # Get keyword results
    keyword = elasticsearch.search(query, k=50)
    
    # Combine and re-rank
    combined = reciprocal_rank_fusion(semantic, keyword)
    
    return reranker.rerank(query, combined)[:10]

๐Ÿ“‹ Details & Resources

Semantic Search Architecture

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Search Query                              โ”‚
โ”‚            "find maintenance docs for Q3"                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  Query Processing                            โ”‚
โ”‚   (Embedding, filter extraction, query expansion)           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚                     โ”‚                     โ”‚
        โ–ผ                     โ–ผ                     โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Vector Search โ”‚   โ”‚ Keyword Search  โ”‚   โ”‚   Filters     โ”‚
โ”‚  (PGVector)   โ”‚   โ”‚ (Elasticsearch) โ”‚   โ”‚  (SQL/NoSQL)  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ”‚                     โ”‚                     โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Result Fusion                             โ”‚
โ”‚           (RRF, weighted combination, de-dup)               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Re-ranking                                โ”‚
โ”‚        (Cross-encoder, business rules, freshness)           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  Search Results                              โ”‚
โ”‚            (Ranked, highlighted, faceted)                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Embedding Pipeline

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from sentence_transformers import SentenceTransformer
from langchain.text_splitter import RecursiveCharacterTextSplitter

class EmbeddingPipeline:
    def __init__(self):
        self.model = SentenceTransformer('all-MiniLM-L6-v2')
        self.splitter = RecursiveCharacterTextSplitter(
            chunk_size=500,
            chunk_overlap=50
        )
    
    def embed_document(self, doc: Document) -> list[Chunk]:
        # Split into chunks
        chunks = self.splitter.split_text(doc.content)
        
        # Generate embeddings
        embeddings = self.model.encode(chunks)
        
        return [
            Chunk(
                content=chunk,
                embedding=embedding,
                metadata={
                    "doc_id": doc.id,
                    "title": doc.title,
                    "chunk_index": i
                }
            )
            for i, (chunk, embedding) in enumerate(zip(chunks, embeddings))
        ]
    
    def embed_query(self, query: str) -> np.ndarray:
        return self.model.encode(query)

Hybrid Search Implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from pgvector.sqlalchemy import Vector

class HybridSearch:
    def __init__(self, db, elasticsearch):
        self.db = db
        self.es = elasticsearch
        self.embedder = EmbeddingPipeline()
    
    async def search(
        self, 
        query: str, 
        filters: dict = None,
        k: int = 10
    ) -> list[SearchResult]:
        # Semantic search
        query_embedding = self.embedder.embed_query(query)
        semantic_results = await self.db.execute(
            select(Document)
            .order_by(Document.embedding.cosine_distance(query_embedding))
            .limit(50)
        )
        
        # Keyword search
        keyword_results = await self.es.search(
            index="documents",
            body={
                "query": {
                    "multi_match": {
                        "query": query,
                        "fields": ["title^2", "content"]
                    }
                },
                "size": 50
            }
        )
        
        # Reciprocal Rank Fusion
        fused = self.reciprocal_rank_fusion(
            semantic_results, 
            keyword_results,
            k=60
        )
        
        # Re-rank with cross-encoder
        reranked = await self.rerank(query, fused)
        
        return reranked[:k]
    
    def reciprocal_rank_fusion(self, *result_lists, k=60):
        scores = {}
        for results in result_lists:
            for rank, doc in enumerate(results):
                if doc.id not in scores:
                    scores[doc.id] = 0
                scores[doc.id] += 1 / (k + rank + 1)
        
        return sorted(scores.items(), key=lambda x: -x[1])

Vector Databases I Use

DatabaseBest ForCharacteristics
PGVectorPostgreSQL shopsSQL familiarity, ACID
PineconeManaged, scaleServerless, fast
ChromaPrototypingSimple, embedded
WeaviateMulti-modalGraphQL, modules
QdrantPerformanceRust, filtering
  • Embeddings: OpenAI, Sentence Transformers, Cohere
  • Vector DBs: PGVector, Pinecone, Chroma, Qdrant
  • Keyword: Elasticsearch, OpenSearch
  • Re-ranking: Cohere Rerank, cross-encoders
  • Frameworks: LangChain, LlamaIndex
  • Languages: Python, TypeScript

Frequently Asked Questions

Semantic search finds results based on meaning rather than exact keyword matches. It uses embeddings (vector representations) to understand context and intent. Semantic search can find relevant documents even when they don’t contain the exact search terms.

How much does semantic search implementation cost?

Semantic search development typically costs $110-160 per hour. A basic implementation starts around $15,000-30,000, while enterprise search with hybrid retrieval, faceting, and multi-language support ranges from $50,000-120,000+.

Semantic search vs keyword search, when should I use each?

Use semantic search for: natural language queries, finding similar content, handling synonyms, or when users don’t know exact terms. Use keyword search for: exact matches, filtering, or structured queries. Best practice: hybrid search combining both.

What embedding models do you use?

I work with: OpenAI embeddings (ada-002, text-embedding-3), Sentence Transformers, Cohere, and custom fine-tuned models. The choice depends on accuracy requirements, language support, and cost. I help benchmark options for your use case.

I implement: multilingual embedding models that work across languages, language detection for query routing, and proper tokenization for non-English text. This enables search that works across language barriers.


Experience:

Case Studies:

Related Technologies: RAG Systems, Vector Databases, Elasticsearch, PostgreSQL

๐Ÿ’ผ Real-World Results

Enterprise IP Search

Anaqua
Challenge

Legal teams needed to search millions of patent documents with natural language queries.

Solution

Built semantic search with PGVector, structure-aware embeddings for legal documents, citation-aware retrieval, and hybrid search for exact patent numbers.

Result

50% faster search, natural language queries work, key factor in company acquisition.

Knowledge Base Search

Sparrow Intelligence
Challenge

Developers needed to query large codebases and documentation naturally.

Solution

Semantic search across code, docs, and conversations. Contextual understanding of technical queries.

Result

Instant answers from thousands of documents and code files.

Content Discovery

FinanceBuzz
Challenge

Help writers find related articles for internal linking.

Solution

Semantic search for article similarity, enabling automatic internal linking suggestions.

Result

Improved SEO through better content connections.

โšก Why Work With Me

  • โœ“ Built enterprise semantic search at Anaqua (acquired)
  • โœ“ Hybrid search expertise, combining vector and keyword
  • โœ“ Domain-specific embeddings for legal/technical content
  • โœ“ Performance optimization at scale (millions of documents)
  • โœ“ Full search stack, from embeddings to UI

Build Intelligent Search

Within 24 hours