private async Task <IEnumerable <int> > GetRecipesForIngrediantsSearchQuery(IIncludableQueryable <Recipe, Ingrediant> recipes, RecipeSearchViewModel model) { Dictionary <string, int> allEntries = null; var hits = new List <int>(); try { foreach (var searchIngrediant in model.Ingrediants) { // check if tag are found within database IEnumerable <int> currentHits = await recipes .SelectMany(x => x.Ingrediants) .Where(ingrediant => ingrediant.Ingrediant.Name.Contains(searchIngrediant, true)) .Select(x => x.IngrediantId) .ToListAsync(); if (currentHits.Any()) { Logger.LogDebug($"Found fuzzy result in source data. Searched for {model}. Found {currentHits}"); hits.AddRange(currentHits); continue; } // if no hits, lookup for fuzzy search cache for search query currentHits = await Repository.GetCachedFuzzyResultAsync(nameof(Ingrediant), searchIngrediant); if (currentHits.Any()) { Logger.LogDebug($"Found fuzzy result in cache data. Searched for {model}. Found {currentHits}"); hits.AddRange(currentHits); continue; } // If no hits available, load all elements and process a fuzzy search on them // TODO: Change to 'real' caching (e.g. Lucene) if (allEntries == null) { var peng = await recipes.FirstOrDefaultAsync(); allEntries = await recipes .SelectMany(x => x.Ingrediants) .Select(x => x.Ingrediant) .Where(x => x != null) .Distinct() .ToDictionaryAsync(x => x.Name, x => x.Id); } var fuzzyoptions = new[] { FuzzyStringComparisonOptions.UseJaccardDistance, FuzzyStringComparisonOptions.UseLongestCommonSubstring, FuzzyStringComparisonOptions.UseSorensenDiceDistance }; var fuzzyHits = allEntries.Keys.Where(x => x.ApproximatelyEquals(searchIngrediant, FuzzyStringComparisonTolerance.Normal, fuzzyoptions)).ToList(); if (!fuzzyHits.Any()) { Logger.LogDebug($"No result found for fuzzy search. Searched for {model}"); continue; } // if hit is found, save to cache for reuse foreach (var entry in fuzzyHits) { var newEntry = new FuzzyEntry() { Id = allEntries[entry], SearchQuery = searchIngrediant, Type = nameof(Ingrediant) }; await Repository.SaveFuzzyEntryAsync(newEntry); hits.Add(allEntries[entry]); Logger.LogDebug($"Found data after calculating cache result. Searched for {model}. Found {entry} ({allEntries[entry]})"); } } } catch (Exception e) { this.Logger.LogError(new EventId(), e, $"Error on fuzzy search. Searched for {model}"); } return(hits.Distinct()); }
private async Task <IEnumerable <int> > GetRecipesForTagSearchQuery(IIncludableQueryable <Recipe, RecipeTag> recipes, RecipeSearchViewModel model) { Dictionary <string, int> allEntries = null; var hits = new List <int>(); try { foreach (var searchModelTag in model.Tags) { // check if tag are found within database IEnumerable <int> currentHits = await recipes.SelectMany(x => x.Tags).Where(x => x.RecipeTag.Name.Contains(searchModelTag, true)).Select(x => x.RecipeTagId).ToListAsync(); if (currentHits.Any()) { hits.AddRange(currentHits); Logger.LogDebug($"Found fuzzy result in source data. Searched for {model}. Found {currentHits}"); continue; } // if no hits, lookup for fuzzy search cache for search query currentHits = await Repository.GetCachedFuzzyResultAsync(nameof(RecipeTag), searchModelTag); if (currentHits.Any()) { hits.AddRange(currentHits); Logger.LogDebug($"Found fuzzy result in cache data. Searched for {model}. Found {currentHits}"); continue; } // If no hits available, load all elements and process a fuzzy search on them // TODO: Change to 'real' caching (e.g. Lucene) if (allEntries == null) { // must be here to enable navigation property for RecipeTags var recipe = await recipes.FirstOrDefaultAsync(); allEntries = await recipes .SelectMany(x => x.Tags) .Select(x => x.RecipeTag) .Where(x => x != null) .Distinct() .ToDictionaryAsync(x => x.Name, x => x.Id); } var fuzzyHits = allEntries.Keys.Where(x => x.ApproximatelyEquals(searchModelTag, FuzzyStringComparisonTolerance.Normal, FuzzyStringComparisonOptions.UseLevenshteinDistance)).ToList(); if (!fuzzyHits.Any()) { Logger.LogDebug($"No result found for fuzzy search. Searched for {model}"); continue; } // if hit is found, save to cache for reuse foreach (var entry in fuzzyHits) { var newEntry = new FuzzyEntry() { Id = allEntries[entry], SearchQuery = searchModelTag, Type = nameof(RecipeTag) }; await Repository.SaveFuzzyEntryAsync(newEntry); hits.Add(allEntries[entry]); Logger.LogDebug($"Found data after calculating cache result. Searched for {model}. Found {entry} ({allEntries[entry]})"); } } } catch (Exception e) { Console.WriteLine(e); throw e; } return(hits.Distinct()); }