12

首先,似乎没有办法使用全文搜索获得完全匹配。在使用全文搜索方法时,这似乎是一个被高度讨论的问题,并且有许多不同的解决方案可以达到预期的结果,但大多数似乎效率很低。由于我的数据库量很大,我被迫使用全文搜索,因此我最近不得不实施其中一种解决方案以获得更准确的结果。

由于它的工作原理,我无法使用全文搜索的排名结果。例如,如果您搜索一部名为的电影Toy Story,并且还有一部名为的电影The Story Behind Toy Story,它会出现而不是完全匹配,因为它Story两次找到了单词 and Toy

每次用户访问记录时,我都会跟踪我自己的排名,我称之为“人气”,这个数字会上升。我使用这个数据点来衡量我的结果,以帮助确定用户可能在寻找什么。

我也有有时需要回退到 LIKE 搜索而不返回完全匹配的问题。即搜索Goonies应该返回The Goonies(最流行的结果)

因此,这是我当前用于实现此目的的存储过程的示例:

DECLARE @Title varchar(255)
SET @Title = '"Toy Story"'
--need to remove quotes from parameter for LIKE search
DECLARE @Title2 varchar(255)
SET @Title2 = REPLACE(@title, '"', '')

--get top 100 results using full-text search and sort them by popularity
SELECT TOP(100) id, title, popularity As Weight into #TempTable FROM movies WHERE CONTAINS(title, @Title) ORDER BY [Weight] DESC

--check if exact match can be found
IF EXISTS(select * from #TempTable where Title = @title2)
--return exact match
SELECT TOP(1) * from #TempTable where Title = @title2
ELSE
--no exact match found, try using like with wildcards
SELECT TOP(1) * from #TempTable where Title like '%' + @title2 + '%'
DROP TABLE #TEMPTABLE

这个存储过程每分钟执行大约 5,000 次,而且很疯狂,它并没有让我的服务器瘫痪。但我真的很想知道是否有更有效的方法来解决这个问题?谢谢。

4

4 回答 4

5

您应该使用全文搜索CONTAINSTABLE来查找前 100 个(可能是 200 个)候选结果,然后使用您自己的标准对找到的结果进行排序。

听起来你想ORDER BY

  1. 短语 ( =)的完全匹配
  2. 完全匹配的短语 ( LIKE)
  3. Popularity列的更高值
  4. Rank从_CONTAINSTABLE

但是你可以玩弄你喜欢的确切顺序。

在 SQL 中看起来像:

DECLARE @title varchar(255)
SET @title = '"Toy Story"'
--need to remove quotes from parameter for LIKE search
DECLARE @title2 varchar(255)
SET @title2 = REPLACE(@title, '"', '')

SELECT
    m.ID,
    m.title,
    m.Popularity,
    k.Rank
FROM Movies m
INNER JOIN CONTAINSTABLE(Movies, title, @title, 100) as [k]
    ON m.ID = k.[Key]
ORDER BY 
  CASE WHEN m.title = @title2 THEN 0 ELSE 1 END,
  CASE WHEN m.title LIKE @title2 THEN 0 ELSE 1 END,
  m.popularity desc,
  k.rank

请参阅SQLFiddle

于 2014-02-17T19:12:28.210 回答
2

这将为您提供包含确切短语“玩具总动员”的电影,按其受欢迎程度排序。

SELECT
    m.[ID],
    m.[Popularity],
    k.[Rank]
FROM [dbo].[Movies] m
INNER JOIN CONTAINSTABLE([dbo].[Movies], [Title], N'"Toy Story"') as [k]
    ON m.[ID] = k.[Key]
ORDER BY m.[Popularity]

请注意,如果您搜索“The Goonies”,上述内容也会为您提供“The Goonies Return”。

于 2013-05-15T01:21:27.703 回答
0

如果感觉你并不真正喜欢全文搜索的模糊部分,但你确实喜欢性能部分。

也许这是一条路径:如果您坚持在加权匹配之前获得精确匹配,您可以尝试对值进行哈希处理。例如“玩具总动员”-> 转换为小写字母-> 玩具总动员-> 散列成 4de2gs5sa(使用您喜欢的任何散列)并对散列执行搜索。

于 2014-02-12T07:47:23.693 回答
0

在 Oracle 中,我将 UTL_MATCH 用于类似目的。( http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/u_match.htm )

例如,即使使用 Jaro Winkler 算法比较表 1 和表 2 中的标题列可能需要一段时间,但如果将这两个表部分连接起来,则可以提高性能。在某些情况下,我使用 Jaro Winkler 将表 1 上的人名与表 2 进行了比较,但结果有限,不仅超出了某个 Jaro Winkler 阈值,而且还限于首字母相同的 2 个表之间的名称。例如,我会使用 Jaro Winkler 将 Albert 与 Aden、Alfonzo 和 Alberto 进行比较,而不是 Albert 和 Frank(限制需要使用该算法的情况的数量)。

Jaro Winkler 实际上也可能适用于电影标题。尽管您使用的是 SQL 服务器(不能使用 utl_match 包),但看起来有一个名为“SimMetrics”的免费库,其中包含 Jaro Winkler 算法以及其他字符串比较指标。您可以在此处找到详细信息和说明:http: //anastasiosyal.com/POST/2009/01/11/18.ASPX?#simmetrics

于 2014-02-17T18:46:55.250 回答