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 查询的全文搜索有疑问,那么您可以应用其他替代解决方案,如下所示:
- 虽然在数据库中插入
AllText
维护其他列,其中包含指示包含 123
的标志(布尔值),因此在 SELECT
语句时只需检查该标志。
- 使用模式公式维护计算列,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';
使用 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 查询的全文搜索有疑问,那么您可以应用其他替代解决方案,如下所示:
- 虽然在数据库中插入
AllText
维护其他列,其中包含指示包含123
的标志(布尔值),因此在SELECT
语句时只需检查该标志。 - 使用模式公式维护计算列,return
true
ORfalse
.
他们在 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';