根据一组关键字进行搜索

我需要根据一组关键字进行搜索,这些关键字会返回与这些关键字相关的所有广告。 然后,结果是一个类别列表,其中包含每个类别的广告计数。

搜索在关键字搜索表中进行:

public class KeywordSearch { public int Id { get; set; } public string Name { get; set; } public Keyword Keyword { get; set; } } 

关键字表的位置是:

 public class Keyword { public int Id { get; set; } public string Name { get; set; } } 

广告与使用下表的关键字相关:

 public class KeywordAdCategory { [Key] [Column("Keyword_Id", Order = 0)] public int Keyword_Id { get; set; } [Key] [Column("Ad_Id", Order = 1)] public int Ad_Id { get; set; } [Key] [Column("Category_Id", Order = 2)] public int Category_Id { get; set; } } 

最后,分类表:

 public class Category { public int Id { get; set; } public string Name { get; set; } } 

例:

  • 关键词:“梅赛德斯 – 奔驰”和“GLK”
  • 关键字搜索:“梅赛德斯”和“奔驰”为关键字“梅赛德斯 – 奔驰”“GLK”为关键字“GLK”
  • 类别:“汽车”和“卡车”
  • 广告:汽车 – 梅赛德斯 – 奔驰GLK卡车 – 梅赛德斯 – 奔驰Citan

    如果我搜索“梅赛德斯 – 奔驰”,我会得到:

    • 汽车:1
    • 卡车:1

    如果我搜索“Mercedes-Benz GLK”,我会得到:

    • 汽车:1

    如果我搜索“Mercedes Citan”,我会得到:

    • 卡车:1

直到现在我得到的:

 var keywordIds = from k in keywordSearchQuery where splitKeywords.Contains(k.Name) select k.Keyword.Id; var matchingKac = from kac in keywordAdCategoryQuery where keywordIds.Distinct().Contains(kac.Keyword_Id) select kac; var addIDs = from kac in matchingKac group kac by kac.Ad_Id into d where d.Count() == splitKeywords.Count() select d.Key; var groupedKac = from kac in keywordAdCategoryQuery where addIDs.Contains(kac.Ad_Id) <--- EDIT2 group kac by new { kac.Category_Id, kac.Ad_Id }; var result = from grp in groupedKac group grp by grp.Key.Category_Id into final join c in categoryQuery on final.Key equals c.Id select new CategoryGetAllBySearchDto { Id = final.Key, Name = c.Name, ListController = c.ListController, ListAction = c.ListAction, SearchCount = final.Count() }; 

问题是我无法获得与所有关键字匹配的广告。

编辑:

当关键字由2个或更多KeywordSearches(如“Mercedes-Benz”)组成时,“其中d.Count()== splitKeywords.Count()”行失败,因为d.count = 1且splitkeywords.Count = 2表示“梅赛德斯 – 奔驰”

任何帮助?

这可能不是直接的答案,但在这种“多参数搜索”的情况下,我只是忘记任何事情并做简单的事情,例如:搜索汽车制造商,CategoryId,MillageMax,价格:

 var searchResults = from c in carDb.Cars where (c.Manufacturer.Contains(Manufacturer) || Manufacturer == null) && (c.CategoryId == CategoryId || CategoryId == null) && (c.Millage <= MillageMax || MillageMax== null) && (c.Price <= Price || Price == null) select c 

现在,如果任何参数为null则通过将括号中的整个表达式设为True来取消包含行,因此它不再参与搜索

如果你试图制作自己的搜索引擎,你可能会失败。你为什么不尝试Lucene。 这是http://lucenenet.apache.org/的链接。 干杯

我想我现在有一个解决方案。 这是基于您之前的问题和一些假设:

  1. 关键词是完整的名称,如“梅赛德斯 – 奔驰GLK”,“梅赛德斯 – 奔驰Citan”。
  2. KeywordSearchs是“Mercedes”,“Benz”和“GLK”代表“Mercedes-Benz GLK”和“Mercedes”,“Benz”和“Citan”代表“Mercedes-Benz Citan”
  3. “梅赛德斯 – 奔驰GLK”是“汽车”,“梅赛德斯 – 奔驰Citan”是“卡车”

考虑到这三个假设,我可以这么说

 var keywordIds = from k in keywordSearchQuery where splitKeywords.Contains(k.Name) select k.Keyword.Id; 

是罪魁祸首,下面的所有问题都依赖于它。 此查询将查找包含搜索字符串中任何字词的所有关键字。

示例:给定搜索字符串“Mercedes-Benz GLK”将分为“Mercedes”,“Benz”和“GLK”。 您的查询现在在“Mercedes-Benz GLK”和“Mercedes-Benz Citan”中找到“Mercedes”和“Benz”。
我认为很明显你不希望“梅赛德斯 – 奔驰GLK”与“梅赛德斯 – 奔驰Citan”相提并论。

解决方案是告诉查询将每个splitKeywords与任何Keywordsearch匹配并返回相应的关键字:

 var keywordIds = keywordSearchQuery .GroupBy(k => k.Keyword.Id) .Where(g => splitKeywords.All(w => g.Any(k => k.Name.Contains(w)))) .Select(g => g.Key); 

对于addIds,将其更改为var addIDs = matchingKac.Select(ad => ad.Ad_Id).Distinct(); 应该做的伎俩。 或者,如果仅在addIds中需要matchingKac,则可以将其更改为

 var matchingKac = (from kac in keywordAdCategoryQuery where keywordIds.Distinct().Contains(kac.Keyword_Id) select kac.Ad_Id).Distinct(); 

并删除addIds。

我没有编译检查这个或任何东西,所以它可能需要一些调整,但你正在寻找这些方面的东西。

 var matchingKac = keywordIds.Distinct().ToList() .Aggregate( keywordAdCategoryQuery.AsQueryable(), (q, id) => q.Where(kac => kac.Keyword_Id == id)); 

你实际上是在说,“从keywordAdCategoryQuery开始,并为每个关键字添加一个.Where()条件,说明它必须包含该关键字。如果你发现Aggregate难以阅读,你可以用for循环做同样的事情。

我建议你添加正则表达式并省略那些特殊字符,然后使用Linq

因此梅赛德斯 – 奔驰可以成为梅赛德斯和奔驰

我建议不要以这种方式为对象定义关键字,因为您可能会搜索并找到太多对象,或者您可能找不到任何对象。 在搜索时,您总会浪费时间。 以用户关注的方式对对象进行分类,而不是搜索。

我已将我的答案发布到: https : //github.com/n074v41l4bl34u/StackOverflow19796132随时查看它。

这是最重要的片段。


有:

 internal class SearchDomain { public List Keywords { get; set; } public List Categories { get; set; } public List KeywordAdCategories { get; set; } } 

然后:

 private static char[] keywordPartsSplitter = new char[] { ' ', '-' }; internal static Dictionary>> FromStringInput(string searchPhrase, SearchDomain searchDomain) { var identifiedKeywords = searchPhrase .Split(keywordPartsSplitter); var knownKeywordParts = identifiedKeywords .Where (ik => searchDomain .Keywords .SelectMany(x => x.GetKeywordParts()) .Any(kp => kp.Equals(ik, StringComparison.InvariantCultureIgnoreCase)) ); var keywordkSearches = knownKeywordParts .Select((kkp, n) => new KeywordSearch() { Id = n, Name = kkp, Keyword = searchDomain .Keywords .Single (k => k.GetKeywordParts() .Any(kp => kp.Equals(kkp, StringComparison.InvariantCultureIgnoreCase)) ) }); var relevantKeywords = keywordkSearches .Select(ks => ks.Keyword) .Distinct(); var keywordAdCategoriesByCategory = searchDomain.Categories .GroupJoin ( searchDomain.KeywordAdCategories, c => c.Id, kac => kac.Category_Id, (c, kac) => new { Category = c, AdKeywordsForCategory = kac } ); var relevantKeywordAdCategories = keywordAdCategoriesByCategory .Where (kacbk => relevantKeywords .All (rk => kacbk .AdKeywordsForCategory .Any(kac => kac.Keyword_Id == rk.Id) ) ); var foundAdsInCategories = relevantKeywordAdCategories .ToDictionary (rkac => rkac.Category, rkac => rkac.AdKeywordsForCategory .GroupBy(g => g.Ad_Id) .ToDictionary(x => x.Key, x => x.ToList()) ); return foundAdsInCategories; } 

它完全符合您的要求但是我发现关键字可以被子关键字整除的可疑之处。 再说一次,也许只是命名。