【问题标题】:Why is SQL Server Full Text Search indexing SCR or SUR acronym followed by a number, together?为什么 SQL Server 全文搜索索引 SCR 或 SUR 首字母缩写词后跟一个数字?
【发布时间】:2021-11-10 09:43:52
【问题描述】:

我发现 SQL Server 全文搜索的一个非常奇怪的行为是索引 SUR、SCR 和可能的其他一些首字母缩略词,以及它后面的数字 - 作为“精确匹配”。

SELECT * FROM sys.dm_fts_parser ('"SUR 12345"', 1033, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
s u r 1 2 3 4 5 1 0 1 Exact Match sur 12345 0 SUR 12345
n n 1 2 3 4 5 s u r 1 0 1 Exact Match nn12345sur 0 SUR 12345
SELECT * FROM sys.dm_fts_parser ('"SCR 12345"', 1033, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
s c r 1 2 3 4 5 1 0 1 Exact Match scr 12345 0 SCR 12345
n n 1 2 3 4 5 s c r 1 0 1 Exact Match nn12345scr 0 SCR 12345

其他首字母缩写词或文本,包括小写 sur,不受影响:

SELECT * FROM sys.dm_fts_parser ('"sur 12345"', 1033, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
s u r 1 0 1 Exact Match sur 0 sur 12345
1 2 3 4 5 1 0 2 Exact Match 12345 0 sur 12345
n n 1 2 3 4 5 1 0 2 Exact Match nn12345 0 sur 12345
SELECT * FROM sys.dm_fts_parser ('"ABC 12345"', 1033, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
a b c 1 0 1 Exact Match abc 0 ABC 12345
1 2 3 4 5 1 0 2 Exact Match 12345 0 ABC 12345
n n 1 2 3 4 5 1 0 2 Exact Match nn12345 0 ABC 12345
SELECT * FROM sys.dm_fts_parser ('"XYZ 76"', 1033, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
x y z 1 0 1 Exact Match xyz 0 XYZ 76
7 6 1 0 2 Exact Match 76 0 XYZ 76
n n 7 6 1 0 2 Exact Match nn76 0 XYZ 76

这种行为似乎出乎意料,很可能是错误的,但我也可能遗漏了一些与断字有关的明显内容(尝试 1033 和 2057 - 效果相同)。我在 SQL Server 2019 Linux 15.0.4053.23 和 2017 CU20 和 CU25 上复制了它,我可以立即访问。

有没有人有类似的问题和解决方案,以便 SUR、SCR 和任何其他可能损坏的首字母缩写词将独立于以下数字进行索引?

编辑:

将语言更改为 0(中性)会导致奇怪的行为 - 它不能解决使用 SUR 首字母缩写词时的问题,但会修复 SCR 首字母缩写词!

SELECT * FROM sys.dm_fts_parser ('"SUR 12345"', 0, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
s u r 1 2 3 4 5 1 0 1 Exact Match sur 12345 0 SUR 12345
n n 1 2 3 4 5 s u r 1 0 1 Exact Match nn12345sur 0 SUR 12345
SELECT * FROM sys.dm_fts_parser ('"SCR 12345"', 0, 0, 0)
keyword group_id phrase_id occurrence special_term display_term expansion_type source_term
s c r 1 0 1 Exact Match scr 0 SCR 12345
1 2 3 4 5 1 0 2 Exact Match 12345 0 SCR 12345
n n 1 2 3 4 5 1 0 2 Exact Match nn12345 0 SCR 12345

我决定悬赏这个问题,因为理想情况下我需要通过重新配置数据库索引来解决找不到搜索词的问题。

为了帮助重现下面的问题,是一个创建数据库的脚本(带有注释掉的 DROP 脚本以帮助重置状态)

/*
DROP FULLTEXT INDEX ON EnglishTexts
DROP FULLTEXT INDEX ON NeutralTexts
DROP FULLTEXT CATALOG TestSearchCatalog
USE master
DROP DATABASE TestSearch
*/

CREATE DATABASE TestSearch
GO

USE [TestSearch]
GO

CREATE FULLTEXT CATALOG TestSearchCatalog WITH ACCENT_SENSITIVITY = OFF
GO

CREATE TABLE EnglishTexts (Id INT IDENTITY(1,1) NOT NULL, Text NVARCHAR(MAX), CONSTRAINT PK_EnglishTexts PRIMARY KEY CLUSTERED (Id))
CREATE FULLTEXT INDEX ON EnglishTexts (Text LANGUAGE 'English') KEY INDEX PK_EnglishTexts ON ([TestSearchCatalog]) WITH (CHANGE_TRACKING = AUTO, STOPLIST = OFF)
INSERT INTO EnglishTexts(Text) VALUES ('PRFX 12233')
INSERT INTO EnglishTexts(Text) VALUES ('SUR 12233')
INSERT INTO EnglishTexts(Text) VALUES ('SCR 12233')

CREATE TABLE NeutralTexts (Id INT IDENTITY(1,1) NOT NULL, Text NVARCHAR(MAX), CONSTRAINT PK_NeutralTexts PRIMARY KEY CLUSTERED (Id))
CREATE FULLTEXT INDEX ON NeutralTexts (Text LANGUAGE 'Neutral') KEY INDEX PK_NeutralTexts ON ([TestSearchCatalog]) WITH (CHANGE_TRACKING = AUTO, STOPLIST = OFF)
INSERT INTO NeutralTexts(Text) VALUES ('PRFX 12233')
INSERT INTO NeutralTexts(Text) VALUES ('SUR 12233')
INSERT INTO NeutralTexts(Text) VALUES ('SCR 12233')

-- following query returns 1 row but should 3 - a possible bug in english word breaker
SELECT * FROM EnglishTexts WHERE CONTAINS(Text, '"12233"')

-- following query returns 2 rows but should 3 - neutral language word breaker is also treating SUR acronym specially - another bug?
SELECT * FROM NeutralTexts WHERE CONTAINS(Text, '"12233"')

-- following query returns 1 row but should 3 - forcing neutral language on a query on english index should apply neutral language (i might misunderstand if this is even possible without a neutral index)
SELECT * FROM EnglishTexts WHERE CONTAINS(Text, '"12233"', LANGUAGE 0)

-- following query returns 2 rows but should 3 - using neutral language on neutral language indexed table should not make a difference
SELECT * FROM NeutralTexts WHERE CONTAINS(Text, '"12233"', LANGUAGE 0)

-- for reference - English word breaker does not split SCR with 12233 and SUR with 12233, causing above problems
SELECT * FROM sys.dm_fts_parser ('"SCR 12233 SUR 12233"', 1033, 0, 0)

-- for reference - Neutral word breaker correctly splits SCR and 12233 but not SUR with 12233
SELECT * FROM sys.dm_fts_parser ('"SCR 12233 SUR 12233"', 0, 0, 0)

【问题讨论】:

  • 尝试发音为SCR。然后注意c 在pronouncing 中的发音。 SCR 听起来与SR 相同,而SUR 和SIR 听起来相同。
  • 全文搜索基本上是通过搜索单词和文本来创建的,您的示例对于全文来说是不合理的。您应该尝试创建一个新的停止列表(空),在该停止列表中的停止词中添加一个空格。使用此非索引字表重建您的全文索引。与丹麦语的答案相同,但只需创建一个新的空停止列表并在其中添加一个空格
  • 另外,如果您解释您正在尝试的搜索类型,我可以提供帮助,它看起来像条形码编号。您是否尝试在带有条形码的产品上查找内容?
  • 示例非常合理 - 文本包含首字母缩写词、空格和数字,例如“图书 ISBN 1234567 很好”。如果首字母缩写词是 SCR 或 SUR 而不是 ISBN,则搜索不会返回 1234567 的结果。
  • @MatBailie 关于发音,听起来(双关语)是一个很好的引导,尽管我认为中性语言不应该受到 SUR 的英语发音的影响

标签: sql sql-server parsing indexing full-text-search


【解决方案1】:

最后我能够确定这个问题与一个货币符号(显然 SUR 和 SCR 是货币符号)后面或前面有一个数字有关,导致两者被索引在一起。

在我看来,只有当用户期望过去(SUR - 苏联卢布,自 1993 年以来未使用)或当前(SCR - 塞舌尔卢比)货币出现在文本中并且只有在货币符号后面出现时,这才可能是一种理想的行为或根据标准在数字之前(例如 $ 在数字之前,SCR 或 € 在数字之后)。

此外,货币符号似乎部分影响了中性语言分词 - 过去的货币(如 SUR)很好,但当前影响语言中性分词的货币是完全出乎意料的行为,因为语言中性文本处理不应受到任何字典单词的影响。

Microsoft documentation of SQL Server 2012 及更高版本 FTS 文本处理解释了对分词器的相关更改,表明新的分词器不会单独索引货币符号或数字,即使在语言中性分词器中也是如此:

term previous new
100$ 100$ 100$
100$ nn100 nn100usd
$100 000 USD $100 $100 000 usd
$100 000 USD 000
$100 000 USD nn000
$100 000 USD nn100$
$100 000 USD usd

解决原始问题的唯一解决方案是恢复为 described here 的 2012 年之前的断词器和词干分析器。该解决方案涉及更改以下注册表项的几个步骤(另存为 .reg 文件并打开以应用,适用于 SQL Server 2017 上的默认实例 - MSSQL14.MSSQLSERVER - 将其更改为 C:\Program File\Microsoft SQL Server 中的实例目录名称):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSearch\Language\enu]
"WBreakerClass"="{188D6CC5-CB03-4C01-912E-47D21295D77E}"
"StemmerClass"="{EEED4C20-7F1B-11CE-BE57-00AA0051FE20}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSearch\CLSID\{188D6CC5-CB03-4C01-912E-47D21295D77E}]
@="langwrbk.dll"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSearch\CLSID\{EEED4C20-7F1B-11CE-BE57-00AA0051FE20}]
@="infosoft.dll"

更改注册表后,需要重新启动 SQL Server 并重新创建 FULLTEXT INDEX 对象 (DROP + CREATE FILLTEXT INDEX ON...) 才能使更改生效。

要恢复为原始分词器和词干分析器,请使用以下注册表项:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSearch\Language\enu]
"WBreakerClass"="{9FAED859-0B30-4434-AE65-412E14A16FB8}"
"StemmerClass"="{E1E5EF84-C4A6-4E50-8188-99AEF3DE2659}"

使用旧版本的分词器有明显的缺点,但至少货币符号的索引与它们周围的数值是分开的。

我想补充一点,我向 Microsoft 支持部门报告了这个问题,但它最终被归类为预期和期望的行为,除了使用旧的断词器之外无法修复它。

SQL Server 在处理 SUR 等术语时缺乏灵活性,在我的领域中它指的是 Surgery 而不是 Seychelles Rupee,这导致我开始将我们的产品迁移到PostgreSQL,将在未来 6 个月内完成。

【讨论】:

    【解决方案2】:

    我检查了你的情况,它很有趣。 经过一些工作和研发,我发现有些东西可能对你有帮助。

    问题是 1 或 2 个字符是停用词,因此当用户搜索包含它的短语时,全文索引搜索引擎会跳过它。解决方案:

    1) Drop all full text indexes and full text catalog
    
    2)Create a stop list and set in the stoplist Action=Delete All Stopwords and Full-Text Language=English
    
    3)Create all full text indexes and full text catalog through scripts as given below instead of wizard
    
    4)Attach stoplist to the full text indexes when creating them
    
    
    /*******************Drop and create FULL TEXT CATALOG for AbstractSearch*************************************/
    
    /****** Drop:  FullTextCatalog [abstractSearch]    Script Date: 12/02/2011 13:10:21 ******/
    
    GO
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Abstract]'))
    
    ALTER FULLTEXT INDEX ON [dbo].[Abstract] DISABLE
    
    GO
    
    /****** Object:  FullTextIndex     Script Date: 12/02/2011 13:10:21 ******/
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Abstract]'))
    
    DROP FULLTEXT INDEX ON [dbo].[Abstract]
    
    GO
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Author]'))
    
    ALTER FULLTEXT INDEX ON [dbo].[Author] DISABLE
    
    GO
    
    /****** Object:  FullTextIndex     Script Date: 12/02/2011 13:10:21 ******/
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Author]'))
    DROP FULLTEXT INDEX ON [dbo].[Author]
    
    GO
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Synonym]'))
    ALTER FULLTEXT INDEX ON [dbo].[Synonym] DISABLE
    
    GO
    
    /****** Object:  FullTextIndex     Script Date: 12/02/2011 13:10:21 ******/
    
    IF  EXISTS (SELECT * FROM sys.fulltext_indexes fti WHERE fti.object_id = OBJECT_ID(N'[dbo].[Synonym]'))
    DROP FULLTEXT INDEX ON [dbo].[Synonym]
    GO
    
    IF  EXISTS (SELECT * FROM sysfulltextcatalogs ftc WHERE ftc.name = N'abstractSearch')
    
    DROP FULLTEXT CATALOG [abstractSearch]
    GO
    
    
    /****** Create:  FullTextCatalog [abstractSearch]    Script Date: 12/02/2011 13:10:21 ******/
    
    CREATE FULLTEXT CATALOG [abstractSearch]
    
    AS DEFAULT
    
    GO
    
    /****** Create:  FullTextIndex on  Abstract with stoplist set to custom stoplist   Script Date: 12/02/2011 13:10:21 ******/
    
    CREATE FULLTEXT INDEX ON dbo.Abstract
    
    (abstractTitle, abstractDescription)
    
    KEY INDEX PK_Abstract
    ON [abstractSearch]
    
    WITH STOPLIST = [AbstractSearchStopList]
    
    
    /******  Create:  FullTextIndex on  Synonym with stoplist set to custom stoplist    Script Date: 12/02/2011 13:10:21 ******/
    CREATE FULLTEXT INDEX ON dbo.Synonym
    
    (synonyms,keywordSynonym)
    
    KEY INDEX PK_Synonyms
    
    ON [abstractSearch]
    
    WITH STOPLIST = [AbstractSearchStopList]
    
    
    /******  Create:  FullTextIndex on  Author with stoplist set to custom stoplist   Script Date: 12/02/2011 13:10:21 ******/
    
    CREATE FULLTEXT INDEX ON dbo.Author
    
    (firstName,lastName,middleName)
    
    KEY INDEX PK_Author
    
    ON [abstractSearch]
    WITH STOPLIST = [AbstractSearchStopList]
    

    【讨论】:

    • 感谢您抽出宝贵的时间来回答,我明天会进行步骤。目前据我所知,我使用的索引没有启用停止列表(默认)。
    • 不幸的是,这篇文章与我的问题无关,我检查了索引没有使用停止列表:SELECT fulltext_catalog_id, stoplist_id FROM sys.fulltext_indexes;
    • 很伤心,无论如何,当你得到解决方案时,请分享你的发现。
    猜你喜欢
    • 1970-01-01
    • 2011-01-08
    • 2011-03-02
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多