根据一组关键字进行搜索

时间:2013-11-05 18:30:15

标签: c# asp.net-mvc linq entity-framework

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

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

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”
  • KeywordSearch:关键词“梅赛德斯 - 奔驰”的“梅赛德斯”和“奔驰”               关键字“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为“梅赛德斯 - 奔驰”

任何帮助?

6 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

我想我现在有一个解决方案。这是基于您的previous question和一些假设:

  1. 关键字是完整的名称,如“梅赛德斯 - 奔驰GLK”,“梅赛德斯 - 奔驰Citan”。
  2. 关键词搜索是“Mercedes”,“Benz”和“GLK”代表“Mercedes-Benz GLK”和“Mercedes”,“Benz”和“Citan”代表“Mercedes-Benz Citan”
  3. “梅赛德斯 - 奔驰GLK”是“汽车”,“梅赛德斯 - 奔驰Citan”是“卡车”
  4. 考虑到这三个假设我可以说

    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。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

这是最重要的摘录。


使用:

internal class SearchDomain
{
  public List<Keyword> Keywords { get; set; }
  public List<Category> Categories { get; set; }
  public List<KeywordAdCategory> KeywordAdCategories { get; set; }
}

然后:

private static char[] keywordPartsSplitter = new char[] { ' ', '-' };

internal static Dictionary<Category, Dictionary<int, List<KeywordAdCategory>>> 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;
}

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