/// <summary> /// function used in fuzzy search /// </summary> /// <param name="grouping"></param> /// <param name="query"></param> private static SearchGrouping CheckTitlesFuzzy(IGrouping <int, SVR_AnimeSeries> grouping, string query) { if (!(grouping?.SelectMany(a => a.GetAllTitles()).Any() ?? false)) { return(null); } SearchGrouping dist = null; foreach (SVR_AnimeSeries item in grouping) { foreach (string title in item.GetAllTitles()) { if (string.IsNullOrEmpty(title)) { continue; } int k = Math.Max(Math.Min((int)(title.Length / 6D), (int)(query.Length / 6D)), 1); if (query.Length <= 4 || title.Length <= 4) { k = 0; } Misc.SearchInfo <IGrouping <int, SVR_AnimeSeries> > result = Misc.DiceFuzzySearch(title, query, k, grouping); if (result.Index == -1) { continue; } SearchGrouping searchGrouping = new SearchGrouping { Distance = result.Distance, Index = result.Index, ExactMatch = result.ExactMatch, Match = title, Results = grouping.OrderBy(a => a.AirDate).ToList() }; if (result.Distance < (dist?.Distance ?? int.MaxValue)) { dist = searchGrouping; } } } return(dist); }
/// <summary> /// function used in fuzzy search /// </summary> /// <param name="grouping"></param> /// <param name="query"></param> private static SearchGrouping CheckTitlesIndexOf(IGrouping <int, SVR_AnimeSeries> grouping, string query) { if (!(grouping?.SelectMany(a => a.GetAllTitles()).Any() ?? false)) { return(null); } SearchGrouping dist = null; foreach (SVR_AnimeSeries item in grouping) { foreach (string title in item.GetAllTitles()) { if (string.IsNullOrEmpty(title)) { continue; } int result = title.IndexOf(query, StringComparison.OrdinalIgnoreCase); if (result == -1) { continue; } SearchGrouping searchGrouping = new SearchGrouping { Distance = 0, Index = result, ExactMatch = true, Match = title, Results = grouping.OrderBy(a => a.AirDate).ToList() }; if (result < (dist?.Index ?? int.MaxValue)) { dist = searchGrouping; } } } return(dist); }
public ActionResult <IEnumerable <SeriesSearchResult> > Search(string query, int limit = int.MaxValue) { SorensenDice search = new SorensenDice(); query = query.ToLowerInvariant(); query = query.Replace("+", " "); List <SeriesSearchResult> seriesList = new List <SeriesSearchResult>(); ParallelQuery <SVR_AnimeSeries> allSeries = RepoFactory.AnimeSeries.GetAll() .Where(a => a?.Contract?.AniDBAnime?.AniDBAnime != null && !a.Contract.AniDBAnime.Tags.Select(b => b.TagName) .FindInEnumerable(User.GetHideCategories())) .AsParallel(); HashSet <string> languages = new HashSet <string> { "en", "x-jat" }; languages.UnionWith(ServerSettings.Instance.LanguagePreference); var distLevenshtein = new ConcurrentDictionary <SVR_AnimeSeries, Tuple <double, string> >(); allSeries.ForAll(a => CheckTitlesFuzzy(search, languages, a, query, ref distLevenshtein, limit)); var tempListToSort = distLevenshtein.Keys.GroupBy(a => a.AnimeGroupID).Select(a => { var tempSeries = a.ToList(); tempSeries.Sort((j, k) => { var result1 = distLevenshtein[j]; var result2 = distLevenshtein[k]; var exactMatch = result1.Item1.CompareTo(result2.Item1); if (exactMatch != 0) { return(exactMatch); } string title1 = j.GetSeriesName(); string title2 = k.GetSeriesName(); if (title1 == null && title2 == null) { return(0); } if (title1 == null) { return(1); } if (title2 == null) { return(-1); } return(string.Compare(title1, title2, StringComparison.InvariantCultureIgnoreCase)); }); var result = new SearchGrouping { Series = a.OrderBy(b => b.AirDate).ToList(), Distance = distLevenshtein[tempSeries[0]].Item1, Match = distLevenshtein[tempSeries[0]].Item2 }; return(result); }); Dictionary <SVR_AnimeSeries, Tuple <double, string> > series = tempListToSort.OrderBy(a => a.Distance) .ThenBy(a => a.Match.Length).SelectMany(a => a.Series).ToDictionary(a => a, a => distLevenshtein[a]); foreach (KeyValuePair <SVR_AnimeSeries, Tuple <double, string> > ser in series) { seriesList.Add(new SeriesSearchResult(HttpContext, ser.Key, ser.Value.Item2, ser.Value.Item1)); if (seriesList.Count >= limit) { break; } } return(seriesList); }