我需要使用全文搜索在我的数据库中的两个表中搜索多个列。有问题的两个表都有相关的全文索引列。
我选择全文搜索的原因: 1.能够轻松搜索重音词(cafè) 2.能够根据单词接近度等排名 “你的意思是XXX吗?”功能
这是一个虚拟表结构,用于说明挑战:
Table Book BookID Name (Full-text indexed) Notes (Full-text indexed) Table Shelf ShelfID BookID Table ShelfAuthor AuthorID ShelfID Table Author AuthorID Name (Full-text indexed)
我需要搜索图书名称,图书笔记和作者姓名。
我知道有两种方法可以做到这一点:
使用全文索引视图:这可能是我首选的方法,但我不能这样做,因为要查看全文索引,需要模式绑定,没有任何外连接,具有唯一索引。我需要获取数据的视图不满足这些约束(它包含我需要的许多其他连接表来获取数据)。
在存储过程中使用连接:这种方法的问题是我需要按排名排序结果。如果我在表中进行多个连接,则默认情况下SQL Server不会跨多个字段进行搜索。我可以在两个链接表上组合两个单独的CONTAINS查询,但我不知道从两个搜索查询中提取组合排名的方法。例如,如果我搜索“Arthur”,则应考虑Book查询和Author查询的结果并相应地加权。
答案 0 :(得分:15)
使用FREETEXTTABLE,您只需设计一些算法来计算每个连接表结果的合并等级。以下示例将结果与书表中的命中结果进行了对比。
SELECT b.Name, a.Name, bkt.[Rank] + akt.[Rank]/2 AS [Rank]
FROM Book b
INNER JOIN Author a ON b.AuthorID = a.AuthorID
INNER JOIN FREETEXTTABLE(Book, Name, @criteria) bkt ON b.ContentID = bkt.[Key]
LEFT JOIN FREETEXTTABLE(Author, Name, @criteria) akt ON a.AuthorID = akt.[Key]
ORDER BY [Rank] DESC
请注意,我简化了此示例的架构。
答案 1 :(得分:5)
我遇到了和你一样的问题,但它实际上涉及10个表(一个用户表和其他一些用于获取信息的表)
我在每个表的WHERE子句中使用FREETEXT进行了第一次查询,但查询花了太长时间。
然后,我看到了几个关于使用FREETEXTTABLE的回复,并检查每个表的键列中的非空值,但这也需要很长时间才能执行。
我使用FREETEXTTABLE和UNION的组合来修复它:
SELECT Users.* FROM Users INNER JOIN
(SELECT Users.UserId FROM Users INNER JOIN FREETEXTTABLE(Users, (column1, column2), @variableWithSearchTerm) UsersFT ON Users.UserId = UsersFT.key
UNION
SELECT Table1.UserId FROM Table1 INNER JOIN FREETEXTTABLE(Table1, TextColumn, @variableWithSearchTerm) Table1FT ON Table1.UserId = Table1FT.key
UNION
SELECT Table2.UserId FROM Table2 INNER JOIN FREETEXTTABLE(Table2, TextColumn, @variableWithSearchTerm) Table2FT ON Table2.UserId = Table2FT.key
... --same for all tables
) fts ON Users.UserId = fts.UserId
事实证明这要快得多。
我希望它有所帮助。
答案 2 :(得分:3)
我认为接受的答案不会解决问题。如果您尝试查找某位作者的所有书籍,并因此使用作者的姓名(或其中的一部分)作为搜索条件,则查询返回的唯一书籍将是具有自己名称的搜索条件的书籍。
我看到这个问题的唯一方法是复制您希望在Book表中搜索的作者列并索引这些列(或列,因为将作者的相关信息存储在XML列中可能很聪明在书表中。)
答案 3 :(得分:2)
FWIW,在类似的情况下,我们的DBA创建了DML触发器来维护专用的全文搜索表。由于其有许多限制,因此无法使用物化视图。
答案 4 :(得分:1)
我会使用存储过程。全文方法或其他任何返回排序,您可以排序。我不确定他们将如何对抗彼此,但我相信你可能会修补一段时间并弄清楚。例如:
Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, @searchString) as SearchResults Order By SearchResults.rank Desc
答案 5 :(得分:0)
这个答案已经过期,但如果你不能修改主表,一种方法是创建一个新的表,并将搜索参数添加到一列。
然后在该列上创建一个完整的文本索引并查询该列。
示例
SELECT
FT_TBL.[EANHotelID] AS HotelID,
ISNULL(FT_TBL.[Name],'-') AS HotelName,
ISNULL(FT_TBL.[Address1],'-') AS HotelAddress,
ISNULL(FT_TBL.[City],'-') AS HotelCity,
ISNULL(FT_TBL.[StateProvince],'-') AS HotelCountyState,
ISNULL(FT_TBL.[PostalCode],'-') AS HotelPostZipCode,
ISNULL(FT_TBL.[Latitude],0.00) AS HotelLatitude,
ISNULL(FT_TBL.[Longitude],0.00) AS HotelLongitude,
ISNULL(FT_TBL.[CheckInTime],'-') AS HotelCheckinTime,
ISNULL(FT_TBL.[CheckOutTime],'-') AS HotelCheckOutTime,
ISNULL(b.[CountryName],'-') AS HotelCountry,
ISNULL(c.PropertyDescription,'-') AS HotelDescription,
KEY_TBL.RANK
FROM [EAN].[dbo].[tblactivepropertylist] AS FT_TBL INNER JOIN
CONTAINSTABLE ([EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn, @s)
AS KEY_TBL
ON FT_TBL.EANHotelID = KEY_TBL.[KEY]
INNER JOIN [EAN].[dbo].[tblCountrylist] b
ON FT_TBL.Country = b.CountryCode
INNER JOIN [EAN].[dbo].[tblPropertyDescriptionList] c
ON FT_TBL.[EANHotelID] = c.EANHotelID
在上面的代码[EAN]。[dbo]。[tblEanFullTextSearch]中,FullTextSearchColumn是添加了字段的新表和列,现在可以对新表进行查询,并连接到要显示的表来自的数据。
希望这有帮助