【问题标题】:How to use LINQ to SQL to create ranked search results?如何使用 LINQ to SQL 创建排名搜索结果?
【发布时间】:2011-01-03 16:01:12
【问题描述】:

我正在寻找一种使用 l2s 根据关键字返回排名结果的方法。

我想要一个关键字,并能够使用.contains() 在表格中搜索该关键字。我无法弄清楚的技巧是如何计算 keyqord 出现的次数,然后根据该计数计算.OrderByDescending()

所以如果我有类似的东西:

string keyword = "SomeKeyword";

IQueryable<Article> searchResults = from a in GenesisRepository.Article
                                    where a.Body.Contains(keyword)
                                    select a;

根据keyworda.Body 中出现的次数,订购searchResults 的最佳方式是什么?

感谢您的帮助。

【问题讨论】:

  • 这似乎不能用 .Split() 和 Regex 完成,因为它们在 LINQ to SQL 中不存在。仍在寻找解决方案...

标签: c# linq-to-sql search full-text-search


【解决方案1】:

尝试插入order by a.Body.Split(' ').Count(w=&gt;w == keyword)。这应该让你看到这个概念是有效的。但是,我强烈建议最终版本将此作为选择投影的一部分,可能使用键值对,并按属性名称排序:

string keyword = "SomeKeyword";

//EDIT: restructured query to force the ordering to be done on the projection, 
//not the source.
IQueryable<Article> searchResults = (from a in GenesisRepository.Article
                                    where a.Body.Contains(keyword)
                                    select new KeyValuePair<int, Article>(
                                       a.Body.Split(' ').Count(w=>w == keyword), a))
                                    .OrderBy(kvp=>kvp.Key);

原因是性能; Split().Count() 方法链是线性复杂度的,每次比较两个值时都会进行评估,使得整体排序复杂度为 N^2logN(慢)。

编辑:另外,请了解 a.Body.Contains(keyword) 不会按整个单词搜索,因此将返回包含“SomeKeywordLongerThanSearch”和“ThisIsSomeKeyword”以及“SomeKeyword”的文章。您可以通过模式“\bSomeKeyword\b”上的正则表达式匹配来避免这种情况,它只会匹配 SomeKeyword 的实例与紧接在之前和之后的单词边界。

【讨论】:

  • 我在KeyValuePairorder by Key 上遇到错误。 Key 在哪里定义?
    Using the generic type 'System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;' requires 2 type arguments
  • 我也意识到我的问题可能存在缺陷。我不认为这会处理多个关键字......即:“这是一个关键字字符串”
  • 为了使排序正常运行,您可能需要将查询的 from、where 和 select 子句括在一组括号中;这将强制编译器首先评估该部分,然后排序,而不是将 Order By 放在它认为性能最高的地方。然后,将new KeyValuePair 替换为new KeyValuePair&lt;int, Article&gt; 或任何a 的类型。我曾认为构造函数可以像泛型方法一样推断类型;我错了。
  • 它现在可以编译,但由于某种原因,当我运行查询然后在 KVP 上尝试 foreach 时,它会失败。当我在searchResults 上设置断点时,我深入研究并发现:{“类型'System.String[]'不支持比较运算符。”}
  • 稍微研究了一下...显然 .Split() 在 linqTOsql 中不受支持 (stackoverflow.com/questions/1211942/…)
【解决方案2】:

这是我想出的一个小技巧,非常简单,但绝对不是“最佳实践”。

IQueryable<Article> searchResults = from a in GenesisRepository.Article
                       where a.Body.Contains(keyword)
                       orderby a.Body.Split(new string[] { keyword }, StringSplitOptions.RemoveEmptyEntries).Count() descending
                       select a;

【讨论】:

  • 方法 'System.String[] Split(System.String[], System.StringSplitOptions)' 没有支持的 SQL 转换。
  • 通过此处提供的解决方案,我得出的结论是您需要制作一个sql server函数或将整个表带回客户端然后执行orderby。去功能或存储过程。
  • 是的...这有点像我想的。太糟糕了。我讨厌需要获取整个结果集,然后使用函数对其执行子查询,如果需要分页,我将不得不这样做。是时候和 sql 程序员谈谈了 :-)
【解决方案3】:

也许这会起作用......

IQueryable<Article> searchResults = from a in GenesisRepository.Article
                                        where a.Body.Contains(keyword)
                                        select a;

searchResults.OrderByDescending(s => Regex.Matches(a.Body, keyword).Count);

【讨论】:

  • 抛出此错误:Method 'System.Text.RegularExpressions.MatchCollection Matches(System.String, System.String)' has no supported translation to SQL.
  • 对,我将排序从 linq 移到 sql 调用。立即尝试。
猜你喜欢
  • 2010-10-22
  • 2011-02-17
  • 2015-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多