NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Tuesday, 17 September 2024
//Less than a minute
यह सिर्फ एक त्वरित लेख है जब यह पूर्ण पाठ खोज श्रृंखला में दूसरों पर निर्भर करता है टाइप हेड नीचे और पूरा पाठ खोज. इस पोस्ट में, मैं आपको दिखा सकता हूँ कि HMMX तथा ईएफ को सीएफ में कैसे लागू कर सकते हैं
खैर, साइट के शीर्ष में मेरे पास एक खोज फंक्शन है जो प्रकार का संकेतक प्रदान करता है (जहाँ आप टाइप टाइप करते हैं वास्तविक समय में आता है). लेकिन मैं छिपाता हूँ कि मोबाइल मोड में और मैं भी खोज परिणाम लिंक करने में समर्थ होना चाहता हूँ (जैसे कि जैसे कि) / ढूंढें/मा( क) समर्पित खोज पृष्ठ पर । यह एक बेहतर उपयोगकर्ता का अनुभव देता है, साथ ही मोबाइल उपकरणों पर काम करता है.
यह मैं परिवर्धित करने के लिए मैं कैसे मेरी खोज की. और मैंने एक पैदा किया; BlogSearchService
, यह मेरे दो पूरे पाठ क्वैरी तरीकों पर आधारित है. इन दुखियों को दो तरीकों से विभाजित करने की जरूरत है क्योंकि जिस तरह से डाका पूर्ण पाठ खोज विस्तार के साथ बनाया जाता है, EF.Functions.WebSearchToTsQuery("english", processedQuery)
और EF.Functions.ToTsQuery("english", query + ":*")
.
सबसे पहले उचित खोज की ज़रूरत होती है और दूसरा MAV खोज लेता है.
private IQueryable<BlogPostEntity> QueryForSpaces(string processedQuery)
{
return context.BlogPosts
.Include(x => x.Categories)
.Include(x => x.LanguageEntity)
.AsNoTrackingWithIdentityResolution()
.Where(x =>
// Search using the precomputed SearchVector
(x.SearchVector.Matches(EF.Functions.WebSearchToTsQuery("english",
processedQuery)) // Use precomputed SearchVector for title and content
|| x.Categories.Any(c =>
EF.Functions.ToTsVector("english", c.Name)
.Matches(EF.Functions.WebSearchToTsQuery("english", processedQuery)))) // Search in categories
&& x.LanguageEntity.Name == "en") // Filter by language
.OrderByDescending(x =>
// Rank based on the precomputed SearchVector
x.SearchVector.Rank(EF.Functions.WebSearchToTsQuery("english",
processedQuery)));
}
private IQueryable<BlogPostEntity> QueryForWildCard(string query)
{
return context.BlogPosts
.Include(x => x.Categories)
.Include(x => x.LanguageEntity)
.AsNoTrackingWithIdentityResolution()
.Where(x =>
// Search using the precomputed SearchVector
(x.SearchVector.Matches(EF.Functions.ToTsQuery("english",
query + ":*")) // Use precomputed SearchVector for title and content
|| x.Categories.Any(c =>
EF.Functions.ToTsVector("english", c.Name)
.Matches(EF.Functions.ToTsQuery("english", query + ":*")))) // Search in categories
&& x.LanguageEntity.Name == "en") // Filter by language
.OrderByDescending(x =>
// Rank based on the precomputed SearchVector
x.SearchVector.Rank(EF.Functions.ToTsQuery("english",
query + ":*"))); // Use precomputed SearchVector for ranking
}
फिर से ये मेरे पूर्वनिर्धारित उपयोग में लें SearchVector
स्तम्भ जो पोस्ट बनाने व अद्यतन करने पर अद्यतन किया गया है. यह मेरी में बनाया गया है DbContext
प्रयोग कर रहा है OnModelCreating
विधि.
entity.Property(b => b.SearchVector)
.HasComputedColumnSql("to_tsvector('english', coalesce(\"Title\", '') || ' ' || coalesce(\"PlainTextContent\", ''))", stored: true);
entity.HasIndex(b => b.SearchVector)
.HasMethod("GIN");
फिर इस दृष्टिकोण की जाँच यह है कि यह केवल अंग्रेज़ी के रूप में है के लिए काम करता है. मुझे इस डाटाबेस के वास्तविक पुनर्वास की ज़रूरत होगी कि यह अन्य भाषाओं के लिए काम करे (जैसे कि प्रत्येक भाषा के लिए मेज़ के रूप में एक मेज़ है) ।
तब मैं इन तरीकों का उपयोग अपने में BlogSearchService
खोज क्वेरी पर आधारित परिणाम बताता है.
public async Task<PostListViewModel> GetPosts(string? query, int page = 1, int pageSize = 10)
{
if(string.IsNullOrEmpty(query))
{
return new PostListViewModel();
}
IQueryable<BlogPostEntity> blogPostQuery = query.Contains(" ") ? QueryForSpaces(query) : QueryForWildCard(query);
var totalPosts = await blogPostQuery.CountAsync();
var results = await blogPostQuery
.Select(x => x.ToListModel())
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PostListViewModel()
{
Posts = results,
TotalItems = totalPosts,
Page = page,
PageSize = pageSize
};
}
मैं कैसे कॉल करने का विधि है यह निर्धारित करने के लिए कि किस विधि में स्पेसेस हैं के लिए सरल चेक का उपयोग करें.
खोज नियंत्रण मैं अपने अधिकांश नियंत्रणों के पैटर्न का पालन करता हूँ जहां यह पता चलता है कि क्या कॉल HMMX से आता है या नहीं किसी भी अधूरा या पूर्ण खाका पृष्ठ भेजने के लिए सक्षम नहीं (जैसे कि यह प्रत्यक्ष नेविगेशन तथा HMX निवेदन के लिए काम करता है).
[Route("search")]
public class SearchController(
BaseControllerService baseControllerService,
BlogSearchService searchService,
ILogger<SearchController> logger)
: BaseController(baseControllerService, logger)
{
[HttpGet]
[Route("{query?}")]
public async Task<IActionResult> Search([FromRoute] string? query)
{
var searchResults = await searchService.GetPosts(query);
var searchModel = new SearchResultsModel
{
Query = query,
SearchResults = searchResults
};
searchModel = await PopulateBaseModel(searchModel);
searchModel.SearchResults.LinkUrl = Url.Action("SearchResults", "Search");
if (Request.IsHtmx()) return PartialView("SearchResults", searchModel);
return View("SearchResults", searchModel);
}
[HttpGet]
[Route("results")]
public async Task<IActionResult> SearchResults([Required] string query, int page = 1, int pageSize = 10)
{
var searchResults = await searchService.GetPosts(query, page, pageSize);
var searchModel = new SearchResultsModel
{
Query = query,
SearchResults = searchResults
};
searchModel = await PopulateBaseModel(searchModel);
searchModel.SearchResults.LinkUrl = Url.Action("SearchResults", "Search");
if (Request.IsHtmx()) return PartialView("_SearchResultsPartial", searchModel.SearchResults);
return View("SearchResults", searchModel);
}
}
यह पूरे नियंत्रण है, आप देख सकते हैं कि मेरे पास दो क्रियाएँ हैं, एक जो पृष्ठ (वैकल्पिक रूप से इसके परिणाम) बताता है और एक जो केवल HMMX निवेदन के परिणाम बताता है.
if (Request.IsHtmx()) return PartialView("_SearchResultsPartial", searchModel.SearchResults);
आप देख सकते हैं कि यह वैकल्पिक रूप से लौटाता है _SearchResultsPartial
परिणाम स्वरूप के लिए निवेदन है कि क्या निवेदन है.
यह एक बहुत ही सरल नियमीय दृश्य है जिसमें pances और परिणाम होते हैं.
@model Mostlylucid.Models.Blog.PostListViewModel
<div class="pt-2" id="content">
@if (Model.Posts?.Any() is true)
{
<div class="inline-flex w-full items-center justify-center print:!hidden">
@if (Model.TotalItems > Model.PageSize)
{
<pager
x-ref="pager"
link-url="@Model.LinkUrl"
hx-boost="true"
hx-target="#content"
hx-swap="show:none"
page="@Model.Page"
page-size="@Model.PageSize"
total-items="@Model.TotalItems"
hx-headers='{"pagerequest": "true"}'>
</pager>
}
<partial name="_Pager" model="Model"/>
</div>
@foreach (var post in Model.Posts)
{
<partial name="_ListPost" model="post"/>
}
}
</div>
मैं एक ही उपयोग _ListPost
आंशिक दृश्य जहाँ भी मुझे पोस्टों की सूची करनी है.
@model Mostlylucid.Models.Blog.PostListModel
<div class="border-b border-grey-lighter pb-8 mb-8">
<a asp-controller="Blog" asp-action="Show" hx-boost="true" hx-swap="show:window:top" hx-target="#contentcontainer" asp-route-slug="@Model.Slug"
class="block font-body text-lg font-semibold transition-colors hover:text-green text-blue-dark dark:text-white dark:hover:text-secondary">@Model.Title</a>
<div class="flex flex-wrap space-x-2 items-center py-4 print:!hidden">
@foreach (var category in Model.Categories)
{
<partial name="_Category" model="category"/>
}
@{ var languageModel = (Model.Slug, Model.Languages, Model.Language); }
<partial name="_LanguageList" model="languageModel"/>
</div>
<div class="block font-body text-black dark:text-white">@Model.Summary</div>
<div class="flex items-center pt-4">
<p class="pr-2 font-body font-light text-primary light:text-black dark:text-white">
@Model.PublishedDate.ToString("f")
</p>
<span class="font-body text-grey dark:text-white">//</span>
<p class="pl-2 font-body font-light text-primary light:text-black dark:text-white">
@Model.ReadingTime
</p>
</div>
</div>
HMAX का मेरा उपयोग यहाँ बहुत सरल है. मैं सिर्फ बटन में हुक करता हूँ (इस बार मैंने तय किया था कि इस बार कुंजी अप / परिवर्तन के लिए इनपुट को नहीं बदल दूँगा) और जब बटन क्लिक किया जाता है तब इस अनुरोध को भेज दीजिए.
निवेदन में क्वैरी शामिल करें जो कि निवेदन में शामिल है hx-include
और लक्ष्य #content
परिणाम को बदलने के लिए पानी.
<div class="flex items-center gap-2 bg-neutral-500 bg-opacity-10 p-2 rounded-lg">
<button
hx-get="@Url.Action("SearchResults", "Search")"
hx-target="#content"
hx-include="[name='query']"
hx-swap="outerHTML"
class="btn btn-outline btn-sm flex items-center gap-2 text-black dark:text-white">
Search
<i class="bx bx-search text-lg"></i>
</button>
<input
type="text"
placeholder="Search..."
value="@Model.Query"
name="query"
class="input input-sm border-0 grow text-black dark:text-white bg-transparent focus:outline-none"/>
</div>
सो इससे कुछ टिप्पणियों का अनुसरण करें खाल मैं खोज को सक्षम करने के लिए इस प्रकार्य को विस्तार करने का फैसला किया:
भविष्य में मैं पृष्ठ आकार में वापस काम जोड़ने की जरूरत है; यह एक हैक का एक बिमेल है और अधिक आवश्यकताओं का समर्थन करने की जरूरत है.
यह करने के लिए मैंने पहली बार इनपुट को एक रूप में लपेट लिया और आन्नति के लिए प्रयोग किया जब उपयोगकर्ता टाइप कर रहा होता है इस रूप को आत्मसमर्पण करने के लिए।
आप देख सकते हैं कि मैं इस्तेमाल कर सकते हैं x-data
क्वैरी के लिए प्रतिक्रियाित वेरिएबल बनाने के लिए और फिर मैं प्रश्न की लंबाई की जाँच करता हूँ कि क्या इस फ़ॉर्म को जमा करना है.
<form
x-data="{ query: '@Model.Query', checkSubmit() { if (this.query.length > 2) { $refs.searchButton.click(); } } }"
class="flex items-center gap-2 bg-neutral-500 bg-opacity-10 p-2 rounded-lg"
action="@Url.Action("Search", "Search")"
hx-push-url="true"
hx-boost="true"
hx-target="#content"
hx-swap="outerHTML show:window:top"
hx-headers='{"pagerequest": "true"}'>
<button
type="submit"
x-ref="searchButton"
class="btn btn-outline btn-sm flex items-center gap-2 text-black dark:text-white">
Search
<i class="bx bx-search text-lg"></i>
</button>
<input
type="text"
placeholder="Search..."
name="query"
value="@Model.Query"
x-model="query"
x-on:input.debounce.200ms="checkSubmit"
x-on:keydown.enter.prevent="$refs.searchButton.click()"
class="input input-sm border-0 grow text-black dark:text-white bg-transparent focus:outline-none"
/>
</form>
मैं एक ही नियंत्रण कार्य को फिर से प्रयोग करने के लिए मैं भी सेट pagerequest
यह सूचित करने के लिए शीर्षक है कि यह एक plaged अनुरोध है.
मैं यू.js का भी इस्तेमाल करता हूँ x-on:keydown.enter.prevent
जब एंटर कुंजी दबाया जाए तो बटन को ट्रिगर करने के लिए क्लिक करें तथा इनपुट पर चले जाने के लिए बहुत से निवेदन रोकने के लिए क्लिक करें.
नियंत्रण में मैं खोज '% 1' क्रिया हटा दिया और इसके बजाय मुख्य में अधिक 'रूट' जोड़ें Search
आरंभिक खोज तथा समझौता किए गए अनुरोधों को नियंत्रित करने के लिए क्रिया.
यहाँ आप देख सकते हैं कि मैं एक अतिरिक्त पैरामीटर जोड़ें बुलाया गया pagerequest
यह निर्धारित करने के लिए कि क्या यह एक पेपलित निवेदन है या नहीं और सूचित करता है कि यह शीर्ष संग्रह से आबाद किया जाना चाहिए.
[HttpGet]
[Route("")]
public async Task<IActionResult> Search(string? query, int page = 1, int pageSize = 10,[FromHeader] bool pagerequest=false)
{
var searchResults = await searchService.GetPosts(query, page, pageSize);
var searchModel = new SearchResultsModel
{
Query = query,
SearchResults = searchResults
};
searchModel = await PopulateBaseModel(searchModel);
var linkUrl = Url.Action("Search", "Search");
searchModel.SearchResults.LinkUrl = linkUrl;
if(pagerequest && Request.IsHtmx()) return PartialView("_SearchResultsPartial", searchModel.SearchResults);
if (Request.IsHtmx()) return PartialView("SearchResults", searchModel);
return View("SearchResults", searchModel);
}
मैं फिर परिणाम मिलता है और इस शीर्षक का पता लगाने के लिए पता लगाने के लिए कि कौन सा आंशिक दृश्य वापसी के लिए.
मैंने और एक स्लेरेट रिटायर्ड रिटायर्ट ने आगे कहा की तरह काम करने के लिए /search/umami
क्वैरी के साथ मुख्य खोज पृष्ठ को पुनर्निदेशित करने के लिए.
[HttpGet]
[Route("{query}")]
public IActionResult InitialSearch([FromRoute] string query)
{
return RedirectToAction("Search", new { query });
}
तो, बहुत सरल है? यह एचएमएमएक्स तथा EF कोपीएसी में उपयोग कर एक खोज पृष्ठ का सीधे कार्यान्वयन है. Name आप आसानी से इसे फ़िल्टर, छंटाई, या अन्य खोज सेवाओं के साथ भी अधिक विशेषताओं को शामिल कर सकते हैं । कुंजी दूर है कि किस तरह एक नरम उपयोगकर्ता के अनुभव के लिए प्राप्त किया जा सकता है...... बैकेंड तर्क साफ और कुशल बनाए रखने के दौरान.