我有一个单词表,一个查找表,其中显示了在文档中找到这些单词的位置,以及该单词在该文档中出现的次数。因此,可能有一条记录表明Alpha在文档X中存在5次,而Beta在文档X中存在3次,而另一种在文档Y中存在两次Beta。
用户可以输入多个单词进行搜索,因此“快速棕色狐狸”是三个查询,但“快速棕色狐狸跳跃”是四个查询。虽然我可以依次得到每个单词的得分结果集,但我真正想要的是为每个单词添加出现次数,这样最高的结果就是所有单词的最高出现次数。
文档可能有数百个“快速”和“棕色”事件,但没有“狐狸”出现。结果应该仍然包括在内,因为它的分数可能高于只有“快速”,“棕色”和“狐狸”各一个的文档。
我无法解决的问题是如何将1到N个查询与出现的总和合并。我认为我需要使用GROUP BY和SUM()但不确定。 Linq首选但SQL可以。 MS SQL 2016。
我想将结果传递给页面索引器,因此结果上的for-each不起作用,而且我们正在讨论80,000个单词记录,300万个文档单词记录和100,000个文档记录。
// TextIndexDocument:
// Id | WordId | Occurences | DocumentId | (more)
//
// TextIndexWord:
// Id | Word
foreach (string word in words)
{
string lword = word.ToLowerInvariant();
var results = from docTable in db.TextIndexDocuments
join wordTable in db.TextIndexWords on docTable.WordId equals wordTable.Id
where wordTable.Word == lword
orderby docTable.Occurences descending
select docTable;
// (incomplete)
}
更多信息
我知道建议使用全文搜索。那么问题是如何将来自六个不相关的表(在论坛帖子,文章,产品......中搜索)的结果排序到一个统一的结果集中 - 让我们说记录ID,记录类型(文章/产品/论坛),以及得分了。最好的结果可能是一个论坛帖子,而下一个最好的点击是几篇文章,然后是产品,然后是另一个论坛帖子等等。 TextIndexDocument表已在所有相关表中包含此信息。
答案 0 :(得分:1)
据我所知,这不能,或者至少很容易在LINQ中完成,特别是以任何一种高效的方式。
假设您的DBA允许,您应该考虑的是Full-Text索引存储在SQL Server中的文档。根据我的理解,RANK运算符正是您正在寻找的,已针对全文进行了高度优化。
回应你的评论:(抱歉没有注意到)
您需要执行一系列子查询或Common-Table-Expressions。 CTE一开始有点难以习惯写作,但是一旦习惯了它们,它们就比用子查询编写的相应查询要优雅得多。无论哪种方式,查询执行计划都将完全相同,因此从CTE路线获得的性能不会提高。
答案 1 :(得分:1)
假设您可以在TextIndexDocuments
中创建导航属性Document
:
public virtual ICollection<TextIndexDocuments> TextIndexDocuments{ get; set; }
以及TextIndexDocument
中的导航属性:
public virtual TextIndexWord TextIndexWord { get; set; }
(强烈推荐)
然后您可以使用属性来获得所需的结果:
var results =
(
from doc in db.Documents
select new
{
doc,
TotalOccurrences =
doc.TextIndexDocuments
.Where(tid => lwords.Contains(tid.TextIndexWord.Word))
.Sum(doc => doc.Occurrences)
}
).OrderByDescending(x => x.TotalOccurrences)
答案 2 :(得分:0)
您想要为每个文档的单词添加出现次数。因此,按文档ID分组,使用SUM
并按总降序排序:
select documentid, sum(occurences)
from doctable
where wordid in (select id from wordtable where word in 'quick', 'brown', 'fox')
group by documentid
order by sum(occurences) desc;