RAG للمنفذين: البحث الدنتي في العمل (العربية (Arabic))

RAG للمنفذين: البحث الدنتي في العمل

Wednesday, 24 December 2025

//

15 minute read

أولاً

جزء من سلسلة السلاسل: هذا هو الجزء 4b- سمات البحث وUI:

داخل الجزء الرابع(أ)لقد بنينا الأساس: أونكس progratings و تخزين متجهات Qdrant. الآن دعونا نضعها للعمل مع البحث الحقيقي - بما في ذلك Sippahead Automative الكامل، والبحث الهجين الذي يجمع بين النص الكامل + النص الكامل، والترشيح المتقدم.

هذه المقالة تغطي تجربة البحث الفعلية التي يتفاعل معها مستخدمو هذه المدونة.

تجربة البحث في نوع الترويسة

صندوق البحث في أعلى هذا الموقع يوفر نتائج البحث الفوري. إليكم كيف يعمل:

sequenceDiagram
    participant U as User
    participant A as Alpine.js
    participant API as SearchApi
    participant H as HybridSearch
    participant S as Semantic Search
    participant P as PostgreSQL

    U->>A: Types "docker"
    A->>A: Debounce 300ms
    A->>API: GET /api/search/docker
    API->>H: HybridSearchAsync("docker")
    par Parallel Search
        H->>S: SearchAsync("docker", 20)
        H->>P: GetSearchResultForComplete("docker")
    end
    S-->>H: Semantic results (by meaning)
    P-->>H: Full-text results (by keywords)
    H->>H: Apply RRF scoring
    H-->>API: Combined results
    API-->>A: JSON results
    A->>U: Display dropdown

المكوّل الرأسي من طراز Alben.js

استخدامات صندوق البحث الألابين لـ تفاعلي UI بدون جافاسكربت إطارات هذا هو المكوّن:

export function typeahead() {
    return {
        query: '',
        results: [],
        highlightedIndex: -1, // Tracks keyboard navigation

        search() {
            // Minimum 2 characters to trigger search
            if (this.query.length < 2) {
                this.results = [];
                this.highlightedIndex = -1;
                return;
            }

            fetch(`/api/search/${encodeURIComponent(this.query)}`, {
                method: 'GET',
                headers: { 'Content-Type': 'application/json' }
            })
            .then(response => {
                if (response.ok) return response.json();
                return Promise.reject(response);
            })
            .then(data => {
                this.results = data;
                this.highlightedIndex = -1;
                // Process HTMX attributes in results
                this.$nextTick(() => {
                    htmx.process(document.getElementById('searchresults'));
                });
            })
            .catch((response) => {
                console.log("Error fetching search results");
            });
        },

        // Keyboard navigation
        moveDown() {
            if (this.highlightedIndex < this.results.length - 1) {
                this.highlightedIndex++;
            }
        },

        moveUp() {
            if (this.highlightedIndex > 0) {
                this.highlightedIndex--;
            }
        },

        selectHighlighted() {
            if (this.highlightedIndex >= 0 && this.highlightedIndex < this.results.length) {
                this.selectResult(this.highlightedIndex);
            }
        },

        selectResult(selectedIndex) {
            // Click the HTMX link to navigate
            let links = document.querySelectorAll('#searchresults a');
            links[selectedIndex].click();
            this.results = [];
            this.highlightedIndex = -1;
            this.query = '';
        }
    }
}

السمات الرئيسية:

  1. ****: 300mms تأخير منع مُرْرِق الخادوم
  2. اطما لا يقل عن اثنين من الشخصيات المطلوبة:
  3. ****مفاتيح السهم + الدخول من أجل تيسير الوصول
  4. HTMXS: النتائج التي تستخدم HTMX من أجل سلاسة الملاحة

الـ البحث صندوق

<div x-data="window.mostlylucid.typeahead()"
     class="relative"
     x-on:click.outside="results = []">

    <label class="input input-sm bg-white dark:bg-custom-dark-bg input-bordered flex items-center gap-2">
        <input
            type="text"
            x-model="query"
            x-on:input.debounce.300ms="search"
            x-on:keydown.down.prevent="moveDown"
            x-on:keydown.up.prevent="moveUp"
            x-on:keydown.enter.prevent="selectHighlighted"
            placeholder="Search..."
            class="border-0 grow input-sm text-black dark:text-white bg-transparent w-full"/>
        <i class="bx bx-search"></i>
    </label>

    <!-- Dropdown Results -->
    <ul x-show="results.length > 0"
        id="searchresults"
        class="absolute z-10 my-2 w-full bg-white dark:bg-custom-dark-bg border rounded-lg shadow-lg">
        <template x-for="(result, index) in results" :key="result.slug">
            <li :class="{'bg-blue-light dark:bg-blue-dark': index === highlightedIndex}"
                class="cursor-pointer text-sm p-2 m-2 hover:bg-blue-light dark:hover:bg-blue-dark">
                <a hx-boost="true"
                   hx-target="#contentcontainer"
                   hx-swap="innerHTML show:window:top"
                   :href="result.url"
                   x-text="result.title"></a>
            </li>
        </template>
    </ul>
</div>

ألف - x-on:click.outside? النقر خارج الهبوط يغلقه نمط UX القياسي للاستكمال الذاتي.

الـ مائل البحث

الـ /api/search/{query} هذا هو المتحكم:

[ApiController]
[Route("api")]
public class SearchApi(
    BlogSearchService searchService,
    UmamiBackgroundSender umamiBackgroundSender,
    ISemanticSearchService semanticSearchService,
    SemanticSearchConfig semanticSearchConfig) : ControllerBase
{
    private const int RrfConstant = 60; // Reciprocal Rank Fusion constant

    [HttpGet]
    [Route("search/{query}")]
    [OutputCache(Duration = 3600, VaryByQueryKeys = new[] { "query" })]
    public async Task<Results<JsonHttpResult<List<SearchResults>>, BadRequest<string>>> Search(string query)
    {
        using var activity = Log.Logger.StartActivity("Search {query}", query);
        try
        {
            var host = Request.Host.Value;
            List<SearchResults> output;

            // Use hybrid search if semantic search is enabled
            if (semanticSearchConfig.Enabled)
            {
                output = await HybridSearchAsync(query, host);
            }
            else
            {
                // Fallback to full-text search only
                output = await FullTextSearchAsync(query, host);
            }

            // Track search event for analytics
            var encodedQuery = HttpUtility.UrlEncode(query);
            await umamiBackgroundSender.Track("searchEvent", new UmamiEventData { { "query", encodedQuery } });

            return TypedResults.Json(output);
        }
        catch (Exception e)
        {
            Log.Error(e, "Error in search");
            return TypedResults.BadRequest("Error in search");
        }
    }
}

مقررات التصميم المهمة:

  1. الدولة الطرف: semanticSearchConfig.Enabled يسمح لك بتبديل البحث الدال
  2. مساقمخبئ لمدة ساعة واحدة يُخفِّض حمّل الخادِم للاستفسارات المشتركة
  3. محل المحل المحل المحلات: كل بحث يتم تعقبه (المساعدات تفهم سلوك المستخدم)
  4. ****يُرجعُ إلى PostusgreSQL إذا فشل البحث الدهني

المجموعة المُجَزَزَة مع انفصام الرتبتين المتطابقتين

السحر الحقيقي هو البحث المُهجر نستعمل انصهار RRRF لدمجها بشكل عادل.

لماذا البحث المختلط؟

وتنطوي نُهج البحث المختلفة على مواطن قوة مختلفة:

• نوع البحث |------------|-----------|------------| | Name □ مرادفات، ومعنى، ومفاهيم □ قد تفوت عبارات دقيقة □ | النص الكامل □ كلمات رئيسية دقيقة، مصطلحات تقنية □ لا يوجد تفاهم مرادف □

مثال: البحث عن "نشر وعاء"

  • الاكتشافات الدهنية: "مفاهيم ذات صلة" و"أدلة الكورنتيس" (المفاهيم ذات الصلة)
  • (أ) الوظائف التي تتضمن تحديداً "نشر حاوية"
  • الحصول على أفضل ما في كل منهما!

RRR RR RR Angorththm

flowchart TB
    subgraph Semantic[Semantic Results]
        S1[Docker Containers - 0.92]
        S2[Kubernetes Basics - 0.87]
        S3[Container Security - 0.81]
    end

    subgraph FullText[Full-Text Results]
        F1[Container Security - rank 1]
        F2[Docker Containers - rank 2]
        F3[CI/CD Pipelines - rank 3]
    end

    subgraph RRF[RRF Scores]
        R1[Container Security = 0.0327]
        R2[Docker Containers = 0.0325]
        R3[Kubernetes Basics = 0.0161]
        R4[CI/CD Pipelines = 0.0159]
    end

    subgraph Final[Final Ranking]
        O1[Container Security]
        O2[Docker Containers]
        O3[Kubernetes Basics]
        O4[CI/CD Pipelines]
    end

    S1 --> R2
    S2 --> R3
    S3 --> R1
    F1 --> R1
    F2 --> R2
    F3 --> R4
    R1 --> O1
    R2 --> O2
    R3 --> O3
    R4 --> O4

والصيغة: score = Σ(1 / (k + rank))

المصدر: المصدر: المصدر:

  • k = 60 )على نحو يمنع الرتب الأولى من السيطرة(
  • rank (بمفهرسة واحدة)

لماذا يعمل RRF:

  • النتائج التي تظهر في -لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا أعلى من مستوى أعلى
  • لا يوجد مصدر واحد يمكن السيطرة عليه
  • لا حاجة إلى تركيبة

التنفيذ

private async Task<List<SearchResults>> HybridSearchAsync(string query, string host)
{
    // Run both searches in parallel
    var fullTextTask = GetFullTextResultsAsync(query);
    var semanticTask = semanticSearchService.SearchAsync(query, limit: 20);

    await Task.WhenAll(fullTextTask, semanticTask);

    var fullTextResults = await fullTextTask;
    var semanticResults = await semanticTask;

    // Apply Reciprocal Rank Fusion to combine results
    var rrfScores = new Dictionary<string, (double Score, string Title, string Slug)>();

    // Score full-text results
    for (int i = 0; i < fullTextResults.Count; i++)
    {
        var (title, slug) = fullTextResults[i];
        var key = slug.ToLowerInvariant();
        var rrfScore = 1.0 / (RrfConstant + i + 1);

        if (rrfScores.TryGetValue(key, out var existing))
        {
            rrfScores[key] = (existing.Score + rrfScore, title, slug);
        }
        else
        {
            rrfScores[key] = (rrfScore, title, slug);
        }
    }

    // Score semantic results
    for (int i = 0; i < semanticResults.Count; i++)
    {
        var result = semanticResults[i];
        var key = result.Slug.ToLowerInvariant();
        var rrfScore = 1.0 / (RrfConstant + i + 1);

        if (rrfScores.TryGetValue(key, out var existing))
        {
            rrfScores[key] = (existing.Score + rrfScore, existing.Title, existing.Slug);
        }
        else
        {
            rrfScores[key] = (rrfScore, result.Title, result.Slug);
        }
    }

    // Sort by combined RRF score and return top results
    return rrfScores.Values
        .OrderByDescending(x => x.Score)
        .Take(15)
        .Select(x => new SearchResults(
            x.Title.Trim(),
            x.Slug,
            Url.ActionLink("Show", "Blog", new { x.Slug }, "https", host)))
        .ToList();
}

تفاصيل التنفيذ الرئيسية:

  1. تنفيذ مُنَفْث: البحثان يجريان بصورة متزامنة (كلا البحثين يجريان في آن واحد)Task.WhenAll)
  2. حالة غير حساسةDedupمُطَرَّد مُسْطَرَدُ مَع: ToLowerInvariant()
  3. معدل التراكم:: نفس الوظيفة في كلا المصدرين تُضاف درجات
  4. & أعلى 15 النتائجبما فيه الكفاية للنوع الرأس، وليس السخام

بحث البحث الكامل

عندما يكون البحث الدلالي معطلاً أو فاشلاً، نتراجع إلى بحث النص الكامل في بوستغريسQL.

& مُسو المُسو المُسو المُ

بحث النص الكامل يعالج حالتين مختلفتين:

private async Task<List<(string Title, string Slug)>> GetFullTextResultsAsync(string query)
{
    if (!query.Contains(' '))
        return await searchService.GetSearchResultForComplete(query);  // Wildcard
    else
        return await searchService.GetSearchResultForQuery(query);     // Web search
}

كلمة واحدة استخدامات بطاقة برية docker:* كلمات متعددة ("حاويات الكركر"): استخدامات الموقع

أزوس الموضعSSQL استفسارات

// Single word with wildcard
private IQueryable<BlogPostEntity> QueryForWildCard(string query)
{
    return context.BlogPosts
        .Include(x => x.Categories)
        .Include(x => x.LanguageEntity)
        .AsNoTracking()
        .Where(x =>
            !x.IsHidden
            && (x.ScheduledPublishDate == null || x.ScheduledPublishDate <= now)
            && (x.SearchVector.Matches(EF.Functions.ToTsQuery("english", query + ":*"))
                || x.Categories.Any(c =>
                    EF.Functions.ToTsVector("english", c.Name)
                        .Matches(EF.Functions.ToTsQuery("english", query + ":*"))))
            && x.LanguageEntity.Name == "en")
        .OrderByDescending(x =>
            x.SearchVector.Rank(EF.Functions.ToTsQuery("english", query + ":*")));
}

// Multiple words with web search
private IQueryable<BlogPostEntity> QueryForSpaces(string processedQuery)
{
    return context.BlogPosts
        .Where(x =>
            x.SearchVector.Matches(EF.Functions.WebSearchToTsQuery("english", processedQuery))
            || x.Categories.Any(c =>
                EF.Functions.ToTsVector("english", c.Name)
                    .Matches(EF.Functions.WebSearchToTsQuery("english", processedQuery))))
        .OrderByDescending(x =>
            x.SearchVector.Rank(EF.Functions.WebSearchToTsQuery("english", processedQuery)));
}

ألف - WebSearchToTsQuery? إنه يتعامل مع الإستفسارات اللغوية الطبيعية مثل جوجل:

  • "docker containers" البحث عن كلا الكلمتين
  • docker OR kubernetes مقدم من مقدم من
  • docker -compose يستبعد "المُعَزَّل"

لمزيد لمزيد من المزيد من PostgresSQLL كامل نص ابحث ابحث انظر جاري البحث مع الموضعات.

صفحة البحث الكامل

إلى أبعد من هذا النوع، هناك صفحة نتائج بحث كاملة مع المرشّح المتقدّم:

flowchart LR
    subgraph SearchPage[Search Page]
        A[Query Input] --> B{Filters}
        B --> C[Language Filter]
        B --> D[Date Range Filter]
        C --> E[Search Results]
        D --> E
        E --> F[Paginated List]
    end

    style A stroke:#10b981,stroke-width:2px
    style B stroke:#6366f1,stroke-width:2px
    style E stroke:#ec4899,stroke-width:2px
    style F stroke:#8b5cf6,stroke-width:2px

)ليــك فــك

[Route("search")]
public class SearchController(
    BaseControllerService baseControllerService,
    BlogSearchService searchService,
    ISemanticSearchService semanticSearchService,
    ILogger<SearchController> logger)
    : BaseController(baseControllerService, logger)
{
    [HttpGet]
    [Route("")]
    [OutputCache(Duration = 3600, VaryByQueryKeys = new[] { "query", "page", "pageSize", "language", "dateRange", "startDate", "endDate" })]
    public async Task<IActionResult> Search(
        string? query,
        int page = 1,
        int pageSize = 10,
        string? language = null,
        DateRangeOption dateRange = DateRangeOption.AllTime,
        DateTime? startDate = null,
        DateTime? endDate = null,
        [FromHeader] bool pagerequest = false)
    {
        // Calculate date range based on option
        var (calculatedStartDate, calculatedEndDate) = CalculateDateRange(dateRange, startDate, endDate);

        // Get available languages for the filter dropdown
        var availableLanguages = await searchService.GetAvailableLanguagesAsync();

        if (string.IsNullOrEmpty(query?.Trim()))
        {
            var emptyModel = new SearchResultsModel { /* ... */ };
            if (Request.IsHtmx()) return PartialView("SearchResults", emptyModel);
            return View("SearchResults", emptyModel);
        }

        var searchResults = await searchService.HybridSearchWithPagingAsync(
            query,
            language,
            calculatedStartDate,
            calculatedEndDate,
            page,
            pageSize);

        // Build response model...
        if (pagerequest && Request.IsHtmx())
            return PartialView("_SearchResultsPartial", searchModel.SearchResults);
        if (Request.IsHtmx())
            return PartialView("SearchResults", searchModel);
        return View("SearchResults", searchModel);
    }
}

public enum DateRangeOption
{
    AllTime,
    LastWeek,
    LastMonth,
    LastYear,
    Custom
}

private static (DateTime? StartDate, DateTime? EndDate) CalculateDateRange(
    DateRangeOption dateRange, DateTime? startDate, DateTime? endDate)
{
    var now = DateTime.UtcNow;
    return dateRange switch
    {
        DateRangeOption.LastWeek => (now.AddDays(-7), now),
        DateRangeOption.LastMonth => (now.AddMonths(-1), now),
        DateRangeOption.LastYear => (now.AddYears(-1), now),
        DateRangeOption.Custom => (startDate, endDate),
        _ => (null, null) // AllTime - no date filter
    };
}

الوظائف ذات الصلة التي لا يزال تحميلها

كل تدوينة تظهر نقاط متشابهة بشكل عام في لوحة قابلة للذوبان. هذا يستخدم HTMX للتحميل الكسول:

<!-- In blog post view -->
<div class="print:hidden"
     hx-get="/search/related/@Model.Slug/@Model.Language"
     hx-trigger="load delay:500ms"
     hx-swap="innerHTML">
    <!-- Loading placeholder -->
    <div class="mt-8 mb-8 text-center opacity-50">
        <span class="loading loading-spinner loading-md"></span>
        <p class="text-sm mt-2">Finding related posts...</p>
    </div>
</div>

لماذا التأخير 500ms؟ تحميل المحتوى الرئيسي أولاً، ثم تحميل الوظائف ذات الصلة في الخلفية. يرى المستخدمون المحتوى فوراً.

الوظائف ذات الصلة

[HttpGet]
[Route("related/{slug}/{language}")]
[OutputCache(Duration = 7200, VaryByRouteValueNames = new[] {"slug", "language"})]
public async Task<IActionResult> RelatedPosts(string slug, string language, int limit = 5)
{
    var results = await semanticSearchService.GetRelatedPostsAsync(slug, language, limit);

    if (Request.IsHtmx())
    {
        return PartialView("_RelatedPosts", results);
    }

    return Json(results);
}

محفوظة لمدة 2 ساعةالوظائف ذات الصلة لا تتغير كثيراً، لذا التثبيت العدواني آمن.

عنصر الوظائف ذات الصلة

A ديزي أوي مكون مع تقدّم شعاعي يُظهر درجات تشابه:

@model List<SearchResult>

@if (Model != null && Model.Any())
{
    <div class="mt-8 mb-8">
        <div class="collapse collapse-arrow bg-base-200">
            <input type="checkbox" class="peer" />
            <div class="collapse-title text-xl font-medium">
                <i class='bx bx-brain text-2xl mr-2'></i>
                Related Posts
                <span class="badge badge-secondary badge-sm ml-2">@Model.Count</span>
            </div>
            <div class="collapse-content">
                <div class="divider mt-0"></div>
                <div class="space-y-2">
                    @foreach (var post in Model)
                    {
                        <div class="card bg-base-100 shadow-sm hover:shadow-md transition-shadow">
                            <div class="card-body p-4">
                                <div class="flex items-start justify-between">
                                    <div class="flex-1">
                                        <a hx-boost="true"
                                           hx-target="#contentcontainer"
                                           asp-action="Show"
                                           asp-controller="Blog"
                                           asp-route-slug="@post.Slug"
                                           asp-route-language="@post.Language"
                                           class="card-title text-base hover:text-secondary">
                                            @post.Title
                                        </a>

                                        @if (post.Categories?.Any() == true)
                                        {
                                            <div class="flex flex-wrap gap-1 mt-2">
                                                @foreach (var category in post.Categories.Take(3))
                                                {
                                                    <span class="badge badge-outline badge-sm">@category</span>
                                                }
                                            </div>
                                        }

                                        <div class="flex items-center gap-3 mt-2 text-sm opacity-70">
                                            <span>
                                                <i class='bx bx-calendar'></i>
                                                @post.PublishedDate.ToString("MMM dd, yyyy")
                                            </span>
                                            <span>
                                                <i class='bx bx-planet'></i>
                                                @post.Language.ToUpper()
                                            </span>
                                        </div>
                                    </div>

                                    <!-- Similarity Score -->
                                    <div class="flex flex-col items-end ml-4">
                                        <div class="radial-progress text-primary text-xs"
                                             style="--value:@(post.Score * 100); --size:3rem; --thickness:3px;"
                                             role="progressbar">
                                            @((post.Score * 100).ToString("F0"))%
                                        </div>
                                        <span class="text-xs opacity-60 mt-1">similarity</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </div>
        </div>
    </div>
}

التقدم الشعاعي يُظهر التشابه كنسبة مئوية (0-10 في المائة)، يساعد المستخدمين على فهم مدى ترابط كل وظيفة.

الرقم المرجعي

نمط

GET /api/search/{query}

□ البارامترات/ النوع / الوصف / |-----------|------|-------------| | query Yo twork (bat) / البحث مصطلح (min 2bars) /

المصدر: المصدر: List<SearchResults>

[
  {
    "title": "Docker Containers Explained",
    "slug": "docker-containers",
    "url": "https://example.com/blog/docker-containers"
  }
]

كثب: ساعة، تختلف حسب الاستعلام

&

GET /search/semantic?query={query}&limit={limit}

□ البارامترات/ النوع / الإفتراض / الوصف / |-----------|------|---------|-------------| | query □ خَطط مُطْرَط عليه □ مُسْطَطَطْطَط | limit ° فينت / 10 / ماكس النتائج / /

المصدر: المصدر: List<SearchResult> مع وجود درجات متشابهة

الوظائف المتصلة بها

GET /search/related/{slug}/{language}?limit={limit}

□ البارامترات/ النوع / الإفتراض / الوصف / |-----------|------|---------|-------------| | slug ° الخيط المطلوب □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ | language □ الوتر □ الشفرة اللغوية المطلوبة (en, es, et al.) □ | limit خ ع 5 خ ع (رأ) الوظائف ذات الصلة

المصدر: المصدر: List<SearchResult> تم فرزها بالتشابه

كثب: ساعتان، تختلف باختلاف اللغتين واللغتين

GET /search?query={query}&page={page}&pageSize={pageSize}&language={language}&dateRange={dateRange}&startDate={startDate}&endDate={endDate}

□ البارامترات/ النوع / الإفتراض / الوصف / |-----------|------|---------|-------------| | query □ خَطط مُطْرَط عليه □ مُسْطَطَطْطَط | page )ي( عدد الصفحات | pageSize ° فينت 10 / 10 النتائج في كل صفحة | language □ سلسلة نصية □ لا □ لا □ لا □ □ لا □ □ لا □ لا □ □ □ لا □ □ □ □ □ □ □ لا □ □ □ □ □ □ | dateRange "كل الوقت" "كل الوقت" "كل الوقت" "الأخير" "الأسبوع الأخير" "الشهر الأخير" "العام الأخير" "العام الأخير" "العادات" | startDate تاريخ بدء التشغيل (مع التاريخ Range=Custom) | endDate التاريخ النهائي (مع التاريخ Range=Custom)

بيانات أداء أداء

// Typeahead - 1 hour (queries are repeated often)
[OutputCache(Duration = 3600, VaryByQueryKeys = new[] { "query" })]

// Related posts - 2 hours (rarely change)
[OutputCache(Duration = 7200, VaryByRouteValueNames = new[] {"slug", "language"})]

// Full search - 1 hour (many filter combinations)
[OutputCache(Duration = 3600, VaryByQueryKeys = new[] { "query", "page", "pageSize", "language", "dateRange", "startDate", "endDate" })]

الشطب

الـ مُستخدِم مُدخِل مُستخدِم مُستخدَم مُستخدَم مُستخدَم مُستخدَم مُستخدَم مُستخدَم مُستخدَم:

x-on:input.debounce.300ms="search"

300ms هو توازن جيد - سريع بما فيه الكفاية للشعور بالتجاوب، بطيئة بما فيه الكفاية للحد من حمولة الخادم.

جاري تحميل

load delay: (ب) محفزات المحتوى غير الحرجة:

hx-trigger="load delay:500ms"

وهذا يكفل أن يكون المحتوى الرئيسي مرئياً قبل تحميل المحتوى الثانوي.

ما هو التالي

هذه المادة تشمل ما يلي: الخبرة المكتسبة من -كيف يتفاعل المستخدمون مع البحث الدنانيكي (أ) (أ) بما في ذلك الفهرسة الآلية وخدمة المعلومات الأساسية، تواصل القيام بما يلي:

الجزء 5: البحث المُدَرَّج و تلقائياً - أنماط الإنتاج:

  • ملف SSSystSystem Watre الوقت الحقيقي
  • خدمة المعلومات الأساسية لفهرسة بدء التشغيل
  • مُشَكَجِجَجِزِ

الموارد الخارجة عن

مواد مُسْمِمْمِم

كلّ الرموز المتوفرة في: chithub. com/doggal/ chweb

  • Mostlylucid/API/SearchApi.cs - متوسط - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • Mostlylucid/Controllers/SearchController.cs - صفحة البحث الكامل
  • Mostlylucid.Services/Blog/BlogSearchService.cs - منطق البحث
  • Mostlylucid/src/js/typeahead.js - المكوّن المكوّن
Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.