SQL Server全文搜索 - 创建一个计算列

时间:2010-01-14 10:54:05

标签: sql-server-2005 tsql full-text-search

我目前正在开展一个项目,我想通过一个输入搜索词来搜索员工。为此我使用的是SQL FTS。

表架构看起来像这样

员工表

EmployeeId,名字,姓氏

示例数据

1,John,Miller

2,查克,诺里斯


地址表

AddressId,EmployeeId,CityId,Street,StreetNumber

示例数据

1,1,1,Avenue,12

2,2,2,Wimbledon Rd,12


城市表

CityId,Name,ZipCode

示例数据

1,汉堡,22335

2,伦敦,12345


所以现在我得到了以下搜索词:

  • John Hamburg:意味着John AND Hamburg并且应该返回1条记录。
  • 约翰伦敦:意味着约翰和伦敦,因为在伦敦没有约翰,所以应该返回0条记录。
  • Norris Wimbledon:意味着Norris和Wimbledone并且应该返回1条记录。

现在问题在于,使用CONTAINSTABLE只允许一次搜索一个表。因此,在“雇员全文”目录上应用“John AND Hamburg”会返回0条记录,因为“Hamburg”位于地址表中。

所以目前我只能使用“OR”代替“AND”,例如:

SELECT
   (keyTblSp.RANK * 3) AS [Rank],
    sp.*
FROM Employee sp    
    INNER JOIN 
        CONTAINSTABLE(Employee, *, 'John OR Hamburg', 1000) AS keyTblSp
        ON sp.EmployeeId = keyTblSp.[KEY]    

UNION ALL
SELECT
   (keyTbl.RANK * 2) AS [Rank],
    sp.*
FROM Employee sp    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId 
    INNER JOIN 
        CONTAINSTABLE([Address], *, 'John OR Hamburg', 1000) AS keyTbl
        ON addr.AddressId = keyTbl.[KEY]    
UNION ALL
SELECT
   (keyTbl.RANK * 2) AS [Rank],
    sp.*
FROM Employee sp    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId 
    LEFT OUTER JOIN [City] cty ON cty.CityId = addr.CityId
    INNER JOIN 
        CONTAINSTABLE([City], *, 'John OR Hamburg', 1000) AS keyTbl
        ON cty.CityId = keyTbl.[KEY]  

这导致不仅生活在汉堡的约翰被归还,而且每个人都叫约翰和每个住在汉堡的人。 我能想到的一个解决方案是以某种方式计算Employee Table中的一列,该列包含全文搜索的所有必要值,如。

员工表

EmployeeId,名字,姓氏, FulltextColumn

示例数据

1 |约翰|米勒| John Miller Avenue 12 Hamburg 22335

那么我就可以做到

SELECT
   (keyTbl.RANK) AS [Rank],
    sp.*
FROM Employee sp    
    INNER JOIN 
        CONTAINSTABLE([Employee], FulltextColumn, 'John AND Hamburg', 1000) AS keyTbl
        ON sp.EmployeeId = keyTbl.[KEY] 

这可能吗?还有其他想法吗?

3 个答案:

答案 0 :(得分:1)

您可以使用联接来要求地址和人名匹配。

SELECT
   (keyTblSp.RANK * 3) AS [Rank],
    sp.*
FROM Employee sp    
    INNER JOIN 
        CONTAINSTABLE(Employee, *, 'John OR Hamburg', 1000) AS keyTblSp
        ON sp.EmployeeId = keyTblSp.[KEY]    
join
(
    SELECT
       (keyTbl.RANK * 2) AS [Rank],
        sp.*
    FROM Employee sp    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId 
    INNER JOIN 
        CONTAINSTABLE([Address], *, 'John OR Hamburg', 1000) AS keyTbl
        ON addr.AddressId = keyTbl.[KEY]
UNION ALL
    SELECT
       (keyTbl.RANK * 2) AS [Rank],
        sp.*
    FROM Employee sp    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = sp.EmployeeId 
    LEFT OUTER JOIN [City] cty ON cty.CityId = addr.CityId
    INNER JOIN 
        CONTAINSTABLE([City], *, 'John OR Hamburg', 1000) AS keyTbl
        ON cty.CityId = keyTbl.[KEY]  
) addr_matches
on addr_matches.EmployeeId = sp.EmployeeId

我认为这会给你指定的结果,显然,这需要一个名称和一个地址搜索术语来搜索返回任何结果。你没有说明如果有人只是搜索“John”会发生什么,如果你总是得到一个名字和地址,我认为上面的工作会很好。

答案 1 :(得分:0)

我认为计算列是您的最佳选择。它将是最灵活的,因为你不知道搜索查询中会有哪些令牌,它会表现得更好,而你的存储过程会更小。

为了根据另一个表中的数据创建计算列,您必须使用这样的UDF(用户定义函数)创建它:

CREATE FUNCTION dbo.udf_ComputedColumnFunction (
    @EmployeeId INT
)
RETURNS VARCHAR(1000)
AS
BEGIN
    DECLARE @RET VARCHAR(1000)

    SELECT
        @RET = e.FirstName + ' ' + e.LastName + ' ' + a.Street  + ' ' +  a.StreetNumber + ' ' + c.Name + ' ' + c.ZipCode
    FROM Employee e
    INNER JOIN Address a ON a.EmployeeId = e.EmployeeId
    INNER JOIN City c ON c.CityId = a.CityId

    RETURN @RET
END
GO


ALTER TABLE Employee
ADD SearchColumn AS dbo.udf_ComputedColumnFunction(EmployeeId)

如果你不想这样做,你可以:

  • 创建indexed view并在其上添加FullText索引。
  • 创建一个由触发器填充的查找表,或者定期运行存储过程。

答案 2 :(得分:0)

我认为您应该创建并索引视图,并且应该将可以在FullText中使用的所有列连接在一个列中,方法是用空格或短划线将它们分开,因为两者都是sql server 2005的干扰词。然后在索引视图创建全文索引。

包含表格默认情况下不适用FormsOf Inflectional或Thesaurus表格。这两个是配置和使用的好选择。

如果你只想去“OR”,那就使用FreeTextTable,好像默认情况下同时应用同义词库和FormsOf屈折形式。