SQL 服务器全文搜索围绕数字和下划线

SQL Server Full Text Search around numbers and underscores

使用 SQL Server 2012(通常使用 SQL Server 2008 R2 到 SQL Server 2016)

这个问题是 SQL-Server Full Text Index Unexpected results 的更具体的重新措辞。请在此处查看我们如何走到这一步以及已经尝试过的内容。

现在我们已经找到了具体的错误,我正在重新发布。非常感谢 @HoneyBadger

他的帮助对这一点来说是无价的。

Table结构:

CREATE TABLE TestFullTextSearch (Id INT NOT NULL, AllText NVARCHAR(400))

CREATE UNIQUE INDEX test_tfts ON TestFullTextSearch(Id)

CREATE FULLTEXT CATALOG ftcat_tfts

CREATE FULLTEXT INDEX ON TestFullTextSearch(AllText)
    KEY INDEX test_tfts ON ftcat_tfts
    WITH CHANGE_TRACKING AUTO, STOPLIST OFF

数据:

INSERT INTO TestFullTextSearch 
VALUES (1, ' 123_456 789 '), (2, ' 789 123_456 '),
       (3, ' 123_456 ABC '), (4, ' ABC 123_456 ')

请注意,此数据仅用于演示问题,并不代表实时数据集。我们的实时数据集可能超过 500,000 行,搜索单个字段中的数据段落 - 因此使用全文搜索。

Select 1: 结果符合预期

SELECT *
FROM TestFullTextSearch
WHERE CONTAINS (AllText, '"123*"')

Id          AllText
----------- ------------
1            123_456 789
2            789 123_456
3            123_456 ABC
4            ABC 123_456

SELECT 2: 遗漏结果集中的第 2 行

SELECT *
FROM TestFullTextSearch
WHERE CONTAINS (AllText, '"123_*"')

Id          AllText
----------- ------------
1            123_456 789
3            123_456 ABC
4            ABC 123_456

SELECT 3: 仅 returns 行 2

SELECT *
FROM TestFullTextSearch
WHERE CONTAINS (AllText, '"123\_*"')

Id          AllText
----------- ------------
2            789 123_456

结论:如果前面的词是数字字符串,则搜索下划线后缀的数字字符串失败。

问题: 我们的客户使用全文搜索并期望结果围绕零件号和目录参考出现,这些参考可能在也可能不在文本部分中,包括其他数字字符串。全文搜索似乎并不以一致的方式支持这一点。

感谢收到的任何帮助。

注意:此问题不会发生在 SQL SERVER 2008,但会发生在 2012+

我也试过切换到旧版本的 FTS 解析器。使用

进行测试
SELECT * FROM sys.dm_fts_parser (' "789 123_456" ',1033,0,0)
SELECT * FROM sys.dm_fts_parser (' "789 123_456" ',2057,0,0)

我有当前的解析器:

恢复到旧版解析器后:

所以它有效果,但我仍然得到相同的结果。

2008 年和 2012 年之间的全文搜索是否有任何其他差异可能会产生这种影响?

为什么不使用 LIKE 运算符?尝试 AllText LIKE '%123[_]%',它将 return 所有四行。

另一种解决方案是使用 CHARINDEX,例如:

where charindex('123_', AllText) > 0

0 表示在另一个字符串中找不到该字符串。

如果您对上面提到的@Michal 查询的全文搜索有疑问,那么您可以应用其他替代解决方案,如下所示:

  1. 虽然在数据库中插入 AllText 维护其他列,其中包含指示包含 123 的标志(布尔值),因此在 SELECT 语句时只需检查该标志。
  2. 使用模式公式维护计算列,return true OR false.

他们在 SQL 2008 和 SQL 2012 之间更改了全文 parsers/stemmers。

通过更改注册表,您可以使用旧式解析器,它应该更适合您的情况。

详情见https://technet.microsoft.com/en-us/library/gg509108(v=sql.110).aspx

如果您需要同时支持新旧风格,那么您可以将美国英语恢复为旧英语并保留英国英语(反之亦然)

使用 SQL 2016,我恢复了英国英语并保持美国英语不变:

exec sp_help_fulltext_system_components 'wordbreaker', 1033

exec sp_help_fulltext_system_components 'wordbreaker', 2057

Returns:

我使用英国英语创建了另一个 table 并填充了它。

CREATE TABLE TestFullTextSearch2 (Id INT NOT NULL, AllText NVARCHAR(400))

CREATE UNIQUE INDEX test_tfts2 ON TestFullTextSearch2(Id)


CREATE FULLTEXT INDEX ON TestFullTextSearch2(AllText language 2057)
    KEY INDEX test_tfts2 ON ftcat_tfts 
    WITH CHANGE_TRACKING AUTO, STOPLIST OFF

    INSERT INTO TestFullTextSearch2
VALUES (1, ' 123_456 789 '), (2, ' 789 123_456 '),
       (3, ' 123_456 ABC '), (4, ' ABC 123_456 ')

所有 3 个查询都得到了预期的 4 个结果。

验证您的更改是否已生效。

exec sp_help_fulltext_system_components 'wordbreaker', 1033

exec sp_help_fulltext_system_components 'wordbreaker', 2057

select t.name, c.* from sys.tables t inner join sys.fulltext_index_columns c on t.object_id = c.object_id

这里的问题基本上是 MSSQL 2012 如何存储索引以及查询本身如何处理下划线 _ 的不同。

检查 index keywords & fts parser 时,这一点变得很清楚。对于第 2 行,关键字 123_456 没有这样存储,因为它前面有数值。但是,fts 解析器将搜索与“123_”完全匹配的内容,并且不会删除下划线。

select * from sys.dm_fts_index_keywords_by_document
( 
    DB_ID('TestDatabase'),     
    OBJECT_ID('TestFullTextSearch') 
) order by document_id

select * from sys.dm_fts_parser('"123_*"', 0, 0, 0)

一种解决方案是 change the word breaker 特定语言。您可以轻松地将其替换为 MSSQL 2008 或 2016 中的分词器 dll,而不会出现此问题。 (例如,使用中性语言:NaturalLanguage6.dll)。确保为相同的语言创建全文索引。

要查找已注册的断字符和 dll 所在的位置,请使用此查询:

EXEC sp_help_fulltext_system_components 'wordbreaker';