DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Essential Techniques for Production Vector Search Systems Part 1 - Hybrid Search
  • Creating an Agentic RAG for Text-to-SQL Applications
  • Hybrid Search Using Postgres DB
  • Microservices With .NET Core: Building Scalable and Resilient Applications

Trending

  • Why Your AI Agent's Logs Aren't Earning Trust
  • Native SQL in Java Without JDBC Boilerplate — Meet Ujorm3
  • Operationalizing Enterprise AI at Scale: Architecture, Governance, and Adoption
  • The Documentation Crisis Nobody Sees: Why AI Agents Are Breaking Faster Than Humans Can Document Them
  1. DZone
  2. Data Engineering
  3. Data
  4. Intelligent Matching and Semantic Search for Marketplace Applications Using OpenAI and .NET

Intelligent Matching and Semantic Search for Marketplace Applications Using OpenAI and .NET

Learn how to build AI-powered semantic search and intelligent matching systems for marketplace platforms using OpenAI embeddings and .NET.

By 
Omer Yilmaz user avatar
Omer Yilmaz
·
Jun. 17, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
130 Views

Join the DZone community and get the full member experience.

Join For Free

Marketplace platforms are fundamentally matching systems. Whether the platform connects:

  • Students and tutors
  • Freelancers and clients
  • Buyers and sellers
  • Consultants and companies

The overall user experience usually depends on how accurately the platform can connect relevant people together.

At early stages, traditional search systems are often enough. Basic SQL filtering, category-based navigation, and keyword matching can solve many initial requirements without major issues.

The situation changes once the platform grows and users begin writing longer, intent-based queries instead of simple keywords.

For example, a user may search for:

“online calculus tutor for engineering preparation”

while a marketplace listing may contain:

“advanced mathematics mentor for university students”

Even though both sides are highly relevant, a traditional keyword-based search engine may completely fail to connect them because the wording is different.

This is one of the areas where semantic search architectures become extremely valuable.

Why Traditional Marketplace Search Starts Breaking Down

Most marketplace platforms initially rely on:

  • SQL LIKE queries
  • full-text search
  • BM25 ranking
  • tag filtering

These approaches work reasonably well when search queries are short and predictable. However, real users rarely search using the exact same terminology as listing owners. A few common examples:

User Query Marketplace Listing
math tutor calculus mentor
IELTS coach English speaking trainer
React mentor frontend architect
startup advisor business consultant


The issue here is not syntax. It is the semantic meaning. Traditional search engines are effective at matching identical words, but much weaker at understanding contextual similarity between different phrases.

Intent Matters More Than Exact Keywords

One thing that becomes visible fairly quickly in marketplace applications is that users tend to search with intent instead of isolated keywords.

For example:

“senior React mentor for interview preparation”

The user is probably not simply searching for “React.” The actual intent may include:

  • Mentorship
  • Senior-level expertise
  • Interview coaching
  • Frontend architecture experience

Traditional keyword search systems struggle to interpret these relationships properly.

Even when partially relevant results appear, ranking quality often becomes inconsistent as queries become longer and more contextual.

Semantic Search Approaches the Problem Differently

Semantic search systems do not treat text as isolated keywords. Instead, text is converted into vector representations called embeddings.

These embeddings represent contextual meaning rather than exact wording.

As a result, the following phrases can become mathematically close to each other even when they do not contain identical words:

  • “Math tutor”
  • “Calculus mentor”
  • “Engineering mathematics coach”

This allows marketplace applications to perform much more flexible matching.

A Typical Semantic Search Architecture

Plain Text
 
User Query
   ↓
Embedding Generation
   ↓
Vector Search
   ↓
Similarity Scoring
   ↓
Hybrid Ranking
   ↓
Marketplace Results


The important detail here is that the following are converted into embeddings before similarity calculations happen:

  • Marketplace listings
  • User queries

.NET Technologies Used in the Architecture

A typical .NET-based semantic search stack may include the following components:

Area Technology
API Layer ASP.NET Core
Background Jobs Hosted Services / Quartz.NET
Queue System RabbitMQ / Azure Service Bus
Database SQL Server / PostgreSQL
Vector Storage pgvector / Pinecone
Cache Redis
Logging Serilog
Monitoring OpenTelemetry
AI Integration OpenAI API


One thing that becomes obvious during implementation is that the OpenAI API itself is usually only a small part of the overall system.

The larger engineering effort often involves:

  • Indexing
  • Ranking
  • Caching
  • Asynchronous processing
  • Operational monitoring
  • Retry handling

Marketplace Listing Model

A simplified marketplace listing model may look like this:

C#
 
public class MarketplaceListing
{
    public long Id { get; set; }

    public string Title { get; set; }

    public string Description { get; set; }

    public string CategoryName { get; set; }

    public string Location { get; set; }

    public bool IsActive { get; set; }

    public bool IsDeleted { get; set; }

    public DateTime CreatedOn { get; set; }

    public DateTime? LastIndexedOn { get; set; }

    public string SearchText =>
        $"{Title} {Description} {CategoryName} {Location}";
}


The SearchText property combines multiple searchable fields into a single semantic context before embedding generation.

Generating Embeddings With OpenAI

A simplified embedding service implementation in .NET may look like this:

C#
 
public class OpenAIEmbeddingService : IEmbeddingService
{
    private readonly HttpClient _httpClient;
    private readonly IConfiguration _configuration;

    public OpenAIEmbeddingService(
        HttpClient httpClient,
        IConfiguration configuration)
    {
        _httpClient = httpClient;
        _configuration = configuration;
    }

    public async Task<float[]> GenerateEmbeddingAsync(
        string input,
        CancellationToken cancellationToken = default)
    {
        var apiKey = _configuration["OpenAI:ApiKey"];

        using var request = new HttpRequestMessage(
            HttpMethod.Post,
            "https://api.openai.com/v1/embeddings");

        request.Headers.Authorization =
            new AuthenticationHeaderValue("Bearer", apiKey);

        var body = new
        {
            model = "text-embedding-3-small",
            input = input
        };

        request.Content = new StringContent(
            JsonSerializer.Serialize(body),
            Encoding.UTF8,
            "application/json");

        using var response =
            await _httpClient.SendAsync(request, cancellationToken);

        response.EnsureSuccessStatusCode();

        var json =
            await response.Content.ReadAsStringAsync(cancellationToken);

        using var document = JsonDocument.Parse(json);

        return document
            .RootElement
            .GetProperty("data")[0]
            .GetProperty("embedding")
            .EnumerateArray()
            .Select(x => x.GetSingle())
            .ToArray();
    }
}

Dependency Injection

C#
 
builder.Services.AddHttpClient<
    IEmbeddingService,
    OpenAIEmbeddingService>();

builder.Services.AddScoped<
    ISemanticSearchService,
    SemanticSearchService>();


Background Indexing

One issue that appears very quickly in production systems is latency. Generating embeddings synchronously during listing creation or updates may slow down the request lifecycle significantly. 

Because of this, many systems move embedding generation into:

  • Background workers
  • Queues
  • Asynchronous indexing pipelines

A simple hosted worker example:

C#
 
public class ListingEmbeddingWorker : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<ListingEmbeddingWorker> _logger;

    public ListingEmbeddingWorker(
        IServiceProvider serviceProvider,
        ILogger<ListingEmbeddingWorker> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(
        CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                using var scope =
                    _serviceProvider.CreateScope();

                var service =
                    scope.ServiceProvider
                        .GetRequiredService<IListingEmbeddingService>();

                await service.IndexPendingListingsAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(
                    ex,
                    "Listing embedding worker failed.");
            }

            await Task.Delay(
                TimeSpan.FromMinutes(5),
                stoppingToken);
        }
    }
}


Vector Similarity

Once embeddings are generated, similarity calculations can be performed. The most common approach is cosine similarity:

cos(θ)=A⋅B∥A∥∥B∥\cos(\theta)=\frac{A\cdot B}{\|A\|\|B\|}cos(θ)=∥A∥∥B∥A⋅B

A simplified helper implementation may look like this:

C#
 
public static class VectorSimilarityHelper
{
    public static double CosineSimilarity(
        float[] vectorA,
        float[] vectorB)
    {
        double dotProduct = 0;
        double magnitudeA = 0;
        double magnitudeB = 0;

        for (int i = 0; i < vectorA.Length; i++)
        {
            dotProduct += vectorA[i] * vectorB[i];
            magnitudeA += vectorA[i] * vectorA[i];
            magnitudeB += vectorB[i] * vectorB[i];
        }

        return dotProduct /
               (Math.Sqrt(magnitudeA) * Math.Sqrt(magnitudeB));
    }
}


Semantic Similarity Alone Is Usually Not Enough

One thing that became obvious during testing was that semantic similarity alone sometimes produced weak ranking behavior.

For example, the following could still receive high semantic scores:

  • Inactive listings
  • Outdated profiles
  • Low-quality marketplace entries

Because of this, most production marketplace systems eventually move toward hybrid ranking models.A simplified ranking formula may look like this:

FinalScore=0.45SemanticScore+0.25KeywordScore+0.15PopularityScore+0.10FreshnessScore+0.05ConversionScoreFinalScore=0.45SemanticScore+0.25KeywordScore+0.15PopularityScore+0.10FreshnessScore+0.05ConversionScoreFinalScore=0.45SemanticScore+0.25KeywordScore+0.15PopularityScore+0.10FreshnessScore+0.05ConversionScore

This combines:

  • semantic relevance
  • keyword relevance
  • popularity
  • freshness
  • conversion metrics

There is usually no perfect ranking formula. In practice, ranking becomes an ongoing optimization problem.

Example Semantic Search Service

C#
 
public class SemanticSearchService : ISemanticSearchService
{
    private readonly AppDbContext _dbContext;
    private readonly IEmbeddingService _embeddingService;

    public SemanticSearchService(
        AppDbContext dbContext,
        IEmbeddingService embeddingService)
    {
        _dbContext = dbContext;
        _embeddingService = embeddingService;
    }

    public async Task<List<SearchResultDto>> SearchAsync(
        string query,
        CancellationToken cancellationToken)
    {
        var queryVector =
            await _embeddingService.GenerateEmbeddingAsync(
                query,
                cancellationToken);

        var listings = await _dbContext.ListingEmbeddings
            .Include(x => x.Listing)
            .ToListAsync(cancellationToken);

        var results = listings
            .Select(x =>
            {
                var vector =
                    JsonSerializer.Deserialize<float[]>(x.VectorJson);

                var similarity =
                    VectorSimilarityHelper.CosineSimilarity(
                        queryVector,
                        vector);

                return new SearchResultDto
                {
                    ListingId = x.ListingId,
                    Title = x.Listing.Title,
                    SimilarityScore = similarity
                };
            })
            .OrderByDescending(x => x.SimilarityScore)
            .Take(50)
            .ToList();

        return results;
    }
}


Production Challenges

One thing that often gets underestimated in semantic search discussions is operational complexity. The AI layer itself is usually easier than the surrounding production engineering. A few examples include:

  • Embedding costs
  • Queue management
  • Indexing latency
  • Retry handling
  • Stale embeddings
  • Cache invalidation
  • Multilingual relevance
  • Ranking quality optimization

For example, the following trigger embedding generation, API costs can grow much faster than expected:

  • Listing update
  • Profile edit
  • Search query

Caching and embedding reuse become important fairly early in the process.

Final Thoughts

Semantic search is not really about replacing traditional search entirely. In most production systems, the better approach is usually to combine these into a layered ranking architecture:

  • Semantic relevance
  • Keyword matching
  • Behavioral scoring
  • Freshness
  • Business metrics

OpenAI embeddings and .NET provide a practical foundation for building these types of marketplace systems, especially for platforms where relevance quality directly affects user experience and conversion rates.

One interesting observation after introducing semantic matching is that users generally spend less time trying to “guess the correct keywords.” The platform becomes significantly better at understanding what users actually mean instead of simply matching individual words.

Semantic search applications Net (command) Data Types

Opinions expressed by DZone contributors are their own.

Related

  • Essential Techniques for Production Vector Search Systems Part 1 - Hybrid Search
  • Creating an Agentic RAG for Text-to-SQL Applications
  • Hybrid Search Using Postgres DB
  • Microservices With .NET Core: Building Scalable and Resilient Applications

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook