NHibernate + SqlServer全文搜索

时间:2011-11-10 07:20:47

标签: c# sql-server nhibernate full-text-search lucene.net

我必须在NHibernate中进行全文搜索

以前的操作以前我使用的是Lucene.Net

我有一张名为候选人的表

对于全文查询,Lucene将从lucene索引返回所有候选Id并形成我在候选中查询的id并返回结果

但问题是有超过10个候选简历可用,因此Lucene非常慢,因为10 Lk行的过滤值并且在查询中将返回值放入候选者并再次过滤候选者需要花费太多时间

此外,我有一个寻呼标准,每个页面我都会返回100个候选人

现在我添加了新表candidate_full_text 在该表中,我在sqlserver 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进行单一查询时,我必须做的事情 而candidate_full_text索引的关键列是候选表id。 在这里我给出了表格模型 1)候选人(Min字段)

Id - int,

名称 - varchar,

Dob - datetime,

2)candidate_full_text

id - int,

candidate_resume_full_text -ntext,(已配置的全文索引)

candidate_id - int

1 个答案:

答案 0 :(得分:2)

如果您能够使用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#app中填写参数并使用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中不可用,但我认为还有其他解决方法可以进行分页(例如参见this article)。 (或者您可能希望将SQL Server升级到2008,它在运行中运行FTS并且具有更好的性能!)

我认为这些方面的解决方案将满足您的需求。