2017-02-11 4 views
1

У меня есть таблица слов, таблица поиска, где эти слова найдены в документах, и количество раз, когда это слово появляется в этом документе. Таким образом, может быть запись, в которой говорится, что Alpha существует 5 раз в документе X, в то время как Beta существует 3 раза в документе X, а другой для бета-версии, существующей дважды в документе Y.Слияние запросов одной таблицы N раз

Пользователь может ввести несколько слов для поиска, так что «быстрая коричневая лиса» - это три вопроса, но «быстрый коричневый лис прыгнул» - это четыре вопроса. В то время как я могу получить результат набора результатов каждого слова по очереди, то, что я на самом деле хочу, состоит в том, чтобы добавить количество совпадений для каждого слова, так что верхний результат является наивысшим количеством встречаемости для всех слов.

Документ может иметь сотни «быстрых» и «коричневых» вхождений, но никаких «лис» не происходит. Результаты должны по-прежнему включаться, так как они могут набирать больше, чем документ, только с одним из «быстрых», «коричневых» и «лис».

Проблема, с которой я не могу разобраться, заключается в том, как объединить 1 к N запросам с суммами, суммированными. I думаю Мне нужно использовать GROUP BY и SUM(), но не обязательно. Linq предпочтет, но SQL будет в порядке. MS SQL 2016.

Я хочу передать результаты на индексный указатель, поэтому для каждого из результатов не будет работать, плюс мы говорим о 80 000 записей слов, 3 миллионах записей в документах и ​​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) 
} 

Более подробная информация

Я понимаю, что полный текст поиска рекомендуется. Проблема заключается в том, как ранжировать результаты из полудюжины несвязанных таблиц (поиск в сообщениях, статьях, продуктах ...) в один унифицированный набор результатов - скажем, идентификатор записи, тип записи (статья/продукт/форум) и Гол. Главным результатом может стать сообщение на форуме, в то время как следующие лучшие хиты - это несколько статей, затем продукт, другой форум и т. Д. Таблица TextIndexDocument уже имеет эту информацию во всех соответствующих таблицах.

+0

Вы описываете полнотекстовый индекс. –

ответ

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) 
+0

Спасибо - похоже, что он должен выполнять эту работу. Однако в настоящее время я пытаюсь установить tiw.Occurrences, поскольку это поле находится в таблице TextIndexDocuments, а не в таблице TextIndexWord. – GeoffM

+0

Ah, .Sum (tiw => docTable.Occurences) – GeoffM

+0

Хм, не уверен. Вам действительно нужны суммы за «Документ». Весь запрос должен быть поднят на один уровень вверх. –

1

Насколько я знаю, это невозможно или, по крайней мере, легко, выполнить в LINQ, особенно в любом виде.

Что вы действительно должны учитывать, предполагая, что ваш DBA позволит это, это Full-Text индексация ваших документов, хранящихся на SQL Server. По моему мнению, оператор RANK - это именно то, что вы ищете, которое было оптимизировано для полнотекстового поиска.

В ответ на ваш комментарий: (извините за не замечая, что)

Вам нужно либо сделать серию подзапросов или Common-Table-Expressions. CTE немного сложно привыкнуть к написанию вначале, но как только вы привыкнете к ним, они намного более элегантны, чем соответствующий запрос, написанный с подзапросами. В любом случае план выполнения запросов будет таким же, так что при переходе по маршруту CTE не будет повышения производительности.

+0

Оцените, хотя я думаю, что в итоге я столкнулся с той же проблемой, что и документы, на самом деле ссылающиеся на несколько других несвязанных таблиц (сообщения на форуме, статьи, страницы продуктов и т. Д.). Другими словами, я мог бы выполнять полный текстовый поиск на сообщениях на форуме, другой по статьям и т. Д., Но все же нужно объединить результаты в один значимый список, занимающий место по количеству обращений. – GeoffM

+0

Я обновил свой ответ с дальнейшими подсказками, извините, я не кормлю ложкой, но у меня даже нет SSMS или SQL Server, установленных на моем ящике прямо сейчас –

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; 
Смежные вопросы