【问题标题】:Sql Server 2008 - Line Break and fulltext queriesSql Server 2008 - 换行和全文查询
【发布时间】:2011-10-27 08:18:57
【问题描述】:

我有一个数据库和一个全文索引表。让我们将此表称为test。此表有一个名为testfield 的字段。现在,我们只插入一条记录如下:

insert into test values ('word' + Char(13) + 'test')

此查询插入带有LINE_BREAK 的单词。

现在,让我们使用全文查询该表:

select * from test where contains(testfield, '"word test"')

在这种情况下,此查询根本不返回任何内容。

还有:

select * from test where contains(testfield, '"wordtest"')

什么都不返回(本来就是这样)

现在,让我们修改搜索词再次查询表:

select * from test where contains(testfield, '"word' + Char(13) + 'test"')

在这种情况下,查询返回正确的行。

问题是:为什么会发生这种情况?我的意思是,SQL 在搜索单词时应该忽略换行符,但它不会。我不认为这是全文引擎的默认行为。至少这是不可接受的。如果我的用户在我的表格上插入带有换行符的行(这很常见,因为他们可以写任何他们想要的东西,因为该字段是一个备注字段)会发生什么?

有什么办法可以改正吗?

编辑

只有当我选择巴西语作为 FT 的语言时才会发生这种情况。如果我选择英语,我提到的问题都不会发生。

编辑

在 Sql Server Denali CTP3 上,英语和葡萄牙语都不起作用。也许这是英文蒸笼中的错误。

编辑

fts_parser的使用截图

【问题讨论】:

  • 如果您搜索“wordtest”而不是“word test”会怎样。只是好奇这是如何解决的
  • 它也不返回任何内容。
  • 尝试插入 'word' + char(13) + char(10) + 'test' 然后搜索 'word test' 看看是否返回
  • @Derek 同样的事情。什么都没找到。

标签: sql-server-2008 full-text-search line-breaks


【解决方案1】:

试试:

select * from test where contains(testfield, 'word NEAR test')

查看CONTAINS documentation,您似乎需要额外的邻近词才能找到Char(13) 之后的匹配项。

编辑:如果使用邻近词还不够,请尝试将字符添加到“干扰词”列表中,以便在索引中忽略它。您可以在$SQL_Server_Install_Path\Microsoft SQL Server\MSSQL.1\MSSQL\FTData 中找到干扰词文件。英文文件名为noiseENG.txt。您可以在Robert Sheldon's article about full-text indexing 中找到有关此详细信息的更多信息。

编辑:我还在研究 CHAR(13) 和 NCHAR(13) 之间的区别,因为您可能会看到 unicode 与非 unicode 问题在您的原始测试中。

编辑:此外,2008 年葡萄牙语获得了新的word breakers。断字器是特定于语言的,可能是您会看到这种差异的原因。它还 matters 为索引列选择了哪种语言。

编辑:要检查单词是如何被破坏的,请尝试运行这个(如果您可以访问 master):

declare @english nvarchar(20), @portugese nvarchar(20)
set @english = N'"hello' + NCHAR(13) + N'world"'
set @portugese = N'"Olá' + NCHAR(13) + N'mundo"'

select * from sys.dm_fts_parser (@english, 1033, 0, 0)
select * from sys.dm_fts_parser (@portugese, 2070, 0, 0)

编辑:这打破了英语和葡萄牙语中的短语“hello[13]world”。下面是结果的截图,和我想的一样。 CHAR(13) 的处理方式略有不同。

【讨论】:

  • 这不好,因为near 不能指定接近度。在这种情况下,near 将返回例如在短语末尾带有单词 test 的行。如果我使用的是 Denali,near 可以工作,因为 denali 允许您指定接近度。我需要搜索一个确切的短语。
  • 那么您搜索的短语需要与您要查找的带有 Char(13) 的文本完全相同。它不像您假设的那样工作,并且像对待空格一样对待 Char(13)。 Char(13) 也可能是字母A。您可以使用某种方法将 Char(13) 替换为真正的空格(通过触发器、夜间作业等)吗?
  • 现在我正在用 char(13) 替换空格,但这不是我想做的。当您说 char(13) 不像空格时,我理解您的观点,但是它在英语中如何工作而在葡萄牙语中却没有?我的意思是,英语和葡萄牙语中的 char(13) 是一回事。
  • 我在回答中添加了一些附加信息。我认为归根结底是语言的差异以及全文索引的存储方式。
  • 回应您的编辑:我确实将 Char(13) 添加到干扰词列表中,但它不起作用。我知道语言之间存在差异,因为轮船会因语言而异。但是想一想:为什么只有英语有效?为什么在德纳利英语和葡萄牙语都不起作用?我对全文、断词器、steamers、词库、字典了解很多。但我不明白为什么它在英语中有效而在其他语言中无效。 AFAIK,微软解决了这个问题,因为在 Denali 中情况有所不同。
【解决方案2】:

我试图在我的 SQL Server 2008 上重现您所谓的“错误”(请参阅​​下面的代码)。结果,它完全按照您的预期工作。我很惊讶你一开始没有提供完整的代码。

更新:将完整索引的语言更改为葡萄牙语并收到相同的结果。它显示“类似错误的行为”。 更新:

为什么会这样?

MS 在 SQL Server 2008 中引入了新的分词器,葡萄牙语就是其中之一。

我的意思是,SQL 在搜索单词时应该忽略换行符 才不是。我不认为这是全文引擎的默认行为。至少不能接受。

更新:看起来这种行为可以在所有新的断路器中看到。

 -- Create auxiliary table to test languages
IF OBJECTPROPERTY(object_id('test_languages'), 'IsUserTable') IS NOT NULL
DROP TABLE test_languages;
GO

CREATE TABLE test_languages
(
componenttype varchar(30),
componentname int,
clsid uniqueidentifier,
fullpath varchar(2000),
version_no varchar(50),
manufacturer varchar(50)
);

-- Populate Auxiliary table 
INSERT INTO test_languages
EXEC ('exec sp_help_fulltext_system_components ''wordbreaker''');


-- Create Cursor and check how languages work with sys.dm_fts_parser 
  DECLARE MY_CURSOR CURSOR FOR
  select 
  componentname
  from test_languages 
  INNER JOIN 
  sys.fulltext_languages
  on sys.fulltext_languages.lcid=test_languages.componentname
  ORDER BY name

  DECLARE @RESULT varchar(max)
  DECLARE @test_var NVARCHAR(20)
  SET @test_var='"word' + CHAR(13) + 'test"'   
  DECLARE @componentname int

  OPEN MY_CURSOR

  FETCH NEXT FROM MY_CURSOR
    INTO @componentname

WHILE (@@FETCH_STATUS = 0)
 BEGIN

    SELECT name+ ' - '+ 
    CASE test_languages.version_no 
  WHEN '6.0.6001.18000' 
  THEN 'Updated Language 6.0.6001.18000'
  WHEN '12.0.9735.0'
  THEN 'Old Language 12.0.9735.0'
  WHEN '12.0.6828.0'
  THEN 'Old Language 12.0.6828.0'
  END
  AS [Language_Type]

 FROM test_languages 
  INNER JOIN 
  sys.fulltext_languages
  ON sys.fulltext_languages.lcid=test_languages.componentname
  WHERE lcid=@componentname
    SELECT display_term
    FROM sys.dm_fts_parser (@test_var, @componentname, 0, 0)



    FETCH NEXT FROM MY_CURSOR
    INTO @componentname

 END;

-- clean up the mess 
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR; 
DROP TABLE test_languages;

由 MS 决定这是否可以接受。不过,您可以通过支持服务提交票证。

如果我的用户在我的表格上插入带有换行符的行会发生什么 (这很常见,因为他们可以写任何他们想要的东西,因为 该字段是备注字段)?

所见即所得

有什么办法可以改正吗?

也许您需要上传自己的断字系统或降级到 SQL Server 2005。 总之祝你好运!

        USE
        master
        GO

        CREATE
        DATABASE Test_Brazil -- Portuguese (Brazil)
        COLLATE
        Latin1_General_100_CI_AI

        USE
        Test_Brazil
        GO

        CREATE
        TABLE [dbo].[test](
        [test] [varchar] (100) NOT NULL
        )
        ON [PRIMARY]

        CREATE UNIQUE NONCLUSTERED INDEX [test] ON [dbo].[test] 
        (
        [test]
        ASC
        )
        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
        GO

        CREATE
        FULLTEXT CATALOG ft AS DEFAULT;

        CREATE
        FULLTEXT INDEX ON test(test)
        KEY INDEX test
        WITH STOPLIST = SYSTEM;

        sp_fulltext_database 'enable'


        insert into test values ('word' + Char(9) + 'test') --Tab    
        insert into test values ('word' + Char(10) + 'test') -- Line feed     
        insert into test values ('word' + Char(13) + 'test') -- Carriage return  
        insert into test values ('word test')
        -- wait 3 sec

        select test from test where contains(test, '"word test"')

        -- 4 rows returned

        DROP FULLTEXT INDEX ON dbo.test
        CREATE
        FULLTEXT INDEX ON dbo.test
        (
         test Language 2070 -- Portuguese
        )
        KEY INDEX test;


        -- 2 rows returned
        select * from test where contains(test, '"word test"')

【讨论】:

  • 所以,你说的是我是对的,对吧?当您选择葡萄牙语时,您只得到 2 个结果,和我一样。在那种情况下,这不是一个答案,你只是复制了我知道它正在发生。不过还是感谢您的帮助。
  • 首先,您没有提供原始代码,所以我不得不重现实际执行您解释的代码。我的回答是“是的,这是一个错误”。您知道有时 MS 软件会出现错误,并且不会像您预期的那样运行。最后,我不会感谢您对我的回答投反对票,这清楚地表明您不欣赏我的时间和精力。
  • 我确实投了反对票,并不是因为我不欣赏您的时间和精力。我愿意。我这样做是因为你只是证实了我所知道的,这不是答案。我需要知道如何克服这个问题,这就是我首先在这里发布的原因。我很感谢这个脚本等等,但我想如果没有这个脚本,复制起来并不难。
猜你喜欢
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-02
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
相关资源
最近更新 更多