# कार्यान्वयनकर्ताओं के लिए RAG: हाइब्रिड खोज और स्वचालित अनुक्रमण

<datetime class="hidden">2025-11-22T12:00</datetime>

<!-- category -- ASP.NET, Semantic Search, ONNX, Qdrant, Machine Learning, Vector Search, RAG, AI-Article -->
# परिचय

**RAG श्रृंखला का एक भाग** यह भाग है

- [भाग 1: RAG मूल और बुनियादी](/blog/rag-primer) - क्या एम्बेडिंग हैं
- [भाग 2: RAG वास्तुकला और आंतरिक](/blog/rag-architecture) -
- [भाग 3: RAG व्यावहारिक में](/blog/rag-practical-applications) - पूर्ण RAG प्रणालियों का निर्माण
- [भाग 4a: ONNX & Qdrant कार्यान्वयन](/blog/semantic-search-with-onnx-and-qdrant) - सीपीयू
- [भाग 4b: क्रिया में सेमेटिक खोज](/blog/semantic-search-in-action) - टाइपेहेडM SK1 हाइब्रिड खोज, और UI अवयव
- **भाग 5: हाइब्रिड खोज** (इस अनुच्छेदM SK1 - उत्पादन एकीकृत नमूने
- [भाग 6: GraphRAG](/blog/graphrag-knowledge-graphs-for-rag) - कोर्स के लिए ज्ञान ग्राफ्स

में [भाग 4a](/blog/semantic-search-with-onnx-and-qdrant), हमने बुनियादी बनायी है [भाग 4b](/blog/semantic-search-in-action), हम खोज UI और हाइब्रिड खोज क्रियान्वयन को शामिल किया है **स्वचालित अनुक्रमण** FileSystemWatcher के माध्यम से (zero-touch सामग्री अद्यतन

[TOC]

# हाइब्रिड खोज

अर्थ खोज शक्तिशाली है लेकिन पारंपरिक पूर्ण **समाधान** दोनों का उपयोग करें

**क्यों हाइब्रिड** विभिन्न दृष्टिकोणों में भिन्न शक्तियां हैं

- **पोस्टग्रेएसक्यूएल पूरा** ([यहां ढका हुआ](/blog/textsearchingpt1)): सही मिलते हैं
- **सांकेतिक भेक्टर खोज**: अर्थ

## पारस्परिक रैंक फ्यूजन

हम उपयोग करते हैं **पारस्परिक रैंक फ्यूजन** बहुविध खोज स्रोतों से परिणामों को जोड़ने के लिए

```mermaid
flowchart TB
    A[User Query: 'docker containers'] --> B[PostgreSQL Full-Text Search]
    A --> C[Semantic Vector Search]

    B --> D["Results:<br/>1. 'Docker Basics' (rank 1)<br/>2. 'Containerizing Apps' (rank 2)<br/>3. 'Docker Compose' (rank 3)"]
    C --> E["Results:<br/>1. 'Containerizing Apps' (rank 1)<br/>2. 'Kubernetes Guide' (rank 2)<br/>3. 'Docker Basics' (rank 3)"]

    D --> F[RRF Algorithm]
    E --> F

    F --> G["Combined Results:<br/>1. 'Containerizing Apps'<br/>   (1/61 + 1/62 = 0.0328)<br/>2. 'Docker Basics'<br/>   (1/61 + 1/63 = 0.0322)<br/>3. 'Docker Compose'<br/>   (1/63 = 0.0159)"]

    style A stroke:#10b981,stroke-width:2px
    style B stroke:#3b82f6,stroke-width:2px
    style C stroke:#6366f1,stroke-width:2px
    style D stroke:#3b82f6,stroke-width:2px
    style E stroke:#6366f1,stroke-width:2px
    style F stroke:#ec4899,stroke-width:4px
    style G stroke:#8b5cf6,stroke-width:2px
```

**आरआरएफ सूत्र** `score = Σ(1 / (k + rank))`

- `k` आरंभिक रैंकों पर प्रभाव डालने से रोकने के लिए स्थिर
- `rank` खोज विधि में = स्थिति
- परिणाम **दोनों** स्रोत एक साथ जोड़े गए प्रत्येक से प्राप्त अंक

**RRF का काम क्यों करता है**

- **दुगुना**: दोनों स्रोतों में उच्च प्राप्तियों के समान परिणाम
- **निष्पक्षता**: कोई खोज विधि अनुचित रूप से प्रभावी नहीं होती
- **सरलता**: कोई जटिल ट्युनिंग की आवश्यकता नहीं

## क्रियान्वयन

```csharp
public class HybridSearchService : IHybridSearchService
{
    private readonly ISemanticSearchService _semanticSearchService;
    private const int RrfConstant = 60;

    public async Task<List<SearchResult>> SearchAsync(
        string query,
        string language = "en",
        int limit = 10,
        CancellationToken cancellationToken = default)
    {
        // Execute both searches in parallel
        var semanticResults = await _semanticSearchService.SearchAsync(
            query, limit * 2, cancellationToken);

        // Filter by language and apply RRF
        var filteredResults = semanticResults
            .Where(r => r.Language == language)
            .ToList();

        return ApplyReciprocalRankFusion(filteredResults)
            .Take(limit)
            .ToList();
    }

    private List<SearchResult> ApplyReciprocalRankFusion(List<SearchResult> results)
    {
        var rrfScores = new Dictionary<string, RrfScore>();

        for (int i = 0; i < results.Count; i++)
        {
            var result = results[i];
            var key = $"{result.Slug}_{result.Language}";

            if (!rrfScores.ContainsKey(key))
                rrfScores[key] = new RrfScore { Result = result };

            // RRF formula: 1 / (k + rank)
            rrfScores[key].Score += 1.0 / (RrfConstant + i + 1);
        }

        return rrfScores.Values
            .OrderByDescending(x => x.Score)
            .Select(x => x.Result)
            .ToList();
    }
}
```

> **नोट** यह सिर्फ सेमेंटिक खोज को दिखाता है. उत्पादन में, PostgreSQL पूरा निष्पादित करता है\- पाठ खोज समांतर रूप से और आरआरएफ गणना में उन परिणामों को शामिल करें

## एकीकरण

यदि आप 'PostgreSQL पूर्ण को पहले से ही लागू किया है[जैसा कि यहाँ वर्णित है](/blog/textsearchingpt1)सेमेटिक खोज जोड़ना सीधा है

```csharp
// Program.cs
services.AddSemanticSearch(configuration);
services.AddSingleton<IHybridSearchService, HybridSearchService>();
```

```csharp
[HttpGet("search/hybrid")]
public async Task<IActionResult> HybridSearch(string query, string language = "en")
{
    var results = await _hybridSearchService.SearchAsync(query, language);
    return PartialView("_SearchResults", results);
}
```

# फ़ाइल सिस्टम वॉकर के साथ स्वचालित अनुक्रमण

सबसे शक्तिशाली विशेषता **स्वचालित अनुक्रमण**एक ब्लॉग पोस्ट सहेजें

## यह कैसे काम करता है

```mermaid
flowchart TB
    A[Save Markdown File] --> B[FileSystemWatcher Detects Change]
    B --> C{File in Main Directory?}
    C -->|Yes| D[Save to Database]
    C -->|No| E[Save to Database Only]
    D --> F[Create BlogPostDocument]
    F --> G[Generate Embedding via ONNX]
    G --> H[Store in Qdrant]
    H --> I[Post Searchable Immediately]

    style A stroke:#10b981,stroke-width:2px
    style B stroke:#f59e0b,stroke-width:2px
    style C stroke:#ec4899,stroke-width:3px
    style D stroke:#3b82f6,stroke-width:2px
    style E stroke:#6b7280,stroke-width:2px
    style F stroke:#8b5cf6,stroke-width:2px
    style G stroke:#6366f1,stroke-width:3px
    style H stroke:#ef4444,stroke-width:2px
    style I stroke:#10b981,stroke-width:2px
```

**कुंजी डिजाइन निर्णय** सिर्फ अनुक्रमणिका फ़ाइलों में **मुख्य मार्कडाउन निर्देशिका**उप-डाइरेक्ट्री नहीं`translated/`, `drafts/`, `comments/`यह खोज सूचकांक साफ रखता है

## फ़ाइल वॉकर एकीकरण

ब्लॉग में पहले से ही एक है `MarkdownDirectoryWatcherService`हम इसे सेमेटिक सूचकांकन ट्रिगर करने के लिए विस्तारित करें

```csharp
// In MarkdownDirectoryWatcherService.cs
private async Task OnChangedAsync(WaitForChangedResult e)
{
    if (e.Name == null) return;

    await retryPolicy.ExecuteAsync(async () =>
    {
        var savedModel = await blogService.SavePost(slug, language, markdown);

        // Index ONLY if file is in main directory (no path separators in name)
        if (!e.Name.Contains(Path.DirectorySeparatorChar) &&
            !e.Name.Contains(Path.AltDirectorySeparatorChar))
        {
            await IndexPostForSemanticSearchAsync(scope, savedModel, language);
        }
    });
}

private async Task IndexPostForSemanticSearchAsync(
    IServiceScope scope,
    BlogPostDto post,
    string language)
{
    var semanticSearchService = scope.ServiceProvider.GetService<ISemanticSearchService>();
    if (semanticSearchService == null) return; // Not configured

    var document = new BlogPostDocument
    {
        Id = $"{post.Slug}_{language}",
        Slug = post.Slug,
        Title = post.Title,
        Content = post.PlainTextContent,
        Language = language,
        Categories = post.Categories?.ToList() ?? new List<string>(),
        PublishedDate = post.PublishedDate
    };

    await semanticSearchService.IndexPostAsync(document);
    _logger.LogInformation("Indexed {Slug} ({Language}) in semantic search", post.Slug, language);
}
```

## मिटाएँ

जब कोई पोस्ट मिटाया जाता है, तो इसे अर्थ अनुक्रमणिका से हटाएँ

```csharp
private async Task OnDeletedAsync(WaitForChangedResult e)
{
    await blogService.Delete(slug, language);

    // Delete from semantic search ONLY if file was in main directory
    if (!e.Name.Contains(Path.DirectorySeparatorChar) &&
        !e.Name.Contains(Path.AltDirectorySeparatorChar))
    {
        var semanticSearchService = scope.ServiceProvider.GetService<ISemanticSearchService>();
        await semanticSearchService?.DeletePostAsync(slug, language);
    }
}
```

# आरंभिक अनुक्रमण के लिए पृष्ठभूमि सेवा

स्टार्टअप पर एक पृष्ठभूमि सेवा अनुक्रमणिका Qdrant में अभी तक नहीं मौजूदा पदों को indexes

```mermaid
flowchart TB
    A[Application Starts] --> B[Wait 10 seconds]
    B --> C[Initialize Semantic Search]
    C --> D{Model Exists?}
    D -->|No| E[Download from Hugging Face]
    D -->|Yes| F[Load ONNX Model]
    E --> F
    F --> G[Scan Main Markdown Directory]
    G --> H{For Each .md File}
    H --> I[Compute Content Hash]
    I --> J{Hash Changed?}
    J -->|Yes| K[Generate Embedding]
    J -->|No| L[Skip - Already Indexed]
    K --> M[Store in Qdrant]
    M --> H
    L --> H
    H -->|Done| N[Indexing Complete]

    style A stroke:#10b981,stroke-width:2px
    style C stroke:#6366f1,stroke-width:2px
    style E stroke:#f59e0b,stroke-width:2px
    style F stroke:#6366f1,stroke-width:3px
    style G stroke:#8b5cf6,stroke-width:2px
    style J stroke:#ec4899,stroke-width:3px
    style K stroke:#6366f1,stroke-width:2px
    style M stroke:#ef4444,stroke-width:2px
    style N stroke:#10b981,stroke-width:2px
```

```csharp
public class SemanticIndexingBackgroundService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Wait for app to be ready
        await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);

        // Initialize (downloads model if needed)
        await _semanticSearchService.InitializeAsync(stoppingToken);

        // Get all posts from main directory only
        var markdownFiles = Directory.GetFiles(
            _markdownConfig.MarkdownPath,
            "*.md",
            SearchOption.TopDirectoryOnly);  // NOT subdirectories

        foreach (var file in markdownFiles)
        {
            var needsIndexing = await _semanticSearchService.NeedsReindexingAsync(
                slug, language, contentHash, stoppingToken);

            if (needsIndexing)
                await _semanticSearchService.IndexPostAsync(document, stoppingToken);
        }
    }
}
```

**यह सुनिश्चित करता है**

1. **लचीला मॉडल लोडिंग** - पहली बार उपयोग पर डाउनलोड्स
2. **वृद्धिशील सूचकांकन** केवल नए
3. **सिर्फ मुख्य निर्देशिका** - ड्राफ्ट और अनुवादित फ़ाइलें अनुक्रमणिका को दूषित नहीं करते

# क्या हम निर्माण किया है

सभी भागों में 4aM SK1 4b, और 5, हम अब है

- ✅ **सीपीयू-सेमेटिक खोज** - कोई GPU आवश्यक नहीं
- ✅ **संबंधित पोस्ट खोज** - Semantically similar content
- ✅ **प्राकृतिक भाषा खोज** - अर्थ से ढूंढें
- ✅ **हाइब्रिड खोज** - सर्वोत्कृष्ट अर्थात्मक
- ✅ **स्वचालित अनुक्रमण** - Zero-touch सामग्री अद्यतन
- ✅ **स्वयं** - आपका डेटा आपके सर्वर पर रहता है

**भावी सुधार**

- **श्रेणी-अभिज्ञ खोज** - विशिष्ट श्रेणियों से बौस्ट परिणाम
- **बहुभाषीय सम्मिलन** भाषा
- **ओपन सर्च इंटीग्रेशन** हाइब्रिड मिश्रण में ओपन सर्च जोड़ें[मेरी ओपन सर्च लेख देखें](/blog/textsearchingpt3))

# निष्कर्ष

यह RAG के व्यावहारिक कार्यान्वयन को पूरा करता है [भाग 4a](/blog/semantic-search-with-onnx-and-qdrant) (उत्तरकरण [भाग 4b](/blog/semantic-search-in-action) खोज UI ), आपके नेट अनुप्रयोग में स्मार्ट खोज को जोड़ने के लिए आपके पास सब कुछ है

## सीखना जारी रखें

- **[RAG भाग 1: मूल और बुनियादी](/blog/rag-primer)** - एम्बेडिंग के पीछे सिद्धांत
- **[RAG भाग 2: वास्तुकला और आंतरिक](/blog/rag-architecture)** - RAG प्रणालियों में गहराई से डुबोना
- **[RAG भाग 3: व्यवहारिक अनुप्रयोग](/blog/rag-practical-applications)** - LLM एकीकरण के साथ पूरा RAG
- **[भाग 4a: ONNX & Qdrant कार्यान्वयन](/blog/semantic-search-with-onnx-and-qdrant)** - फाउंडेशन
- **[भाग 4b: क्रिया में सेमेटिक खोज](/blog/semantic-search-in-action)** - टाइपेहेड, हाइब्रिड खोज
- **[पूर्ण-PostgreSQL के साथ पाठ खोज](/blog/textsearchingpt1)** हाइब्रिड खोज का पूरा पाठ पक्ष

## संसाधन

### Qdrant & भेक्टर डाटाबेस

- [Qdrant के साथ Self-Hosted भेक्टर डाटाबेस](/blog/self-hosted-vector-databases-qdrant) - Qdrant संकल्पनाओं में गहराई से डुबोने के लिए
- [क्वैंड हाइब्रिड खोजQuery](https://qdrant.tech/documentation/concepts/hybrid-queries/) - Qdrant

### हाइब्रिड खोज

- [पारस्परिक रैंक फ्यूजन कागज](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf) - आरआरएफ एल्गोरिथ्म

### फ़ाइल सिस्टम निगरानी

- [FileSystemWatcher वर्ग](https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher) -
- [पृष्ठभूमि सेवा वर्ग](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.backgroundservice) ASP में होस्ट किए गए सेवाएँ

### पूर्ण कोड

सभी कोड ‘:’ पर उपलब्ध है [github.comM SK1scottgal/mostlylucidweb](https://github.com/scottgal/mostlylucidweb)

- `Mostlylucid.SemanticSearch/` Core semantic search library
- `Mostlylucid/Blog/WatcherService/` - शब्दानुक्रमण अनुक्रमणिका के साथ फ़ाइल द्रष्टा