NHibernate + SqlServer полнотекстовый поиск - PullRequest
5 голосов
/ 10 ноября 2011

Мне нужно выполнить полнотекстовый поиск в NHibernate

. Для выполнения следующей операции ранее я использую Lucene.Net

. У меня есть таблица кандидатов

Для полнотекстового запроса.Lucene вернет все идентификаторы кандидатов из индекса Lucene и сформирует этот идентификатор, который я вставил в запрос в кандидате, и вернет результат

Но проблема в том, что доступно более 10 Отсутствует резюме кандидатов, поэтому Lucene работает очень медленно, потому что фильтрзначение из строки 10 Lk и поместите возвращаемое значение в запросе к кандидату, и снова фильтр кандидата занимает слишком много времени

Также у меня есть критерии подкачки и для каждой страницы я возвращаю 100 кандидатов

сейчася добавил новую таблицу кандидат_full_text в эту таблицу, я настроил полнотекстовый индекс в SQL Server 2000, теперь я хочу запросить с помощью NHibernate DetachedCriteria следующим образом

1) Select candidate with some filters

2) Execute the function ContainsTable for candidate_full_text table 
 (which returns candidate tables id as key and rank of occurrence of the search string)

3) join the result from 1 & 2

4) Apply paging criteria (ie return 1st 100,2nd 100,3rd 100.. etc) according to page no

5) return the result by order of rank column (which is return by ContainsTable)

Следующие вещи, которые я должен сделать в одном запросе с DetachedCriteria и ключевой столбецдля index_full_text указывается идентификатор таблицы кандидатов. Здесь igiven таблицы моделей 1) кандидат (поля Min)

Id - int,

Имя - varchar,

Dob - datetime,

2 )андидат_full_text

id - int,

андидат_resume_full_text -ntext, (настроенный полнотекстовый индекс)

андидат_ид - int

1 Ответ

2 голосов
/ 28 апреля 2012

Если вы можете использовать SQL Server FTS вместо Lucene и производительность является приемлемой, вы можете воспользоваться возможностью выполнять реляционные объединения между результатами SQL Server FTS и другими реляционными данными в вашей базе данных. Чтобы выполнить эти объединения, вы должны использовать функцию CONTAINSTABLE вместо предиката CONTAINS.

Используя ваш пример, давайте настроим следующие таблицы в SQL Server:

create table Candidate
( 
Id int primary key,
Name varchar(50),
Dob  datetime
)

create table Candidate_Full_Text
(
id int primary key,
candidate_resume_full_text ntext, -- FTS column
candidate_id int foreign key references Candidate(Id)
)

Затем вы можете создать параметризованный именованный запрос в nHibernate следующим образом:

<sql-query name="CandidateSearch">
   <![CDATA[
     SELECT TOP (:take) * 
        FROM
            (SELECT c.Id, c.Name, ft.[RANK], ROW_NUMBER() OVER(ORDER BY ft.[RANK] desc) as rownum          
            FROM ContainsTable(Candidate_full_text, candidate_resume_full_text , :phrase, LANGUAGE 1033) ft
                        INNER JOIN Candidate c on ft.[KEY] = c.Id
            WHERE c.Name = :name and c.Dob > :dob
             ) a
        WHERE a.rownum > :skip ORDER BY a.rownum 
  ]]>
</sql-query>

Обратите внимание, как этот запрос реляционно связывает результаты функции CONTAINSTABLE с другой таблицей в вашей базе данных. Используя SQL FTS, легко объединить результаты FTS со сложными реляционными запросами по другим данным в вашей БД. Эта возможность является одним из ключевых преимуществ использования SQL Server FTS по сравнению с Lucene и может стать причиной выбора его вместо Lucene, несмотря на его более низкую общую производительность.

Наконец, вы можете заполнить ваши параметры в приложении C # и выполнить запрос с помощью объекта nHibernate ISession:

        int take = 5;
        int skip = 10;
        string phrase = "(team NEAR player) OR (teamwork NEAR coopertive)";
        string name = "John Doe";
        DateTime dob = new DateTime(1963, 7, 1);

        var results = _session.GetNamedQuery("ExpandedSearchTerm")
                              .SetString("phrase", phrase)
                              .SetDateTime("dob", dob)
                              .SetString("phrase", phrase)
                              .SetInt32("take", take)
                              .SetInt32("skip", skip)
                              .List();

Функция ROWNUMBER () недоступна в SQL Server 2000, который вы используете, но я думаю, что существуют другие способы обхода страниц (см., Например, эту статью ). (Или, возможно, вы захотите обновить SQL Server до 2008 года, который работает в процессе FTS и имеет гораздо лучшую производительность!)

Я думаю, что решение в этом направлении удовлетворит ваши потребности.

...