为什么 CONTAINS 在字符串末尾找不到匹配项?

Mag*_*ith 5 sql-server full-text-search

我在 Microsoft SQL Server 2008 R2 (SP3) 中有一个存储过程,它在表中搜索与@Keywords我传入的参数匹配的任何内容。LIKE由于该表有 155,000 行,所以使用速度太慢,所以我创建了一个全文目录并切换到使用CONTAINS反而。我对这个功能不是很熟悉,但在研究之后似乎我需要做的就是处理用户选择的单词:

SET @Keywords = '"' + @Keywords + '*"'
Run Code Online (Sandbox Code Playgroud)

添加双引号和星号效果很好,直到有人发现在搜索他们知道肯定存在的字符串时没有结果。似乎*正在停止CONTAINS查找@Keywords位于字符串最末尾的行。

使用非常简单的 t-SQL 进行分析:

--first I prove that I can find the one row which the user was searching for
--this column is a NVARCHAR(200)
SELECT * FROM News 
WHERE Headline = '1120 days at sea and still sailing' --1 row returned (OK)
SELECT * FROM News 
WHERE Headline LIKE '1120 days at sea and still sailing%' --1 row returned (OK)

--using the full headline
SELECT * FROM News 
WHERE CONTAINS(Headline, '"1120 days at sea and still sailing*"') --no rows, just like my proc (WRONG)
SELECT * FROM News 
WHERE CONTAINS(Headline, '"1120 days at sea and still sailing"') --1 row returned if asterisk omitted (OK)

--using part of the headline so we don't touch the end of the
SELECT * FROM News 
WHERE CONTAINS(Headline, '"days at sea and still"') --lots of rows, since it is anything with 'days' and then 'sea' present (NOT USEFUL)
SELECT * FROM News 
WHERE CONTAINS(Headline, '"days at sea and still*"') --no rows (WRONG)
Run Code Online (Sandbox Code Playgroud)

我注意到,CONTAINS考虑在/和/仍然是“噪音”字并且忽略它们。很公平。航行这个词是字符串末尾的麻烦词。

我的问题:

我应该如何修改传入的关键字以确保CONTAINS无论列值中关键字字符串的位置如何,都可以找到结果?

Ran*_*gen 5

这与添加星号 (*) 与 组合时如何处理非索引字表(或干扰词)有关CONTAINS()

对此有更长的解释。

简而言之:默认 <> 前缀搜索

默认情况下,使用非SYSTEM索引字表时,某些单词不会被索引并分类为非索引字表单词。

添加 * + 时,CONTAINS()它们不会被视为非索引字词,并且确切的短语必须匹配。但是,当使用默认非SYSTEM索引字表时,这些“非索引字表单词”不会添加到索引中,导致找不到匹配项。


问题

您是说,当存在星号时,预期的行为是为包含干扰词的用户返回零匹配项?当您考虑大多数人可能会输入的内容时,这似乎令人惊讶!

前缀匹配与 Microsoft 文档中的 contains 相结合

指定以指定文本开头的单词或短语的匹配。将前缀术语括在双引号 ("") 中,并在结束引号前添加星号 (*),以便匹配以星号之前指定的简单术语开头的所有文本

来源

这里的关键词是:

以便匹配以星号之前指定的简单术语开头的所有文本

这意味着我们在使用前缀匹配 和 时必须具有精确匹配CONTAINS()


解决方法#1 禁用非索引字表

解决此问题的一种方法是禁用“非索引字表”

ALTER FULLTEXT INDEX ON News
SET STOPLIST OFF;
Run Code Online (Sandbox Code Playgroud)

您必须知道,这会增加存储在全文索引中的单词,因为单词“and”、“or”、“still”等被添加到索引中。

禁用非索引字列表可能会影响性能。

重新启用系统非索引字表

ALTER FULLTEXT INDEX ON News
SET STOPLIST SYSTEM;
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建自己的非索引字表

根据您的查询对此进行测试:

ALTER FULLTEXT INDEX ON News
SET STOPLIST OFF;
INSERT INTO News(Headline)
VALUES('1120 days at sea and still sailing')

INSERT INTO News(Headline)
VALUES('zzz 1120 days at sea and still sailing')

SELECT * FROM News 
WHERE CONTAINS(Headline, '"days at sea and still*"') 
Run Code Online (Sandbox Code Playgroud)

结果

id  Headline
1   1120 days at sea and still sailing
2   zzz 1120 days at sea and still sailing
Run Code Online (Sandbox Code Playgroud)

对于其他解决方法,您可以考虑使用CONTAINS()FREETEXT()不使用前缀匹配,或使用前缀匹配 +CONTAINS()与一个(非噪音)单词以获得更准确的结果


在您的情况下,启用transform noise words似乎不适用于前缀匹配

sp_configure 'show advanced options', 1;
RECONFIGURE;
GO
sp_configure 'transform noise words', 1;
RECONFIGURE;
GO
Run Code Online (Sandbox Code Playgroud)

再次由于前缀匹配 + contains 的工作方式。

SELECT * FROM News 
WHERE CONTAINS(Headline, '"1120 days at sea and still sailing*"')
Run Code Online (Sandbox Code Playgroud)

- 没有结果


在全文索引内(使用 stoplist = system)。

SELECT display_term,column_id,document_count
FROM sys.dm_fts_index_keywords(DB_ID('MNGDB'), OBJECT_ID('dbo.News'));
Run Code Online (Sandbox Code Playgroud)

结果

display_term    column_id   document_count
1120                 2           2
days                 2           2
nn1120               2           2
sailing              2           2
sea                  2           2
zzz                  2           1
END OF FILE          2           2 
Run Code Online (Sandbox Code Playgroud)

'Still'、'at'、'and' 被过滤掉,禁用非索引字表时它们将被添加到索引中

无停用词测试

ALTER FULLTEXT INDEX ON News
SET STOPLIST SYSTEM;

INSERT INTO dbo.News
VALUES('days sea sailing')
SELECT * FROM dbo.News 
WHERE CONTAINS(Headline, '"days sea sailing*"') 

id  Headline
4   days sea sailing
Run Code Online (Sandbox Code Playgroud)

更多关于星号的信息

星号的存在启用前缀匹配模式...如果提供了短语,则如果该列包含所有指定单词且最终单词后有零个或多个其他字符,则会检测到匹配项

来源