Вот то, что я придумал:
var query =
from a in q
from w in Words
let title = a.Title.ToLower()
let body = a.Body.ToLower()
let replTitle = Regex.Replace(title, string.Format("\\b{0}\\b", w), string.Empty)
let replBody = Regex.Replace(body, string.Format("\\b{0}\\b", w), string.Empty)
let titleOccurences = (title.Length - replTitle.Length) / w.Length
let bodyOccurences = (body.Length - replBody.Length) / w.Length
let score = titleOccurences * 5 + bodyOccurences
where score > 0
select new { Article = a, Score = score };
var results = query.GroupBy(r => r.Article)
.OrderByDescending(g => g.Sum(r => r.Score))
.Take(Settings.ArticlesPerPage);
Подсчет вхождений выполняется с (удивительно) быстрым и грязным методом замены вхождений на string.Empty
и вычисления на основе полученной длины строки.После того, как баллы за каждую статью и каждое слово рассчитаны, я группирую для каждой статьи, упорядочив по сумме баллов за все слова и вычеркивая часть из результатов.
Я не стрелялдо компилятора, поэтому, пожалуйста, извините за любые очевидные ошибки.
Обновление: Эта версия использует регулярные выражения, как в
Regex.Replace(title, string.Format("\\b{0}\\b", w), string.Empty)
вместо
* 1015 оригинальной версии*
, чтобы теперь он соответствовал только целым словам (версия string.Replace
также будет соответствовать фрагментам слов).