使用containstable和freetext进行相关度排名的搜索

1 人关注

我读到过,在SQL 2008服务器下,你可以使用containstable以及contain和freetext对搜索结果进行排名。我最近才第一次使用freetext。freetext可以单独循环浏览单词,并与索引列进行比较。我希望能够先搜索短语,然后再搜索单字。

比方说,描述列是有索引的。我正在使用这样的存储过程查询。

SELECT id, description, item from table where (FREETEXT(description,@strsearch))

例如,如果有3个行集包含有苹果的单词,我搜索 "苹果蛋糕",那么id2的行集应该在前面,然后其他两个行集应该在后面。

id1 apple pie 4/01/2012
id2 apple cake 2/29/2011
id3 candy apple 5/9/2011

例如,如果有4个行集包含有食物的词,我搜索 "快餐店",有id3的行集应该是第一个,其次是id1(不是完全匹配,但因为它的列中有 "快餐"),然后是其他两个行集。

id1 McDonalds fast food
id2 healthy food
id3 fast food restaurant
id4 Italian restaurant
sql-server-2008
stored-procedures
full-text-search
Patriotec
Patriotec
发布于 2012-04-29
1 个回答
Aaron Bertrand
Aaron Bertrand
发布于 2012-04-29
已采纳
0 人赞同

这篇文章有帮助吗?

MSDN:限制排名结果集(全文搜索)

这在某种程度上意味着,使用一个额外的参数将允许你把结果限制在相关性最大的那些(你可以用 WEIGHT 来影响),并且还可以按照这种相关性来排序 RANK )。

top_n_by_rank是一个整数值,n,它指定只返回n个排名最高的 排名最高的匹配结果,按降序返回。

文档中没有 FREETEXT 的例子,它只提到了 CONTAINSTABLE 。但它肯定暗示 CONTAINSTABLE 输出一个 RANK 列,你可以用它来 ORDER BY

我不知道是否有任何方法可以强制执行你自己的相关性定义。根据FTS拉出前10个相关的匹配,然后在输出结果上应用你自己的排名,这可能是有意义的,例如,你可以使用一个函数来分割搜索词,并根据匹配的单词数量来排序。为了简单起见,在下面的例子中,我没有在子查询中使用Full-Text,但你可以用你实际要做的任何事情来代替它。首先创建这个函数。

IF OBJECT_ID('dbo.SplitStrings') IS NOT NULL
DROP FUNCTION dbo.SplitStrings;
CREATE FUNCTION dbo.SplitStrings(@List NVARCHAR(MAX))
RETURNS TABLE
RETURN ( SELECT Item FROM
       ( SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)')
         FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(@List, ' ', '</i><i>') + '</i>').query('.')
           ) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
       WHERE Item IS NOT NULL

然后是一个简单的脚本,显示如何进行匹配。

DECLARE @foo TABLE
    id INT,
    [description] NVARCHAR(450)
INSERT @foo VALUES
(1,N'McDonalds fast food'),
(2,N'healthy food'),
(3,N'fast food restaurant'),
(4,N'Italian restaurant'),
(5,N'Spike''s Junkyard Dogs');
DECLARE @searchstring NVARCHAR(255) = N'fast food restaurant';
SELECT x.id, x.[description]--, MatchCount = COUNT(s.Item)
    SELECT f.id, f.[description]
    FROM @foo AS f
    -- pretend this actually does full-text search:
--where (FREETEXT(description,@strsearch))
-- and ignore how I actually matched:    
INNER JOIN dbo.SplitStrings(@searchstring) AS s
    ON CHARINDEX(s.Item, f.[description]) > 0
GROUP BY f.id, f.[description] 
) AS x
INNER JOIN dbo.SplitStrings(@searchstring) AS s
ON CHARINDEX(s.Item, x.[description]) > 0
GROUP BY x.id, x.[description]
ORDER BY COUNT(s.Item) DESC, [description];
id description
-- -----------