【问题标题】:SQL Server 2005 Full Text Search over multiple tables and columnsSQL Server 2005 对多个表和列的全文搜索
【发布时间】:2010-01-13 15:53:09
【问题描述】:

我正在寻找一个好的解决方案来有效地使用 SQL Serve r2005 的 containstable 功能。目前我有,例如一个 Employee 和一个 Address 表。

-Employee
Id
Name

-Address
Id
Street
City
EmployeeId

现在用户只能在一个文本框中输入搜索词,我希望将这些词拆分并使用“AND”运算符进行搜索。 FREETEXTTABLE 似乎可以自动使用“OR”。

现在假设用户输入了“John Hamburg”。这意味着他想在汉堡找到约翰。 所以这是“约翰和汉堡”。

因此以下内容将不包含任何结果,因为 CONTAINSTABLE 会检查每一列中的“John AND Hamburg”。

所以我的问题是:使用 AND 运算符跨多个列/表执行全文搜索的最佳方法是什么?

SELECT *
FROM Employee emp
    INNER JOIN 
        CONTAINSTABLE(Employee, *, '(JOHN  AND Hamburg)', 1000) AS keyTblSp
        ON sp.ServiceProviderId = keyTblSp.[KEY]    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
UNION ALL
SELECT *
FROM Employee emp 
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
    INNER JOIN 
        CONTAINSTABLE([Address], *, '(JOHN  AND Hamburg)', 1000) AS keyTblAddr
        ON addr.AddressId = keyTblAddr.[KEY]    

...

【问题讨论】:

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


    【解决方案1】:

    这更像是一个语法问题。你如何通过一个输入框来判断用户的意图?

    • 他们在寻找“John Hamburg”这个人吗?
    • 他们在寻找“约翰汉堡街”吗?
    • 他们在寻找住在斯普林菲尔德“汉堡街”的“约翰”吗?
    • 他们在寻找住在“汉堡”市的“约翰”吗?

    在不知道用户意图的情况下,你能期望的最好结果就是对条款进行 OR,并获得最高排名的点击。

    否则,您需要编写大量逻辑,具体取决于传入的字数:

    2 个字:

    搜索术语 1 的员工数据,搜索术语 2 的员工数据,搜索术语 1 的地址数据,搜索术语 2 的地址数据。按术语合并结果,按点击次数最多排序。

    三个字:

    搜索术语 1 的员工数据,搜索术语 2 的员工数据,搜索术语 3 的员工数据,搜索术语 1 的地址数据,搜索术语 2 的地址数据,搜索术语 3 的地址数据。按术语合并结果,按点击次数排序。

    等等……

    我想我会重新设计 GUI,至少将输入分成名称和地址。如果这不可能,请强制执行语法规则,“在出现逗号之前,第一个单词将被视为名称,之后的任何单词都将被视为地址”

    编辑:

    您最好的选择仍然是 OR 条款,并获得最高排名的命中。这是一个示例,以及一个示例为什么如果不对输入进行一些预处理以判断用户的意图,这是不理想的:

    insert into Employee (id, [name]) values (1, 'John Hamburg')
    insert into Employee (id, [name]) values (2, 'John Smith')
    insert into Employee (id, [name]) values (3, 'Bob Hamburg')
    insert into Employee (id, [name]) values (4, 'Bob Smith')
    insert into Employee (id, [name]) values (5, 'John Doe')
    
    insert into Address (id, street, city, employeeid) values (1, 'Main St.', 'Springville', 1)
    insert into Address (id, street, city, employeeid) values (2, 'Hamburg St.', 'Springville', 2)
    insert into Address (id, street, city, employeeid) values (3, 'St. John Ave.', 'Springville', 3)
    insert into Address (id, street, city, employeeid) values (4, '5th Ave.', 'Hamburg', 4)
    insert into Address (id, street, city, employeeid) values (5, 'Oak Lane', 'Hamburg', 5)
    

    现在,由于我们不知道哪些关键字将应用于哪个表,因此我们必须假设它们可以应用于任何一个表,因此我们必须对每个表进行 OR 运算,将结果合并,聚合它们,然后计算最高等级。

    SELECT Id, [Name], Street, City, SUM([Rank])
    FROM
    (
        SELECT emp.Id, [Name], Street, City, [Rank]
        FROM Employee emp 
        JOIN [Address] addr ON emp.Id = addr.EmployeeId
        JOIN CONTAINSTABLE(Employee, *, 'JOHN OR Hamburg') AS keyTblEmp ON emp.Id = keyTblEmp.[KEY]
    
        UNION ALL
    
        SELECT emp.Id, [Name], Street, City, [Rank]
        FROM Employee emp 
        JOIN [Address] addr ON emp.Id = addr.EmployeeId
        JOIN CONTAINSTABLE([Address], *, 'JOHN OR Hamburg') AS keyTblAdd ON addr.Id = keyTblAdd.[KEY]   
    ) as tmp
    
    GROUP BY Id, [Name], Street, City
    ORDER BY SUM([Rank]) DESC
    

    这不太理想,这就是你得到的例子(在你的例子中,你会希望来自汉堡的 John Doe 首先出现):

    Id       Name              Street            City           Rank
    2        John Smith        Hamburg St.       Springville    112
    3        Bob Hamburg       St. John Ave.     Springville    112
    5        John Doe          Oak Lane          Hamburg        96
    1        John Hamburg      Main St.          Springville    48
    4        Bob Smith         5th Ave.          Hamburg        48
    

    但在将输入提交给 SQL 以对用户想要的内容做出“最佳猜测”之前,您可以在不解析输入的情况下做到这一点。

    【讨论】:

    • 感谢您的回复。我想保留一个输入框,因为用户应该很容易像在 Google 中那样快速搜索一些东西。如果用户搜索 John Hamburg,他希望得到 John 的结果,例如住在 Hamburg 的 John,他的姓可能是 Hamburg,也可能住在 Hamburg,但是对于不住在 Hamburg 的 Just John 没有结果。或者住在汉堡的其他人。问题是,稍后将可以搜索更多信息,例如电子邮件等。所以我需要一个包含所有数据的包含表,其中包含由 AND 连接的术语。
    • 回到语法。如果您不知道输入关键字应应用于哪个表和列,则无法在没有大量逻辑编程的情况下创建“一刀切”的 AND 语句。在上述情况下,您如何知道将第一个关键字搜索为 [Name],将第二个关键字搜索为 [City]?如果用户希望第二个关键字成为名称的一部分或街道的一部分怎么办?除非你有一些你没有提到的语法规则,比如“第一个词是名字,第二个词是城市”?
    • @Chris 每当我看到 like in Google 这个短语时,我的反应总是一样的:如果创建 like in Google 逻辑很容易在 stackoverflow 上回答,他们就不会雇佣成千上万的高薪开发人员.不要指望能够在几天内复制这种质量。
    • @ean5533 我知道,我不想创建第二个 Google。我提到谷歌只是为了强调,我需要一种技术解决方案来搜索存储在关系模型中的大量数据,只需一个文本框。
    【解决方案2】:

    我遇到了同样的问题。这是我的解决方案,适用于我的情况:

    我创建了一个返回我想要的列的视图。我添加了另一个额外的列,它聚合了我想要搜索的所有列。所以,在这种情况下,视图会是这样的

    SELECT emp.*, addr.*, ISNULL(emp.Name,'') + ' ' + ISNULL(addr.City, '') AS SearchResult 
    FROM Employee emp 
        LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
    

    在此之后,我在 SearchResult 列上创建了一个全文索引。然后,我在这个专栏上搜索

    SELECT *
    FROM vEmpAddr ea
    INNER JOIN CONTAINSTABLE(vEmpAddr, *, 'John AND Hamburg') a ON ea.ID = a.[Key]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-06
      相关资源
      最近更新 更多