Technical Guide

Search Finds Nothing: LLM Exact-Match Disaster

AI built a literal-only search that returned zilch; we introduced fuzzy matching and relevance ranking so results actually show.

January 15, 2025 4 min read

The problem

An online marketplace's search function returned zero results for 92% of queries. Users searching for "mens shoes" found nothing, despite having 3,400 men's shoe listings. Support tickets complained: "Search is broken", "Can't find anything", "Is this site empty?". Analytics showed users performed an average of 4.7 failed searches before giving up. The company was losing $85,000/week in missed sales.

How AI created this issue

The developer asked Claude to implement a product search feature. Claude created a basic exact-match SQL query:


# Claude's search implementation
def search_products(query):
    # Simple exact match search
    sql = """
    SELECT * FROM products 
    WHERE LOWER(name) = LOWER(%s)
    OR LOWER(description) = LOWER(%s)
    ORDER BY created_at DESC
    """
    
    results = db.execute(sql, [query, query])
    return results

# This returns nothing for "mens shoes" because products are named:
# - "Men's Running Shoes - Nike Air Max"
# - "Casual Leather Shoes for Men"
# - "Mens Athletic Footwear"

Claude's search required exact matches of the entire field. It didn't handle plurals, typos, word order, or partial matches. The AI never suggested full-text search, fuzzy matching, or relevance scoring - just a basic string comparison that worked in the trivial example but failed with real user queries.

The solution

  1. PostgreSQL full-text search implementation: Replaced exact match with intelligent search:
    
    # Proper search with PostgreSQL full-text search
    def search_products(query):
        # Create search vector from multiple fields
        sql = """
        WITH search_query AS (
            SELECT plainto_tsquery('english', %s) AS query
        )
        SELECT 
            p.*,
            ts_rank(search_vector, query) AS rank,
            ts_headline('english', name, query, 
                'StartSel=, StopSel=') AS highlighted_name
        FROM products p, search_query
        WHERE search_vector @@ query
        OR name ILIKE '%%' || %s || '%%'  -- Fallback partial match
        ORDER BY 
            CASE WHEN name ILIKE %s || '%%' THEN 0 ELSE 1 END,  -- Prioritize prefix matches
            rank DESC,
            popularity DESC
        LIMIT 50
        """
        
        # Handle common variations
        normalized_query = query.replace("mens", "men's").replace("shoes", "shoe")
        
        return db.execute(sql, [normalized_query, query, query])
  2. Search index optimization: Added GIN indexes and search vectors:
    
    -- Add search vector column
    ALTER TABLE products ADD COLUMN search_vector tsvector;
    
    -- Populate with weighted fields
    UPDATE products SET search_vector = 
        setweight(to_tsvector('english', coalesce(name, '')), 'A') ||
        setweight(to_tsvector('english', coalesce(brand, '')), 'B') ||
        setweight(to_tsvector('english', coalesce(category, '')), 'C') ||
        setweight(to_tsvector('english', coalesce(description, '')), 'D');
    
    -- Create GIN index for fast searches
    CREATE INDEX idx_products_search ON products USING GIN (search_vector);
    
    -- Auto-update trigger
    CREATE TRIGGER update_search_vector 
    BEFORE INSERT OR UPDATE ON products
    FOR EACH ROW EXECUTE FUNCTION 
    tsvector_update_trigger(search_vector, 'pg_catalog.english', 
        name, brand, category, description);
  3. Typo tolerance: Implemented trigram similarity for fuzzy matching
  4. Synonym handling: Added common product synonyms (shoe/footwear, men's/mens)
  5. Search analytics: Track failed searches to continuously improve

The results

  • Search success rate jumped from 8% to 94%
  • Average searches per session: 4.7 → 1.3
  • Conversion rate increased 287% as users found products
  • Support tickets about search dropped 96%
  • Revenue increased $340,000/month from improved discovery
  • Search response time: 1.2s → 85ms with proper indexing

The team learned that AI tools often implement the simplest possible solution that technically works. Real-world search requires understanding of linguistics, user behavior, and database capabilities. They now start with proven search solutions (Elasticsearch, PostgreSQL FTS) rather than asking AI to reinvent search from scratch.

Ready to fix your codebase?

Let us analyze your application and resolve these issues before they impact your users.

Get Diagnostic Assessment →