WEBSITE ĐANG PHÁT TRIỂN

Từ Episerver Find đến AI-powered search - con đường migration

Bạn đang dùng Episerver Find và muốn cải thiện search quality với AI? Đừng rewrite toàn bộ. Có một con đường từng bước - từ keyword search → hybrid search → semantic search - mà không cần phá vỡ hệ thống đang chạy ổn.

Khi khách hàng phàn nàn về search

Cuối năm 2024, tôi nhận được complaint từ một khách hàng đang dùng hệ thống e-commerce mà team tôi build và maintain. Hệ thống search dùng Episerver Find - hoạt động tốt nhiều năm.

Nhưng khách hàng nói: "Search ngày càng kém hơn so với Amazon. Khách vào tìm 'giày thể thao bền' không ra gì. Tìm tên thương hiệu sai chính tả thì không có kết quả."

Tôi ngồi test thử. Họ đúng. Episerver Find mặc định là keyword search - không có semantic understanding, không có typo tolerance tốt, không hiểu intent của user.

Câu hỏi là: làm thế nào để cải thiện mà không rewrite toàn bộ hệ thống?


Quay lại chuyện kỹ thuật: tại sao keyword search không đủ

Episerver Find về bản chất là một wrapper trên Elasticsearch với opinionated configuration. Khi bạn gọi:

var results = SearchClient.Instance
    .Search<ProductContent>()
    .For("giày thể thao bền")
    .GetContentResult();

Nó chuyển thành một Elasticsearch query tìm documents có chứa các từ "giày", "thể thao", "bền". Rất đơn giản - và cũng rất giới hạn.

Vấn đề 1: Semantic gap. User muốn "giày bền" nhưng product description dùng từ "độ bền cao". Keyword search không match.

Vấn đề 2: Typo tolerance. "Nike" thay vì "Nike" → không ra kết quả.

Vấn đề 3: Intent mismatch. "Giày cho chạy bộ buổi sáng" là một intent cụ thể, nhưng keyword search chỉ thấy "giày", "chạy", "bộ", "buổi", "sáng" - không hiểu intent.

AI-powered search giải quyết những vấn đề này bằng cách understand semantic meaning, không chỉ match keywords.


Lộ trình migration 3 bước

Bước 1: Cải thiện Episerver Find với Better Configuration

Trước khi nghĩ đến AI, hãy tận dụng tối đa những gì Elasticsearch/Episerver Find đã có.

// Cấu hình Episerver Find với fuzzy matching và synonyms
SearchClient.Instance
    .Search<ProductContent>()
    .For("giay the thao", x => x
        .UseFuzzyMatching(Fuzziness.EditDistance(1))  // typo tolerance
        .InField(p => p.Name, boost: 3.0)
        .InField(p => p.Description, boost: 1.0)
        .InField(p => p.Categories.Select(c => c.Name), boost: 2.0)
    )
    .Filter(x => x.PublishedStatus.Match(true))
    .OrderByDescending(x => x.Relevance())
    .GetContentResult();

Thêm synonyms dictionary:

// elasticsearch_synonyms.txt
giầy, giày
nịt, belt
ao, áo
quan, quần
nike, nike, naik
adidas, adidas, adidass

Cấu hình fuzzy matching đúng có thể cải thiện typo tolerance đáng kể mà không cần thay đổi architecture.

Kết quả thực tế: Chúng tôi làm bước này trước và search quality cải thiện khoảng 20-30% chỉ với configuration.


Bước 2: Hybrid Search - Kết hợp Keyword + Vector

Đây là bước thêm semantic understanding mà không cần bỏ Episerver Find.

Ý tưởng: Khi user search, bạn chạy song song:

  1. Keyword search qua Episerver Find (như cũ)
  2. Vector similarity search qua Elasticsearch dense_vector field
  3. Merge và re-rank kết quả
public class HybridSearchService
{
    private readonly IClient _episeverFind;
    private readonly ElasticClient _elasticClient;
    private readonly IEmbeddingService _embeddingService;

    public async Task<IEnumerable<ProductContent>> SearchAsync(string query)
    {
        // Parallel execution
        var keywordTask = SearchWithEpiserver(query);
        var vectorTask = SearchWithVectors(query);

        await Task.WhenAll(keywordTask, vectorTask);

        // Reciprocal Rank Fusion để merge kết quả
        return MergeWithRRF(
            keywordTask.Result,
            vectorTask.Result,
            keywordWeight: 0.6,
            vectorWeight: 0.4
        );
    }

    private async Task<List<(ProductContent, double)>> SearchWithVectors(string query)
    {
        // Convert query thành embedding
        var queryVector = await _embeddingService.GetEmbeddingAsync(query);

        var response = await _elasticClient.SearchAsync<ProductDocument>(s => s
            .Index("products")
            .Query(q => q
                .ScriptScore(ss => ss
                    .Query(qq => qq.MatchAll())
                    .Script(sc => sc
                        .Source("cosineSimilarity(params.queryVector, 'description_vector') + 1.0")
                        .Params(p => p.Add("queryVector", queryVector))
                    )
                )
            )
            .Size(20)
        );

        return response.Hits
            .Select(h => (MapToProductContent(h.Source), h.Score ?? 0.0))
            .ToList();
    }
}

Lưu ý quan trọng: Vector field cần được thêm vào Elasticsearch index. Với Episerver Find, bạn có thể dùng một Elasticsearch index riêng cho vector search, không cần sửa index của Find.


Bước 3: AI Re-ranking

Sau khi có kết quả từ hybrid search, bước cuối cùng là dùng AI model để re-rank dựa trên relevance thực sự.

public class SearchReranker
{
    private readonly IChatClient _llmClient; // Claude, GPT-4o, hoặc local model

    public async Task<IEnumerable<ProductContent>> RerankAsync(
        string userQuery,
        IEnumerable<ProductContent> candidates)
    {
        // Dùng cross-encoder model để score từng candidate
        var scoringTasks = candidates.Select(async product =>
        {
            var relevanceScore = await ScoreRelevance(userQuery, product);
            return (product, relevanceScore);
        });

        var scored = await Task.WhenAll(scoringTasks);

        return scored
            .OrderByDescending(x => x.relevanceScore)
            .Select(x => x.product)
            .Take(10);
    }

    private async Task<double> ScoreRelevance(string query, ProductContent product)
    {
        // Với production, dùng dedicated cross-encoder model
        // Ví dụ: ms-marco-MiniLM-L-6-v2 chạy local
        // Không dùng GPT-4o/Claude cho từng result - quá tốn kém
        return await _crossEncoderModel.ScoreAsync(query, product.Description);
    }
}

Lưu ý về chi phí: Cross-encoder model nên chạy on-premise hoặc là model nhỏ. Đừng dùng GPT-4o/Claude để re-rank từng product - với 20 results và 100k queries/ngày, chi phí token sẽ rất cao.


Kinh nghiệm từ dự án thực

Chúng tôi đã implement lộ trình này trong 4 tháng:

  • Tháng 1: Better Episerver Find configuration (synonyms, fuzzy, boosting)
  • Tháng 2-3: Add vector field vào product index, implement embedding pipeline
  • Tháng 4: Hybrid search và A/B testing

Kết quả sau 4 tháng:

  • Search zero-results rate giảm từ 15% xuống 4%
  • Conversion rate từ search tăng 23%
  • User satisfaction (khảo sát) tăng đáng kể

Điều quan trọng nhất: Chúng tôi không cần rewrite Episerver Find. Hệ thống cũ vẫn chạy, chúng tôi chỉ thêm layer mới.


Triết lý

Có một pattern tôi thấy ở nhiều team khi nghĩ đến "AI search": muốn rewrite everything ngay lập tức.

Tôi không nghĩ đó là cách đúng. Hệ thống đang hoạt động tốt - dù không perfect - là valuable. Migration từng bước giúp bạn:

  1. Validate từng improvement với real data
  2. Rollback dễ nếu có vấn đề
  3. Team học dần thay vì bị overwhelm

"Make it work, then make it better" - vẫn còn đúng trong thời AI.


Bạn đã gặp tình huống này chưa?

Nếu bạn đang dùng Episerver Find hoặc bất kỳ keyword search nào và muốn upgrade lên AI search - bạn đang ở giai đoạn nào? Keyword enhancement, hybrid, hay full semantic? Tôi rất muốn nghe kinh nghiệm của bạn 👇


/Son Do - believe in basic

#1percentbetter #AIArchitecture #Episerver #SemanticSearch #VectorSearch #dotnet


Bài viết liên quan

Xem thêm
AI Integration — Góc nhìn Architect

Prompt Engineering 2026: Không phải 1 góc nhìn — mà 40 góc nhìn song song

Năm 2026, AI agents đang bùng nổ và nhiều người vội vã tuyên bố "prompt engineering đã chết". Sai hoàn toàn. Chain of Thought, flipping roles — những kỹ thuật cơ bản đó vẫn còn sống, chỉ là giờ chúng ta không chạy 1 luồng nữa, mà chạy song song 40 luồng cùng lúc. Bài này là câu chuyện về sự tiến hóa đó. Hôm rồi tôi ngồi cà phê với một ông bạn — tôi gọi anh là Khoa cho tiện — senior developer 6 năm, đang chuyển sang làm AI engineer ở một startup khá hot trong nước. Anh mở màn bằng một câu khiến tôi suýt đổ cà phê: "Anh ơi, prompt engineering giờ chết rồi. Giờ phải học AI agents mới là đúng hướng." Tôi nhìn anh, hỏi: "Chết theo nghĩa nào?" Anh giải thích: "Thì giờ người ta build hệ thống multi-agent rồi, AI tự lo với nhau, mình chỉ cần thiết kế workflow là xong. Ai còn ngồi viết prompt thủ công nữa?" Tôi im lặng một lúc, rồi hỏi ngược: "Thế mấy cái agent đó nó tự nhiên biết làm việc không? Hay vẫn cần ai đó chỉ cho nó cách nghĩ?" Anh Khoa dừng lại. Ừ nhỉ.

AI Integration — Góc nhìn Architect

Ba cấp độ làm việc với AI: automation, augmentation, và agency - bạn đang ở đâu?

Hầu hết developer đang dùng AI chỉ một cách: giao việc và chờ kết quả. Nhưng có hai cách hiệu quả hơn nhiều - và một trong số đó có thể thay đổi hoàn toàn cách bạn làm việc. Bài này là framework tôi dùng để tự đánh giá mình đang khai thác AI đến đâu. Tuần trước tôi ngồi cà phê với một anh bạn - senior developer 8 năm kinh nghiệm, tôi gọi là anh Hưng cho dễ. Anh vừa xong một sprint khá nặng, và câu đầu tiên mở miệng là: "Mày ơi, giờ tao làm việc với AI nhiều lắm, năng suất tăng rõ rệt." Tôi gật đầu, hỏi tiếp: "Bạn đang dùng theo cách nào?" Anh Hưng giải thích: ChatGPT để viết unit test. GitHub Copilot để gợi ý code. Claude để explain stack trace. Ổn đấy. Tôi hỏi tiếp: "Còn ngoài ra?" Anh im lặng một lúc. "Ngoài ra là... mình hỏi nó trả lời, xong mình copy, sửa lại, done." Câu đó làm tôi nghĩ nhiều. Không phải vì anh Hưng dùng AI sai - mà vì câu đó mô tả chính xác cách phần lớn developer giỏi đang bỏ lỡ hai phần ba giá trị của AI.