SQL Server 2008 - разрыв строки и полнотекстовые запросы - PullRequest
3 голосов
/ 15 августа 2011

У меня есть база данных и полнотекстовая индексированная таблица. Давайте назовем эту таблицу 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 должен игнорировать разрывы строк при поиске слова, а это не так. Я не верю, что это стандартное поведение полнотекстового движка. По крайней мере, это не приемлемо. Что произойдет, если мои пользователи вставят строки с разрывами строк в мою таблицу (и это обычно, так как они могут написать все, что захотят, потому что поле является памятным полем)?

Есть ли способ исправить это?

EDIT

Это происходит только тогда, когда я выбираю бразильский язык для FT. Если я выбираю английский, ни одна из упомянутых проблем не возникает.

EDIT

На Sql Server Denali CTP3 не работает ни английский, ни португальский языки. Может быть, это ошибка в английском пароходе.

EDIT

Снимок экрана для использования fts_parser

Ответы [ 2 ]

0 голосов
/ 24 августа 2011

Попробуйте:

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

Глядя на документацию CONTAINS , кажется, что вам потребуется дополнительный термин близости, чтобы найти совпадение после Char(13).

Редактировать: Если недостаточно использовать термин близости, попробуйте добавить символ в список «шумовых слов», чтобы он игнорировался при индексации. Вы можете найти файлы шумовых слов в $SQL_Server_Install_Path\Microsoft SQL Server\MSSQL.1\MSSQL\FTData. Английский файл называется noiseENG.txt. Подробнее об этом можно прочитать в статье Роберта Шелдона о полнотекстовой индексации .

Редактировать: Я также провожу некоторые исследования различий между CHAR (13) и NCHAR (13), так как может возникнуть проблема с юникодом и не-юникодом, которую вы видите в Ваше оригинальное тестирование.

Редактировать: Кроме того, в 2008 году у Portugese появились новые средства разбиения по словам . Средства разбиения по словам зависят от языка и, вероятно, почему вы можете увидеть эту разницу. Также имеет значение , какой язык был выбран для индексированного столбца.

Редактировать: Чтобы проверить, как слова разбиваются, попробуйте запустить это (если у вас есть доступ к мастеру):

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) обрабатывается немного по-другому.

Screenshot

0 голосов
/ 22 августа 2011

Я пытался воспроизвести вашу так называемую «ошибку» на моем SQL Server 2008 (см. Код ниже). В результате он работает именно так, как вы ожидали. Я удивлен, что вы не предоставили полный код.

ОБНОВЛЕНИЕ: изменен язык полного индекса на португальский и получен тот же результат. Показывает "поведение, похожее на ошибку". UPDATE:

Почему это происходит?

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. Вы можете отправить заявку в службу поддержки.

Что произойдет, если мои пользователи вставят строки с разрывами строк в мою таблицу (и это обычно, так как они могут написать все, что хотят, потому что поле является памятным полем)?

WYSIWYG

Есть ли способ исправить это?

Может быть, вам потребуется загрузить собственный инструмент разбиения по словам или перейти на SQL Server 2005. Goodluck в любом случае!

        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"')
...