12

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

在 KeywordSearch 表中进行搜索:

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”
  • 关键字搜索:“Mercedes”和“Benz”为关键字“Mercedes-Benz” “GLK”为关键字“GLK”
  • 类别:“汽车”和“卡车”
  • 广告:汽车 - 梅赛德斯-奔驰 GLK 卡车 - 梅赛德斯-奔驰 Citan

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

    • 汽车:1
    • 卡车:1

    如果我搜索“梅赛德斯-奔驰 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”,“where d.Count() == splitKeywords.Count()”行会失败,因为 d.count = 1 和 splitkeywords.Count = 2 for "奔驰”

有什么帮助吗?

4

7 回答 7

2

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

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因此它不再参与搜索

于 2013-11-12T07:49:37.137 回答
1

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

于 2013-11-14T18:28:18.657 回答
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;
}

它完全符合您的要求,但是我发现关键字可被子关键字整除的问题有些可疑。再一次,也许这只是命名。

于 2013-12-15T21:07:48.087 回答
0

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

  1. 关键字是完整的名称,例如“Mercedes-Benz GLK”、“Mercedes-Benz Citan”。
  2. “Mercedes-Benz GLK”和“Mercedes”的关键字搜索是“Mercedes”、“Benz”和“GLK”、“Mercedes-Benz Citan”的“Benz”和“Citan”
  3. “Mercedes-Benz GLK”是“Car”,“Mercedes-Benz Citan”是“Truck”

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

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”。
我认为很明显,您不希望“Mercedes-Benz GLK”与“Mercedes-Benz Citan”匹配。

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

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。

于 2013-11-07T14:13:30.500 回答
0

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

于 2013-11-29T09:55:27.543 回答
0

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

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

您实际上是在说,“以 开头keywordAdCategoryQuery,并为每个关键字添加一个.Where()条件,说明其中必须包含该关键字。如果您发现难以阅读,您可以使用for循环执行相同的操作。Aggregate

于 2013-11-05T18:36:29.783 回答
0

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

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

于 2013-11-16T05:38:41.653 回答