public ActionResult GetResult(string keywords, bool?isstrict, string topSearchKeywords) { bool isStrictQuery = isstrict ?? false; //TODO: use Input Sanitizer instead var keywordsCollection = InputSanitiser.ExtractWordsFromInput(keywords).ToList(); //sanitise input bool isPhrase = keywordsCollection.Count > 1; var sanitisedKeywordsAsString = string.Join(" ", keywordsCollection); var didYouMean = sanitisedKeywordsAsString; //First search exact word var results = _siteSearchService.GetRawResults(sanitisedKeywordsAsString, false).ToList(); //If no reasults and q is not strict - search fuzzy but display the corrected word if (!results.Any() && !isStrictQuery && keywordsCollection.Any()) { if (isPhrase) { RankedPhrase topPhrase = PhraseSuggester.GetTopPhraseAndResults(sanitisedKeywordsAsString); if (topPhrase != null) { didYouMean = topPhrase.Content; results = topPhrase.Results.ToList(); } } else { didYouMean = _spellChecker.Check(sanitisedKeywordsAsString); results = _siteSearchService.GetRawResults(sanitisedKeywordsAsString, true).ToList(); } } //Finally if still no results return the partial with top search words suggestions if (!results.Any()) { List <string> topSearchedTerms = topSearchKeywords.Split(',').ToList(); var vm = new NoResultsFoundVm { SearchedTerm = sanitisedKeywordsAsString, Keywords = topSearchedTerms }; return(PartialView("_NoSearchResultsAndSuggestions", vm)); } else { var contentResults = _siteSearchService.ConvertSearchResultToPublishedContentWithTemplate(results, ContentCache, UmbracoContext); var mappedResults = _siteSearchService.MapToCustomResults(contentResults); var vm = new SiteSearchVm { SearchedTerm = sanitisedKeywordsAsString, SpellCheckerSuggestionWord = didYouMean, SearcResults = mappedResults, }; return(PartialView("_SiteSearchResultsAndSuggestionsPartial", vm)); } }
public RankedPhrase GetTopPhraseAndResults(string keywords) { var termsInPhrase = InputSanitiser.ExtractWordsFromInput(keywords).Take(3).ToList(); //get up to 3 real words and sanitised var termsTop5Candidates = new List <List <string> >(); foreach (var word in termsInPhrase) { //if exact match exists it will be included in the top suggestions list as well as the other 5 var topSpellCheckerSuggestions = _spellChecker.GetTopSuggestions(word, 4); var topSpellCheckerSuggestionsStoWordsCleaned = InputSanitiser.GetRealWordsOnly(topSpellCheckerSuggestions); termsTop5Candidates.Add(topSpellCheckerSuggestionsStoWordsCleaned); } //The inutual null is used so that the first cross-join will have something to build on (with strings, null + s = s) IEnumerable <string> combinations = new List <string> { null }; foreach (var list in termsTop5Candidates) { // cross join the current result with each member of the next list combinations = combinations.SelectMany(o => list.Select(s => o + " " + s)); } //for reference: https://stackoverflow.com/questions/12251874/when-to-use-a-parallel-foreach-loop-instead-of-a-regular-foreach var phraseseAndResults = new ConcurrentBag <RankedPhrase>(); Parallel.ForEach(combinations, currentCombination => { var trimmedItem = currentCombination.Trim(); //trim white space var searchResultsItems = _siteSearchService.GetRawResults(trimmedItem, false).ToList(); var phrase = new RankedPhrase { Rank = searchResultsItems.Count, Results = searchResultsItems, Content = trimmedItem }; phraseseAndResults.Add(phrase); }); return(phraseseAndResults.OrderByDescending(x => x.Rank).FirstOrDefault()); }