Поддержка полнотекстового поиска в SQL Server

 Margaret Li (Program Manager, Data Access Group)
Frank Pellow (Program Manager, SQL Server Relational Engine)

 


Информация, содержащаяся в этом документе, представляет текущую точку зрения корпорации Microsoft на обсуждаемые вопросы на момент публикации. Поскольку Microsoft должна реагировать на изменяющиеся условия на рынке, документ не следует рассматривать как обязательство со стороны Microsoft; корпорация Microsoft не может гарантировать, что вся представленная информация сохранит точность после даты публикации. Настоящий документ предназначен только для информационных целей. MICROSOFT НЕ ДАЕТ В ЭТОМ ДОКУМЕНТЕ НИКАКИХ ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ.

Ó 1998 Microsoft Corporation. Все права защищены. Microsoft, MS-DOS, SQL Server и Windows NT представляют собой зарегистрированные товарные знаки или товарные знаки корпорации Microsoft, используемые в США и других странах. Другие упоминаемые здесь названия продуктов или компаний могут представлять собой товарные знаки соответствующих владельцев.

 

Microsoft Part Number: 098-80764


 


Оглавление  

Резюме

1

Введение

1

Понятия полнотекстового поиска

1

Полнотекстовый поиск в Transact-SQL

2

        Предикат CONTAINS

3

        Предикат FREETEXT

4

        Сочетание предикатов и их использование

4

        Функция ContainsTable()

5

        Функция FreetextTable()

6

Текстовые запросы для данных, хранящихся в файловой системе

6

Компонентная архитектура полнотекстового индексирования

6

Компонентная архитектура полнотекстовых запросов

8

Администрирование полнотекстового поиска

10

Выводы

13

 


Резюме

   

В состав системы Microsoft® SQL Server™ 7.0 введены средства поддержки текстовых запросов, которые работают  с информацией, находящейся как в базах данных SQL Server, так и в файловой системе.  Вначале мы вводим основные понятия, относящиеся к полнотекстовому поиску, затем – возможную форму полнотекстового запроса и тип информации, которую можно находить с помощью таких запросов. Потом мы проводим читателя через сугубо техническое обсуждение внутреннего устройства и архитектуры полнотекстовой поисковой системы, а далее описываем, как эта система может администрироваться с помощью хранимых процедур и графических интерфейсов пользователя, предоставляемых SQL Server Enterprise Manager.

Назначение этой статьи -- дать полный обзор возможностей полнотекстового поиска SQL Server 7.0 и представление о том, как различные составные части взаимодействуют друг с другом при их поддержке.

Поддержка текстовых запросов относительно данных, содержащихся в файловой системе, — тема, изложенная в других документах, посвященных SQL Server 7.0.

Введение

Весьма большая часть информации, хранящейся сегодня цифровыми средствами, по-прежнему имеет форму неструктурированных данных -- в основном, текста. Хотя большей частью текстовые данные хранятся в файловой системе, некоторые организации начали помещать их в реляционные базы данных, используя для этого столбцы символьных типов, таких как varchar или text. В результате теперь пользователи нуждаются в механизмах, позволяющих эффективно отыскивать тексты в самой базе данных. Традиционные реляционные СУБД, такие как Microsoft SQL Server 6.5, не предназначались для эффективного полнотекстового поиска. Например, хотя SQL Server 6.5 располагает кое-какими средствами поиска текста на основе шаблонов, он не может выполнять задания на поиск слов и выражений, которые должны быть расположены близко по отношению друг к другу.

Есть два основных типа текстовых запросов: 

Поиск свойств: Применять к документам фильтры, извлекающие из них отдельные свойства – такие, как имя автора, тема, тип, количество слов или печатных страниц.

Полнотекстовый поиск:  Создавать индексы всех значимых слов в документах, а затем использовать их для поддержки лингвистического поиска и поиска по признаку близости текстовых образцов друг к другу.

Отсутствие средств полнотекстового поиска в составе реляционных систем управления базами данных заставило потребителей обращаться к вспомогательным продуктам других поставщиков. Обычно их решение состоит в том, чтобы выкачивать данные из баз через те или иные интерфейсы и хранить их в файловой системе как файлы, к которым можно применить полнотекстовое индексирование. Это не обеспечивает пользователю органичной стыковки, при которой он мог бы сочетать полнотекстовые и обычные структурированные реляционные запросы.

Некоторые реляционные системы управления базами данных сейчас предоставляют пользователям возможность задавать полнотекстовые и реляционные условия, органично объединяя их в одном запросе. Давайте посмотрим, как может выглядеть такой запрос. Допустим, содержимое простейших, неструктурированных текстовых документов находится в столбце DocText таблицы, названной 'doc_collection', а, кроме того, эта таблица имеет столбцы для атрибутов документа: StorName, Size и DocAuthor. Тогда должно быть можно послать запрос следующего вида:

SELECT Q.StorName, Q.Size, Q.DocAuthor, W.Citizenship

FROM doc_collection as Q,

     writers as W

WHERE CONTAINS(DocText, ' "SQL Server" NEAR() text')

  AND Q.DocAuthor = W.writer_name

который должен вернуть:

-         названия, размеры, имена авторов для всех документов,

-         в которых слова "SQL Server" находятся в непосредственной близости к слову "text",

-         и все такие кортежи будут соединены с данными о гражданстве автора, полученными из таблицы 'writers'.

В последние шесть месяцев мы работали над тем, чтобы такие запросы были возможны. Цель состоит в том, чтобы внедрить в SQL Server 7.0 [KT1] технологию Microsoft Text Search, что должно предоставить пользователям возможность выполнять несложные полнотекстовые запросы над неструктурированными текстовыми данными, хранящимися в реляционных таблицах. Синтаксис этих запросов должен естественным образом расширять средства языка SQL. 

Мы использовали имеющиеся у Microsoft технологии, чтобы дать возможность выполнять полнотекстовый поиск в данных, хранящихся под управлением SQL Server. Технология Microsoft Information Retrieval существовала до нас и уже поставлялась в составе Index Server 2.0 и Site Server 3.0. Мы объединили разные компоненты этих технологий и встроили их в SQL Server 7.0, предоставив пользователям реляционной системы управления базами данных Microsoft средства поддержки полнотекстового поиска. Две сторонние по отношению к SQL Server технологии, которые нам удалось включить в его состав, это: 

·          Microsoft Search Service[1] -- служба полнотекстового индексирования и поиска, которую далее в этом документе мы называем «механизмом индексирования» или «механизмом поиска».

·          Интерпретатор, входящий в состав провайдера OLE DB для Index Server 2.0, который принимает части запроса на SQL, относящиеся к полнотекстовым средствам, и преобразует их в форму, пригодную для исполнения поисковым механизмом.

Этот документ преследует три цели:

·          познакомить с дополнительными средствами языка SQL, предназначенными для поддержки полнотекстового поиска информации, хранящейся в базе данных,

·          показать, как различные технологии были объединены для того, чтобы обеспечить полнотекстовый поиск информации, хранящейся в базе данных,

·          представить новые средства администрирования SQL Server, необходимые для поддержки средств полнотекстового поиска информации, хранящейся в базе данных.

Понятия полнотекстового поиска

Для поддержки полнотекстового поиска неструктурированной текстовой информации в определенной базе данных нужно уметь решать четыре основные задачи:

·          Определять таблицы и столбцы, зарегистрированные для полнотекстового поиска.

·          Индексировать данные в зарегистрированных столбцах. В процессе индексирования просматривается текстовый поток, определяются границы слов (как говорят, производится разбивка на слова), удаляется «мусор» в виде несущественных, незначимых слов (noise-words[2]), а затем оставшиеся слова заносятся в полнотекстовый индекс.

·          Создавать запросы на поиск в зарегистрированных столбцах, для которых заполнены полнотекстовые индексы.

·          Следить за тем, чтобы последующие изменения в зарегистрированных столбцах передавались механизму индексирования, чтобы полнотекстовые индексы всегда были согласованы с данными.

Для реализации вышеописанных процедур индексирования, выполнения запросов и обновления принципиально важно, чтобы в каждой таблице, регистрируемой для полнотекстового поиска, существовал простой первичный ключ, то есть была одна колонка, значение которой однозначно идентифицировало бы всю строку. Полнотекстовый индекс содержит входы для всех значимых слов в каждой строке и значение, содержащееся в ключевой колонке на пересечении с этой строкой.

При обработке полнотекстового запроса поисковый механизм возвращает значение ключа для строки, которое совпадает с критерием поиска для SQL Server. Происходящее лучше объяснить на простом примере. Допустим, есть таблица SciFi, имеющая нижеследующую структуру, в которой колонка Book_No содержит первичные ключи:

Book_No

Writer

Title

A025

Asimov

Foundation's Edge

A027

Asimov

Foundation and Empire

C011

Clarke

Childhood's End

V109

Verne

Mysterious Island

Предположим далее, что у нас есть полнотекстовый запрос, с помощью которого мы хотим найти названия книг, включающие слово "Foundation". Когда реляционный механизм SQL Server встречает предикат полнотекстового поиска, он вызывает поисковый механизм, который находит значения  Book_No для строк, удовлетворяющих условию запроса. В нашем случае возвращаются значения A025 и A027. Затем реляционный механизм использует эту информацию совместно с другой, находящейся в ее прямом распоряжении, чтобы ответить на запрос.

В отличие от «классических» реляционных индексов, применяемых в базах данных, традиционные полнотекстовые индексы не обновляются сразу же после изменения содержимого зарегистрированных полнотекстовых столбцов или после добавления и удаления строк в зарегистрированных таблицах. Чаще всего полнотекстовые индексы обновляются асинхронно. На то есть две причины:

·          Обновление полнотекстового индекса обычно требует значительно больше времени, чем обновление классического.

·          Полнотекстовый поиск является нечетким по своей природе и результаты его не обязательно должны быть столь же точны, как в классическом случае.

Во время обновления полнотекстовых индексов уникальное значение ключевого столбца передается механизму индексирования, чтобы указать ему, какие данные требуется индексировать заново. Например, если содержимое поля Title, соответствующее значению ключа V109, будет исправлено на 'Mystery Island', индекс надо будет обновить, отразив в нем это изменение.

Процесс администрирования полнотекстовой системы начинается с объявления таблиц и столбцов, подлежащих полнотекстовому поиску. Для их регистрации можно использовать графические интерфейсы пользователя (GUI) с мастером подсказок или встроенные хранимые процедуры. Затем – отдельно -- посылается запрос на заполнение полнотекстовых индексов (вновь с помощью GUI или хранимых процедур). 

В конечном счете, запускается механизм индексирования и начинается асинхронный процесс индексирования. Полнотекстовое индексирование состоит из регистрации того, какие значимые слова встречаются и где. Например, полнотекстовый индекс может показывать, что слово 'Microsoft' встретилось под номерами 423 и 982 в столбце 'Abstract' таблицы 'DevTools' в строке, в которой 'ProductID’, имеет значение 6. Такая индексная структура позволяет эффективно отыскивать все поля, содержащие индексированные слова, и выполнять более сложные поисковые операции типа поиска выражений или близко расположенных элементов текста. Пример поиска выражения – поиск словосочетания белый слон, то есть таких мест, где за словом «белый» сразу следует слово «слон». Пример поиска близко расположенных слов – поиск мест, в которых слово «большой» встречается вблизи слова «дом». Чтобы предохранить полнотекстовый индекс от замусоривания, малозначительные слова, не помогающие поиску -- такие как a, and, the -- игнорируются. Списки таких слов уже составлены для многих языков, и число поддерживаемых языков растет. Выбор того или иного списка незначимых слов основан на том, на какой язык настроен сервер базы данных. Эти списки вполне достаточны для нормальной работы, а для специальных случаев их можно изменять. Списки расположены в известных местах и администратор может переделывать любой из них с помощью обычного редактора текстов. Например, компьютерные фирмы могут пожелать добавить к списку незначимых слово «компьютер».

Для того чтобы пользователи смогли давать полнотекстовые запросы, необходимо было расширить язык Transact-SQL. Нам удалось приспособить для этой цели синтаксис предикатов CONTAINS и FREETEXT, которые уже поддерживались провайдерами Microsoft OLE DB в двух реализациях: в Index Server 2.0 и в Site Server 3.0 Search. 

Предикат CONTAINS используется для поиска:

·          слова или выражения

·          начальной части слова или выражения

·          слов или выражений, расположенных вблизи друг друга

·          словоформ (например, от drive производится drives, drove, driving, driven)

·          набора слов или выражений, каждому из которых присвоен свой «весовой коэффициент».

 

Предикат FREETEXT – простая форма запроса на естественном языке. В запросе можно указать любой текст: слово, выражение или предложение. Поисковый механизм будет искать соответствие смысла, а не совпадение слов.

 

Реляционный механизм SQL Server распознает CONTAINS и FREETEXT и производит некоторые синтаксические и семантические проверки – смотрит, например, зарегистрирован ли столбец, упомянутый в предикате, для полнотекстового поиска. В процессе выполнения запроса полнотекстовый предикат и относящаяся к нему информация передаются компоненту Full-Text Query. После дальнейшей синтаксической и семантической проверки запускается поисковый механизм, который возвращает набор ключей, идентифицирующих те строки в таблице, содержимое которых удовлетворило условиям полнотекстового запроса.

В настоящее время администратор имеет два механизма, позволяющие приводить полнотекстовый индекс в соответствие с изменениями данных в соответствующей таблице:

·          Можно потребовать обновить индекс в любой момент.

·          Обновление индекса можно производить по расписанию.

Для обоих вариантов предусмотрены графические интерфейсы и хранимые процедуры. Если в таблице есть столбец, содержащий данные типа TIMESTAMP, можно заказать инкрементное обновление индекса, при котором будут учтены только изменения, происшедшие с момента предыдущего обновления. Если в таблице нет столбца типа TIMESTAMP, то можно только создать индекс заново.

В следующих версиях предполагается реализовать альтернативное решение, при котором полнотекстовые индексы будут обновляться автоматически на основе протокола изменений.

Полнотекстовые запросы в Transact-SQL

Прежде всего имеет смысл повторить, что расширения, внесенные в язык, согласованы с тем, как реализована поддержка SQL для полнотекстового поиска в Index Server 2.0. Более того, поддержка полнотекстового поиска в SQL следует предложенной в ISO SQL-3 функциональной методологии расширения синтаксиса для этой цели.

Прежде всего, в Transact-SQL добавлены новые предикаты CONTAINS и FREETEXT. Они используются для поиска в столбцах значений, удовлетворяющих специальным полнотекстовым критериям запроса.

Кроме того, поддерживаются новые функции ContainsTable() и FreetextTable(). Эти функции, которые можно использовать в обороте FROM, возвращают таблицу из двух столбцов: один содержит уникальное значение, идентифицирующее строку, в которой обнаружено совпадение с заданным критерием полнотекстового запроса, а другой содержит оценочное значение, показывающее, насколько хорошо данные в строке совпали с критерием.

Займемся сначала новыми предикатами. Чтобы следовать практике, принятой при описании аналогичных возможностей в других продуктах, и обеспечить расширение этих предикатов в будущем, мы избрали функциональную нотацию. Синтаксис высокого уровня таков:

 ●─┬CONTAINS┬─(column_ref[s]──,ft_search_condition)──●

   └FREETEXT┘

 

В SQL Server 7.0 язык всегда находится под влиянием локальных установок, определенных для той или иной базы данных. Гибкий функциональный стиль этих двух предикатов позволит в будущем легко ввести совместимое снизу вверх дополнение в виде третьего параметра, указывающего, какой национальный язык имеется в виду в этом запросе.

Эти предикаты можно использовать с типами данных «символьного семейства». Под «символьным семейством» мы имеем в виду CHAR, VARCHAR, TEXT, NCHAR, NVARCHAR и NTEXT. В настоящее время содержимое сложных текстовых документов, которые часто хранят в столбцах с типом данных, принадлежащим к «двоичному семейству», пока нельзя индексировать и запрашивать. Возможность поддержки таких решений будет рассматриваться в следующих за SQL Server 7.0 версиях.

Предикат CONTAINS

Этот предикат используется для того, чтобы определить, содержат или нет данные, хранящиеся в зарегистрированном для полнотекстового использования столбце, определенные слова и выражения. В настоящее время этот предикат можно применять только к основным таблицам.

Предикат имеет следующий синтаксис:

   ●──CONTAINS──(─┬─column_ref─┬──────────────────────>

                  └─*──────────┘

   >──,──'──contains_condition──'──)─────────────────●
 

 

   contains_condition:

   ●──┬──┬──simple_term──────┬─────┬──────────────────>

      │  ├──prefix_term──────┤     │

      │  ├──proximity_term───┤     │

      │  ├──generation_term──┤     │

      │  └──weighted_term────┘     │

      │                            │

      └──(──contains_condition──)──┘

     ┌──────────────────────────────────────────────┐

     v                                              │

   >──┬────────────────────────────────────────────┬┴─●

      └──┬─OR──────┬──┬─┬──simple_term──────┬────┬─┘

         ├─AND─────┤  │ ├──prefix_term──────┤    │

         └─AND NOT─┘  │ ├──proximity_term───┤    │

                      │ ├──generation_term──┤    │

                      │ └──weighted_term────┘    │

                      │                          │

                      └─(── contains_condition─)─┘

  где:

column ref  или  * Идентифицируют столбец или столбцы, в которых ведется поиск.

column ref   Конкретный столбец, зарегистрированный для полнотекстового использования.

*                     Все столбцы в таблице, зарегистрированные для полнотекстового использования. 

simple_term, prefix_term, proximity_term, generation_term, и weighted_term будут объяснены ниже.

AND, OR и NOT – то, чего и следует ожидать (см. ниже).

simple_term:

Точное символьное значение (слово или выражение), которое надо найти. 

Синтаксис:

   ●──┬─word──────────┬────────────────────●

      │               │
      └─"──phrase──"──┘

где:

word  — один или несколько символов без пробелов и знаков препинания.

phrase  — несколько слов, разделенных пробелами.

В соответствии с нормами, принятыми в продуктах такого рода, поиск всегда производится с учетом регистра символов в слове или выражении.  

Примеры применения simple_term в контексте предиката CONTAINS в обороте WHERE:

WHERE CONTAINS( context_col, 'hockey' )

WHERE CONTAINS( context_col, ' "ice hockey" ')

Допустим, имеется строка, в которой на пересечении со столбцом context_col записано “This is a dissertation on the use of frozen meadow muffins as hockey pucks”, и другая строка, содержащая значение "Dissertation on new ways of splitting the atom".  При этом “this”, “is”, “a” и т. д. скорее всего будут сочтены незначимыми словами и не попадут в полтотекстовый индекс. Поэтому запрос с предикатом CONTAINS вида:

   CONTAINS (context_col, '"this is a dissertation"')

будет эквивалентен:

   CONTAINS (b_column, 'dissertation')

и вернет обе строки, как соответствующие условию. Причина в том, что в первом запросе слова “this”, “is” и  “a” тоже будут выброшены до начала выполнения. 

Сочетание термов

Как и для других условий поиска, применяемых в SQL, более сложные условия можно определить посредством связывания отдельных операндов булевыми операторами. В данном случае операндами могут быть термы любого из обсуждаемых типов. За исключением того что комбинация OR NOT не поддерживается, а NOT не может предшествовать самому первому терму, правила в точности совпадают с теми, которые используются при объединении предикатов в условиях поиска. Например, для того чтобы изменить обычный приоритет операторов, можно ставить скобки.

Ниже следуют примеры сочетания термов simple_term в предикате CONTAINS в обороте WHERE:

WHERE CONTAINS( context_col, 'hockey OR curling' )

WHERE CONTAINS( context_col, 'hockey AND NOT field')

WHERE CONTAINS( context_col,

                ' ("ice hockey" OR curling) AND NOT

                  Canada ' )

prefix_term:

Слово или выражение, с которых должен начинаться искомый текст.

Синтаксис:

   ●──┬─"──word──*──"────┬───────────────────●

      │                  │
      └─"──phrase──*──"──┘

Каждый prefix_term состоит из simple_term, за которым следует звездочка.  Текст, идущий до звездочки, будет участвовать в сравнении. В данном случае, символ * напоминает символ % в предикате LIKE: ему удовлетворяют ноль, один или более любых символов. В случае выражения каждое слово в нем рассматривается как префикс -- например, терму "local bus *" удовлетворят выражения "locality busy",  "local bush" и "locale bust".

Ниже следуют примеры prefix_term, используемых в контексте предиката CONTAINS в обороте WHERE:

WHERE CONTAINS( context_col, ' "atom*" ' )

 Этому условию удовлетворяют значения в столбце context_col, начинающиеся с 'atom':  ‘atom’, 'atomic', 'atomism', 'atomy' и т.д.

WHERE CONTAINS( abstract, ' "wine*" OR "vine*" ')

  Этому условию удовлетворяют значения в столбце abstract, содержащие слова 'wine' или 'vine' или слова, начинающиеся с них, такие как 'winery', 'wines', 'vineyard' или 'vinegar'.


proximity_term:

Используется, чтобы показать, что искомые слова или выражения должны быть расположены вблизи друг от друга.

Синтаксис:

                       ┌────────────────────────────┐                                              

                       v                            │

   ●─┬─simple_term_1─┬──┬─NEAR()─┬┬─simple_term_n─┬─┴─●

     │               │  └ ~ ─────┘│               │
     └─prefix_term_1─┘            └─prefix_term_n─┘

Терм proximity_term аналогичен по действию оператору AND в том смысле, что все перечисленные слова должны присутствовать одновременно. Однако в отличие от AND,  совпадение с условиями запроса будет оцениваться тем выше, чем ближе они расположены друг к другу.

Синтаксис разработан с учетом добавления в перспективе спецификации единицы измерения близости (в словах, предложениях, параграфах, главах и т.д.).

NEAR() и ~ означают одно и то же: слово или выражение в левой части оператора должны находиться вблизи от того, что стоит в его правой части. Что значит, вблизи? Ответ намеренно приблизителен. Можно считать, что это примерно 50 слов, но алгоритм более сложен. Слова в одном предложении считаются расположенными на расстоянии 1 друг от друга, а «зазоры» между предложениями, абзацами и главами считаются несколько более длинными. Даже если искомые слова и выражения находятся очень далеко друг от друга, строка все равно считается удовлетворяющей запросу, просто она получит очень низкую (нулевую) оценку. Однако, если contains_condition состоят только из терма с NEAR(), то SQL Server не будет включать в ответ строки, получившие оценку ноль.

Мишени для поиска этого типа можно задавать «цепочкой» -- например:

   a ~ b ~ c

значит, что a должно быть вблизи b, а b – вблизи c.

Из-за нечеткого характера полнотекстового поиска, часто бывает желательно видеть вышеупомянутые оценки совпадения. Функция ContainsTable(), которая будет описана ниже, позволяет выполнять запросы, сообщающие оценки для каждой найденной строки. 

 

Ниже следуют примеры использования proximity_term в контексте предиката CONTAINS в обороте WHERE:

WHERE CONTAINS( context_col, ' hockey ~ player ' )

  Этому запросу соответствуют значения context_col, в которых слово 'hockey' соседствует со словом ‘player'.

WHERE CONTAINS( context_col, ' hockey ~ "play*" ')

     Этому запросу соответствуют значения context_col, в которых слово 'hockey' соседствует со словом, начинающимся с 'play'.

WHERE CONTAINS( context_col, '  "great*"

                              ~ "Maurice Richard" ')

     Этому запросу соответствуют значения context_col, в которых слово, начинающееся с ‘great' соседствует с выражением "Maurice Richard".

generation_term

Означает лингвистическое родство. Используется, чтобы показать, что запросу могут удовлетворять грамматические формы указанного слова.

Синтаксис:                      

                               ┌──────────────┐                                               

                               v              │ 

   ●──FORMSOF──(──INFLECTIONAL───,simple_term─┴─)──●

    

Ключевое слово INFLECTIONAL означает, что запросу будут удовлетворять единственное и множественное число существительного или различные временные формы глагола.  Единственный такой терм не будет находить как формы, свойственные только глаголам, так и формы, свойственные только существительным. Опять-таки, синтаксис может быть дополнен так, чтобы обрабатывались и другие лингвистические формы – например, производные слова, омонимы или синонимы.

 

Ниже следует пример использования generation_term в контексте предиката CONTAINS в обороте WHERE:

WHERE CONTAINS(curriculum_vite,

               ' FORMSOF (INFLECTIONAL, skate) ' )

 Этому запросу соответствуют значения curriculum_vite, в которых содержатся такие слова как 'skate', 'skates', 'skated' и 'skating'.

weighted_term

Используется в запросах, возвращающих строки таблиц, содержащие слова и выражения из списка, в котором каждой цели [KT2] поиска дополнительно может быть придан весовой коэффициент. Для того чтобы строка удовлетворила условию запроса достаточно, чтобы в ней нашелся хотя бы один элемент из списка.

Синтаксис:

   ●──ISABOUT─────────────────────────────────────────>

        ┌──,──────────────────────────────────────┐                                              

        v                                         │ 

   >──(──┬─simple_term─────┬──┬──────────────────┬┴─)─●

         ├─prefix_term─────┤  └─WEIGHT─(─n.nnn─)─┘

         ├─proximity_term──┤

         └─generation_term─┘

где:

n.nnn — постоянное число от 0 до 1.

Строка возвращается в том случае, если в ней обнаружен хотя бы один из элементов ISABOUT.

Каждому компоненту вектора может быть дополнительно приписан весовой коэффициент WEIGHT. Он повлияет на весовой коэффициент, присваиваемый найденной строке.

Ниже следуют примеры использования weighted_term в контексте предиката CONTAINS в обороте WHERE:

WHERE CONTAINS( article,

                ' ISABOUT(hockey, puck, goalie) ' )

 Этому запросу соответствуют значения столбца article, в которых содержится любое из слов 'hockey', 'puck' или 'goalie', причем лучшими будут считаться те строки, в которых найдено более одного из этих слов.

WHERE CONTAINS( article,

         'ISABOUT("Toronto Maple Leafs" WEIGHT(1.0),

                  "Maple Leafs" WEIGHT(.5),

                  Leafs WEIGHT(.2) )

         ' )

 Этому запросу соответствуют значения столбца article, в которых может содержаться информация о хоккейной команде Toronto Maple Leafs, причем лучшими будут считаться те строки, в которых обнаружится больше слов, входящих в ее название.

Предикат FREETEXT

Предикат FREETEXT используется для того, чтобы определить, соответствует ли содержимое  зарегистрированного для полнотекстового поиска столбца смыслу, а не дословному значению того, что указано в предикате.

Синтаксис:

   ●──FREETEXT──(─┬─column_ref─┬──────────────────────>

                  └─*──────────┘

   >──,──'──freetext_string──'──)─────────────────────●

Это очень простая реализация запроса на естественном языке, при выполнении которого поисковый механизм разобьет freetext_string на слова, то есть на некоторое число термов для поиска, построит по ним словоформы, присвоит каждому терму некоторый эвристический весовой коэффициент и затем найдет строки, соответствующие получившемуся запросу.

Ниже следуют примеры использования предиката FREETEXT в обороте WHERE:

WHERE FREETEXT(articles, ' Who have been the most 

    valuable players for the Montreal Canadien? ' )

Сочетания предикатов и их использование

Поскольку CONTAINS и FREETEXT являются предикатами SQL, их можно использовать в любом условии поиска. В частности, их можно сочетать друг с другом и с другими предикатами, такими как равенство, LIKE и BETWEEN, чтобы задавать сложные условия.   

Оборот WHERE в нижеследующем запросе использует предикат CONTAINS вместе с предикатом сравнения. Он возвращает название и год издания для всех книг в таблице 'titles' базы данных 'pubs', которые стоят меньше, чем $20.00, а текст в столбце 'notes' показывает, что эта книга – о хоккее на льду.

SELECT title, DatePart(year, pubdate)

  FROM pubs

  WHERE price < 20.00

    AND CONTAINS (notes, ' "ice hockey" ')

 

В следующем примере запроса CONTAINS используется внутри подзапроса. Запрос возвращает названия всех книг в таблице 'titles', издатель которых расположен вблизи «летающей тарелки» в Moonbeam, Ontario. Известно, что информация об этом издателе есть в столбце 'pr_info' таблицы 'pub_info', причем существует только один такой издатель.

SELECT T.title, P.pub_name

  FROM publishers P,

       Titles T

  WHERE P.pub_id = T.pub_id

    AND P.pub_id = (SELECT pub_id

                      FROM pub_info

                      WHERE CONTAINS

                              (pr_info,

                               ' moonbeam AND

                                 ontario AND

                                 "flying saucer"

                               ') )

Функция ContainsTable()

Функция ContainsTable() используется для выполнения полнотекстовых запросов типа "contains", которые возвращают оценку соответствия для каждой строки.

Синтаксис:

  ●──CONTAINSTABLE──(──table_ref───,─┬─column_ref─┬────>

                                   └─*──────────┘

   >──,──'──contains_condition──'──)─────────────────●

 

где:

table_ref  — таблица, зарегистрированная для полнотекстового поиска

column_ref  — столбец, зарегистрированный для полнотекстового поиска

или

*  Все столбцы в таблице, зарегистрированные для полнотекстового поиска.

contains_condition — то же самое, что было описано для предиката CONTAINS

Хотя и предикат CONTAINS, и функция ContainsTable() используются для сходных по смыслу полнотекстовых запросов, а синтаксис SQL, используемый для спецификации условий поиска, в них один и тот же, есть большая разница в том, как они используются:

1.     CONTAINS() возвращает логическое значение (истина/ложь), поэтому он обычно используется в обороте WHERE оператора SELECT.

ContainTable() возвращает таблицу из нуля, одной или более строк, поэтому она всегда используется в обороте FROM.

2.     CONTAINS() может быть использован только для того, чтобы задавать критерии выборки, по которым SQL Server определит принадлежность членов к результирующему множеству.

ContainsTable()  также используется для того, чтобы задавать критерии выборки. Возвращаемая ей таблица имеет столбец, называемый KEY, который содержит значения «полнотекстового ключа». Каждая таблица, зарегистрированная для полнотекстового поиска, должна иметь ключевой столбец, значения которого гарантировано уникальны. Значения, возвращаемые в столбце KEY, являются значениями этого «полнотекстового ключа» для строк, соответствующих критериям выборки, заданными в contains_conditionКроме того, таблица, возвращаемая функцией ContainsTable(), имеет столбец под названием RANK, содержащий число в диапазоне от 0 до 1000. Это число показывает, насколько хорошо строка удовлетворила критерию выборки.

Запросы, использующие функцию ContainsTable(), более сложны, чем те, которые используют предикат CONTAINS, поскольку необходимо в явном виде задать реляционное соединение строк, возвращенных ContainsTable(), со строками в table_ref. Воспользуемся примером из раздела «Введение», чтобы показать, как следует писать такие запросы. В этом примере содержимое неких документов находится в столбце  DocText таблицы 'doc_collection', которая кроме этого содержит столбцы StorName, Size и DocAuthor. Уникальный ключ для этой таблицы находится в столбце DocNo. Мы хотели бы, чтобы строки в результирующем множестве были упорядочены так, чтобы те из них, которые имеют наибольшее значение RANK, возвращались первыми. Дополнения к первоначальному запросу ниже выделены жирным шрифтом.

SELECT Q.StorName, Q.Size, Q.DocAuthor, W.Citizenship

FROM doc_collection as Q,

     writers as W,

     ContainsTable(doc_collection, DocText,

                   ' "SQL Server" NEAR() text'

                  ) AS K

WHERE Q.DocAuthor = W.writer_name

  AND K.[KEY] = Q.DocNo

ORDER BY K.RANK DESC

Чтобы упростить использование функции ContainsTable() в запросах, использующих одну таблицу и не требующих группировки, мы рекомендуем применять постоянную заготовку следующего вида:

 

SELECT select_list ,KEY_TBL.RANK

FROM table_ref AS FT_TBL

CONTAINSTABLE (     table_ref

                ,   { column_ref | * }

                , ' contains_condition ' )

) AS KEY_TBL

WHERE FT_TBL.key_column = KEY_TBL.[KEY]

      AND predicate  ...

ORDER BY KEY_TBL.RANK DESC

 

Пояснения:

Затенено

Всегда присутствует в точности как написано

 

Жирный курсив

Заменить на нужное значение

 

СЕРЫЕ_ЗАГЛАВНЫЕ

Может отсутствовать, но если есть, то в точности как написано

 

Предикат ...

Может отсутствовать. Задает предикат, дополнительно фильтрующий строки, возвращаемые функцией ContainsTable()

Следующий пример основан на этой заготовке. В нем текст таблички в Зале хоккейной славы находится в столбце PlaqueWording таблицы HockeyHall, которая, кроме того, содержит столбцы PlayerName, StartYear и LastYear. Уникальный ключевой столбец называется PlaqueNo. Мы хотим получить PlayerName, PlaqueNo и RANK для хоккеистов, которые играли за команду Kenora в начале века. Наилучшие соответствия будут возвращаться первыми.

SELECT PlayerName, PlaqueNo, KEY_TBL.RANK

FROM HockeyHall AS FT_TBL

     CONTAINSTABLE(HockeyHall, PlaqueWording,

                   ' Kenora OR "Rat Portage" '

                  ) AS KEY_TBL

WHERE FT_TBL.PlaqueNO = KEY_TBL.[KEY]

  AND StartYear < 1915 AND EndYear > 1899

ORDER BY KEY_TBL.RANK DESC

Функция FreetextTable()

Используется для полнотекстовых запросов типа "freetext" и возвращает оценку соответствия для каждой найденной строки.

Синтаксис:

   ●──FREETEXTTABLE──(─table_ref───,─┬─column_ref─┬───>

                                     └─*──────────┘

   >──,──'──freetext_string──'──)─────────────────────●

Эта функция используется таким же образом, как и ContainsTable(), а условия поиска для нее задаются как для предиката FREETEXT.

Текстовые запросы для данных, хранящихся в файловой системе

Этим запросам посвящен отдельный документ. 

Важно иметь в виду, что такой механизм тоже существует, поэтому мы сообщим здесь начальные сведения о нем.

Кроме того, важно отметить, что возможность поиска данных в файловой системе сегодня уже реализована в Index Server 2.0. В SQL Server 7.0 она еще более усовершенствована. Процессор распределенных запросов (Distributed Query Processor) совместно с провайдером Microsoft OLE DB для Index Server 2.0 может создавать запросы на поиск данных, хранящихся в файловой системе, по признаку наличия определенных свойств, наряду с запросами на поиск данных в полнотекстовом режиме, а затем объединять результаты с информацией из базы данных. Подробное обсуждение этой темы является предметом другого документа.

Сейчас, в этом документе, мы покажем, как задаются такие запросы, изменив первый рассмотренный в ней пример так, чтобы некоторые данные поступали из файловой системы.  Следующий запрос:

-         Выбирает имена, размеры и авторов из всех файлов  Microsoft Word на диске D

-         Для тех документов, в которых выражение "SQL Server" содержится вблизи слова "text"

И соединяет их с таблицей 'writers', чтобы получить сведения о гражданстве автора.

SELECT Q.FileName, Q.Size, Q.DocAuthor, W.Citizenship

FROM OpenQuery(MyLinkedServer,

               'SELECT FileName, Size, DocAuthor

                from SCOPE('' "D:\" '')

                WHERE CONTAINS(''"SQL Server"

                                 NEAR() text'')

                AND FileName LIKE ''%.doc%'' '

              ) as Q,

     writers as W

WHERE Q.DocAuthor = W.writer_name

Из текста запроса очевидно, что его составителю должно быть известно, где находятся данные. Организация по стандартизации ISO SQL работает над определением нового типа данных DATALINK, который сделает возможными органичные запросы с доступом к информации, находящейся как внутри, так и вне базы данных. Это даст некоторые интересные возможности.

 

 

 

 

Компонентная архитектура полнотекстового индексирования

У компонентной архитектуры есть две составляющие: Query Components (компоненты, связанные с запросами) и Indexing Components (компоненты, связанные с индексированием).  Query Components будут обсуждаться в следующем разделе.

Indexing Components управляют начальным заполнением полнотекстовых индексов и их последующим обновлением.

Перед тем как обсуждать последовательность шагов процесса индексирования, мы представим различные субкомпоненты. Затем будет описано их взаимодействие.

SQL Server Enterprise Manager User Interface. Это графический интерфейс пользователя для утилиты, с помощью которой администрируется полнотекстовое индексирование. Он состоит из дополнения к набору вкладок, определяющих свойства SQL Server Enterprise Manager, и нового мастера подсказок. Все это предназначено для начинающих администраторов полнотекстовой              подсистемы или для тех, кто редко занимается ею. Тем не менее, GUI полезен и для опытных пользователей. С его помощью можно указать таблицы, предназначенные для полнотекстового индексирования, и проделать последовательность шагов по настройке.

Одна из возможностей – назначить расписание для регулярного обновления полнотекстовых индексов на основе имеющихся в SQL Server средств планирования и выполнения заданий. Кроме того, с помощью GUI можно посмотреть свойства индексируемых таблиц. Этот интерфейс использует набор новых хранимых процедур и свойств, доступных через функции SQL Server для работы со свойствами, а также существующий планировщик SQL Server Agent Job Scheduler.

Хранимые процедуры системы администрирования полнотекстового поиска.  Этот набор системных хранимых процедур используется для:

-         создания полнотекстовых каталогов (full-text catalog), используемых для хранения полнотекстовых собраний.

-         регистрирования таблицы и некоторых ее столбцов для полнотекстового поиска.

-         запрашивания заполнения индексов, хранящихся в  полнотекстовом каталоге.

-         Отмены любого из перечисленных действий и возврата к начальному состоянию.

Именно эти процедуры, а не GUI, занимаются установкой и конфигурированием полнотекстового индексирования. Опытный администратор может предпочесть пользоваться ими непосредственно, а не через SQL Server Enterprise. Эти хранимые процедуры можно вызывать из сценариев и из других хранимых процедур.

Выполнение хранимых процедур по расписанию.  Для планирования выполнения процедур обновления полнотекстовых каталогов по расписанию можно использовать тот же набор хранимых процедур (таких как sp_add_jobschedule), который используется для планирования всех остальных заданий.


Компонентная архитектура полнотекстового индексирования

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



Дополнения для поддержки полнотекстового поиска, внесенные в системные таблицы.  Системный каталог 'sysdatabases' дополнен свойством IsFulltextEnabled, значение которого можно получить с помощью функции DatabaseProperty().

В каждой базе данных появилась новая системная таблица 'sysfulltextcatalogs'. В ней хранятся метаданные обо всех полнотекстовых каталогах, присоединенных к этой базе данных. Обратите внимание, что каждый полнотекстовый каталог присоединяется к одной и только к одной базе данных.

Таблицы 'sysobjects', 'sysindexes' и 'syscolumns', находящиеся в каждой базе данных, дополнены информацией о таблицах и столбцах в них, в которых возможен полнотекстовый поиск. В ее состав входит следующее:

-         столбец 'ftcatid' в каждой строке, описывающей таблицу пользователя в 'sysobjects', указывает на строку в 'sysfulltextcatalogs'.

-         свойство TableHasActiveFulltextIndex, значение которого можно узнать с помощью функции ObjectProperty().

-         свойство TableFulltextIKeyColumn, представляющее собой идентификатор столбца, содержащего уникальные полнотекстовые ключи. Его значение можно узнать с помощью функции ObjectProperty().

-         свойство TableFulltextCatalogId, представляющее собой идентификатор полнотекстового каталога, связанного с этой таблицей. Его значение можно узнать с помощью функции ObjectProperty().

-         свойство IsFulltextKey, значение которого можно узнать с помощью функции IndexProperty().

-         свойство IsFulltextIndexed , значение которого можно узнать с помощью функции ColumnProperty().

Microsoft Search Service. [3]  Это служба Microsoft Windows NT®, выполняющая две функции:

·          Indexing Support (поддержка индексирования) принимает запросы на заполнение полнотекстового индекса для данной таблицы.

·          Querying Support (поддержка запросов) обрабатывает полнотекстовые запросы. Она будет описана ниже.  

Microsoft Search Service работает в контексте учетной записи локальной системы. Эта служба должна работать на том же компьютере, на котором работает сам SQL Server.

Поддержка индексирования. Информация о заполнении полнотекстовых индексов передается в форме значения population start seed, которое однозначно указывает и базу данных, и таблицу, которую надо индексировать. Когда служба готова заниматься заполнением, она вызывает драйвер SQL Server.

Драйвер SQL Server.  Этот компонент, входящий в состав Indexing Support, специально написан для того, чтобы управлять SQL Server. Он всегда  работает в том же процессе, что и Microsoft Search Service.

Механизм индексирования.  Этот компонент получает на вход подлежащие индексированию единицы текста (в форме символьных строк), каждую вместе с идентифицирующим ключом. Он просматривает строку, определяет границы слов, удаляет незначимые слова, а оставшимися словами заполняет полнотекстовый индекс.

Поддержка запросов.  Используется для обработки полнотекстовых запросов и пока не будет описываться.

Полнотекстовые каталоги.  Представляют собой места хранения полнотекстовых индексов. Это оглавления файловой системы, доступ к которым имеет только системный администратор и Microsoft Search Service. Полнотекстовые индексы организованы в полнотекстовые каталоги, имеющие удобные для пользователя имена. Обычно полнотекстовые индексы для всей базы данных хранятся в одном каталоге. Тем не менее, администратор может разбить их на несколько каталогов. Это особенно удобно в тех случаях, когда полнотекстовому индексированию подвергаются таблицы с очень большим количеством строк. Полнотекстовый каталог может хранить данные для не более чем 231 (64K) строк.

В SQL Server 7.0 нет средств координации процедур защитного копирования и восстановления самой реляционной базы данных и относящихся к ней индексов в полнотекстовых каталогах, однако, есть средства для приведения их вновь в согласованное состояние. Совместное защитное копирование и восстановление планируется включить в следующие версии.

 

Порядок администрирования полнотекстового поиска

Все нижеследующие шаги относятся к администрированию через GUI или с помощью хранимых процедур (как непосредственно, так и по расписанию). 

№0    Предварительные шаги состоят в том, чтобы разрешить полнотекстовый поиск во всей базе данных, а затем указать таблицы и столбцы, подлежащие полнотекстовому индексированию. Эта информация хранится в системных таблицах SQL Server.

№1    Когда таблица активируется для полнотекстового поиска, в службу  Indexing Support передается population start seed для нее.

№2    На следующем шаге запрашивается начальное заполнение индекса для таблицы. На самом деле, минимальной единицей обработки является полнотекстовый каталог, поэтому, если к нему присоединено более одной таблицы, результатом такого запроса станет заполнение полнотекстовых индексов для всех присоединенных к каталогу таблиц.

№3    Сами таблицы и строки, подлежащие индексированию, находятся внутри SQL Server, поэтому, когда Indexing Support получает запрос на заполнение полнотекстового каталога, он обращается обратно к SQL Server, чтобы получить данные из всех столбцов таблицы, которые надо проиндексировать. По мере поступления данных, они передаются в Index Engine, которая разбивает их на слова, удаляет «мусор» и заполняет индекс.

№4    Как обеспечивается актуальность полнотекстовых индексов? Предусмотрен GUI, который помогает создавать расписание периодических обновлений полнотекстовых каталогов. Этот GUI использует хранимые процедуры из SQL Server Job Scheduler. Кроме того, обновление можно запустить в любой момент – через GUI или непосредственно, вызвав хранимую процедуру.

Если в таблице есть столбец, содержащий отметку о времени обновления строки (timestamp), обновление может быть организовано более эффективным образом. При построении population start seed для данной таблицы запоминается самое позднее встретившееся в ней время обновления. Когда запрашивается следующее инкрементное заполнение, драйвер SQL Server соединяется с базой данных и запрашивает только те строки, у которых временная отметка сделана позже.

Если во время инкрементного заполнения в каталоге встречается таблица, не имеющая столбца для отметки времени, то индекс для нее создается заново.

Есть два случая, когда индекс создается заново, даже если в таблице есть столбец с отметками времени. Это происходит:

- когда меняется схема таблицы,

- когда таблица активируется для полнотекстового поиска снова.

После индексирования таблицы со столбцом, содержащим отметки времени, самое позднее встретившееся на этот раз время обновления строки запоминается снова.

Поскольку инкрементное обновление относительно мало меняющихся таблиц с отметками времени выполняется намного быстрее, чем полная перестройка индекса, пользователи могут планировать его чаще. При этом следует следить за тем, чтобы не смешивать в одном полнотекстовом каталоге таблицы с отметками времени и без них, поскольку для этих двух групп таблиц лучше задавать отдельные расписания обновления.

№n   Со временем для полнотекстового поиска будут регистрироваться все новые таблицы и столбцы и для них будут создаваться новые индексы. Вполне возможно, что для некоторых таблиц и столбцов полнотекстовый поиск будет отменен, а некоторые полнотекстовые каталоги будут стерты.

 

Компонентная архитектура полнотекстовых запросов

Query Components принимают от SQL Server полнотекстовые предикаты и функции, возвращающие множества строк, преобразуют части предиката во внутреннее представление и направляют его Microsoft Search Service, который возвращает множество удовлетворивших запросу строк. Затем множество строк возвращается SQL Server, а он использует эту информацию для того, чтобы построить результирующее множество, возвращаемое в качестве ответа на запрос.

Реляционный механизм (SQL Relational Engine) принимает предикаты CONTAINS и FREETEXT, а также функции ContainsTable() и FreetextTable(). Во время разбора проверяются некоторые условия – например, зарегистрирована ли запрашиваемая колонка для полнотекстового поиска. Если все оказалось в порядке, то во время выполнения ft_search_condition вместе с информацией о контексте посылается провайдеру полнотекстового поиска (Full-Text Provider). В конце концов провайдер возвращает SQL Server’у множество строк. Оно используется в любых соединениях, требуемых или подразумеваемых первоначальным запросом.

Провайдер полнотекстового поиска разбирает и проверяет ft_search_condition, строит надлежащее внутреннее представление условий полнотекстового поиска и передает его поисковому механизму. Результат возвращается реляционному механизму в виде множества строк, удовлетворивших ft_search_condition. Обращение с этим множеством концептуально аналогично тому, как это сделано при поддержке функций OpenRowset() и OpenQuery(), которые тоже возвращают множества строк.

Microsoft Search Service.  Эта служба рассмотрена выше, при описании компонентной архитектуры полнотекстового индексирования.

Поисковый механизм.  Это компонент, обрабатывающий запросы на полнотекстовый поиск. Он определяет, какие входы в индексе удовлетворяют критерию отбора. Для каждого такого входа возвращается значение уникального ключа и оценка соответствия.

Поддержка индексирования.  Была рассмотрена выше, при описании компонентной архитектуры полнотекстового индексирования.


Компонентная архитектура полнотекстового запроса

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



Процесс обработки полнотекстового запроса

№1    Запрос, содержащий один из полнотекстовых элементов (то есть CONTAINS, FREETEXT, ContainsTable() или FreetextTable), поступает в реляционный механизм SQL Server.

№2    Запросы, содержащие предикаты CONTAINS или FREETEXT, переписываются так, чтобы множества строк, полученные от провайдера полнотекстового поиска, в конце автоматически соединялись с таблицей, над которой работает предикат. Механизм такой перезаписи обеспечивает органичную стыковку этих предикатов с SQL Server. Пользователи, вставляющие CONTAINS и FREETEXT в свои запросы, не должны заботиться о том, как происходит внутренний вызов Microsoft Search Service.

№3    Вызывается полнотекстовый провайдер, которому передается следующая информация:

-         условия поиска ft_search_condition    

-         внутреннее (удобное) имя полнотекстового каталога, в котором находятся полнотекстовые индексы для данной таблицы

-         кодированное обозначение языка (используемое, например, для разбивки на слова)

-         ссылки на базу данных, таблицу и столбец.

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

Заметьте, что реляционный механизм SQL не занимается содержимым ft_search_condition. Он передает его полнотекстовому провайдеру, который проверяет его на допустимость и строит внутреннее представление условий для полнотекстового поиска. 

№4    Команда передается компоненту, отвечающему за поддержку запросов (Querying Support).

№5    Querying Support возвращает множество строк, состоящих из уникального значения в ключевой колонке для строки, удовлетворившей условию полнотекстового поиска, и значения оценки соответствия RANK. 

№6    Множество строк передается реляционному механизму SQL. Если выполняется функция ContainsTable() или FreetextTable(), возвращаются значения RANK, в противном случае они убираются из результата. 

№7    Значения из множества строк подставляются в запрос наряду со значениями, полученными из реляционной базы данных, и результирующее множество возвращается пользователю.

Администрирование полнотекстовых индексов

В текущей реализации полнотекстовые индексы довольно сильно отличаются от «классических» для SQL. По этой причине они нуждаются в специальном администрировании, которое будет рассмотрено в этом разделе. Далее следует сводка основных отличий:

Классические индексы SQL

Полнотекстовые индексы

Индексы хранятся в базе данных и управляются СУБД.

Полнотекстовые индексы хранятся в файловой системе, но администрируются через базу данных.  

Может быть несколько индексов для одной таблицы.

Для таблицы может быть определен только один полнотекстовый индекс.

Индексы автоматически обновляются при изменении, добавлении или удалении данных.

Заполнение полнотекстовых индексов происходит по специальному запросу или по расписанию.

Индексы существуют независимо.

Группы (один или более) полнотекстовых индексов к одной базе данных сводятся в полнотекстовый каталог.

Индексы создаются и уничтожаются с помощью операторов SQL.

Полнотекстовые индексы создаются, управляются и уничтожаются с помощью хранимых процедур (непосредственно или через GUI).

Администрирование полнотекстового поиска происходит на нескольких разных уровнях:

·         Сервер.  Некоторые свойства устанавливаются для всего сервера – например, те, которые требуются Microsoft Search Service для инициализации и подготовки индексов к заполнению. 

·         База данных.  При разрешении или запрещении использования полнотекстового поиска для всей базы данных в ней создаются или уничтожаются метаданные для одного или более полнотекстовых каталогов. 

·         Полнотекстовый каталог.  Полнотекстовые каталоги заполняются с помощью средств администрирования.   

·         Таблица.  Таблица должна быть зарегистрирована для полнотекстового поиска. При этом создаются метаданные для ее полнотекстового индекса. До того как зарегистрированная таблица сможет участвовать в очередном заполнении полнотекстового индекса, она должна быть активирована.

·         Столбцы.  Колонки, в которых будет разрешен полнотекстовый поиск, могут добавляться к неактивной зарегистрированной таблице или удаляться из нее.

Для всех этих уровней существуют утилиты, позволяющие узнавать о свойствах, статусе и объеме (например, о размере полнотекстового каталога). Как было показано выше, эти средства имеют вид как GUI, так и хранимых процедур, и почти любая задача может быть выполнена любым из этих двух способов. В силу технической ориентации этого документа мы сосредоточимся на хранимых процедурах и дадим лишь несколько примеров использования GUI. Мы используем термин «хранимые процедуры» скорее для того, чтобы показать, на каком уровне администратор общается с SQL Server. На самом деле, используется сочетание хранимых процедур и функций, возвращающих скалярные значения свойств.

Ниже излагается сценарий, следуя которому администратор, работающий «в режиме хранимых процедур» мог бы выполнить заявку на организацию полнотекстового поиска в выбранных таблицах и столбцах в базе данных 'pubs'.  При описании каждого шага, [серым] цветом помечено, на каком уровне выполняется соответствующее административное действие. Мы не будем демонстрировать все имеющиеся возможности, а только постараемся дать представление о том, как эти процедуры могут быть использованы.

1.     [Сервер]   Убедитесь, что служба Microsoft Search Service запущена. Для этого достаточно посмотреть на форму и цвет значка Full-Text Search в SQL Server Enterprise Manager.

При необходимости служба может быть запущена одним из следующих способов:

-       через контекстное меню из объекта Full-Text Search в SQL Server Enterprise Manager,  

-       снаружи SQL Server -- через Service Control Manager   (обратите внимание, что в Service Control Manager та же служба называется "Microsoft Search Service"),

-       из командного режима MS-DOS® вводом строки "net start mssearch".

-       С помощью SQL Server Service Manager.

В каждом из этих мест служба полнотекстового поиска может быть также и остановлена.

В этом случае 'pubs' еще не была задействована (enabled).

2.     [Сервер]   Проверьте, разрешен ли полнотекстовый поиск в базе данных pubs.  Следующий оператор SQL:

SELECT DatabaseProperty('pubs',

                        'IsFulltextEnabled'  )

вернет 1, если поиск разрешен и 0, если нет.

В этом случае, служба уже запущена.

3.     [Сервер]   Подключитесь к базе данных pubs, выполнив оператор SQL:

USE pubs

4.     [База данных]   Разрешите полнотекстовый поиск в pubs, выполнив следующую хранимую процедуру:

sp_fulltext_database 'enable'

5.      [Каталог]   Создайте полнотекстовый каталог под именем PubsCatalog и в оглавлении, где полнотекстовые каталоги размещаются по умолчанию. Это делается с помощью следующей хранимой процедуры:

sp_fulltext_catalog 'PubsCatalog', 'create'

Эта процедура вносит метаданные о полнотекстовом каталоге в системные таблицы базы данных и создает пустой каталог в файловой системе. Файл создается в корневом оглавлении пути, используемого для хранения полнотекстовых каталогов по умолчанию. Указав третий параметр, его можно было бы создать в другом месте. 

6.     [Таблица]   Зарегистрируйте для полнотекстового поиска таблицы 'authors', 'jobs', 'pub_info' и 'titles'. Регистрируемые таблицы должны иметь столбец (называемый full-text unique key column), значение которого гарантированно-уникально для каждой строки.  Поскольку все перечисленные таблицы имеют простой первичный ключ, все они соответствуют этому требованию.    

При регистрации такой таблицы необходимо указать имя индекса, который гарантирует уникальность значения ключа. Для каждой таблицы его можно узнать с помощью хранимой процедуры sp_help_index. Интересующие нас индексы будут называться так:

 

Authors

UPKCL_auidind

 

Jobs

PK_jobs_22AA996

 

Pub_info

UPKCL_pubinfo

 

Titles 

UPKCL_titleind

Зная эти имена, мы можем теперь зарегистрировать таблицы для полнотекстового поиска. Этого делается с помощью хранимой процедуры sp_fulltext_table, которую надо выполнить для каждой таблицы отдельно:

 

sp_fulltext_table 'authors', 'create',   

           'PubsCatalog', 'UPKCL_auidind'

sp_fulltext_table 'jobs', 'create',   

           'PubsCatalog', 'PK_jobs_22AA996'

sp_fulltext_table 'pub_info', 'create',   

           'PubsCatalog', 'UPKCL_pubinfo'

sp_fulltext_table 'titles', 'create',   

           'PubsCatalog', 'UPKCL_titleind'

В результате выполнения этих команд надлежащие сведения о зарегистрированных таблицах и о полнотекстовом каталоге, в котором будут храниться индексы для них, будут внесены в системные метаданные.

7.     [Столбец]   Для каждой из только что зарегистрированных таблиц укажите имена столбцов, которые должны быть зарегистрированы. Это делается с помощью хранимой процедуры sp_fulltext_column, которую придется выполнить для каждого столбца отдельно:

sp_fulltext_column 'authors', 'address', 'add'    

sp_fulltext_column 'jobs', 'job_desc', 'add'  

sp_fulltext_column 'pub_info', 'pr_info', 'add'  

sp_fulltext_column 'titles', 'type', 'add'

sp_fulltext_column 'titles', 'notes', 'add'      

В результате в системных таблицах появятся дополнительные метаданные. 

Между прочим, мы только что сделали ошибку (намеренно, для иллюстрации): в таблице 'titles' зарегистрирован столбец 'type' вместо 'titles'.  

8.     [Таблица]   До того как будет создан полнотекстовый индекс, таблица должна быть еще и активирована. Это делается вызовом процедуры sp_fulltext_table (один раз для каждой из таблиц):

sp_fulltext_table 'authors', 'activate'    

sp_fulltext_table 'jobs', 'activate'

sp_fulltext_table 'pub_info', 'activate'    

sp_fulltext_table 'titles', 'activate'

Заметьте, что полнотекстовый индекс при этом не создается. Активирование это просто отметка в метаданных полнотекстового каталога, означающая, что эти таблицы надо обработать при следующей операции индексирования.[4]  

9.     [Каталог]   Запустите полную загрузку полнотекстового каталога PubsCatalog с помощью хранимой процедуры sp_fulltext_catalog:

sp_fulltext_catalog 'PubsCatalog', 'start_full'    

Заметьте, что заполнение полнотекстового каталога выполняется асинхронно. Это значит, что после того, как вышеуказанная процедура завершилась и возвратила управление, полнотекстовые индексы, скорее всего, еще не созданы. 

10.    [Каталог]   Узнать о ходе заполнения полнотекстового каталога PubsCatalog можно с помощью следующего оператора:

SELECT FulltextCatalogProperty

( 'PubsCatalog', 'PopulateStatus' )

Оператор возвращает 0, если служба не занимается данным каталогом, а значит (предположительно) работа над ним завершена. Значения 1 или более означают различные стадии заполнения.

11.   [Проверка]   Запустите какой-нибудь SQL-запрос, чтобы убедиться, что административные работы выполнены надлежащим образом. Например, такой:

SELECT P.pub_name, T.title, T.price

  FROM publishers P, titles.T

  WHERE P.pub_id = T.pub_id

    AND P.country = 'England'

    AND CONTAINS (T.notes,

                  '"case is altered" OR

                   "cat and custard pot" OR

                   "the monarch and the sphinx"

                  ' )

12.    [Проверка]   А теперь такой:

SELECT title_id, title, pubdate

  FROM titles

  WHERE CONTAINS (T.title,

                  'classic ~ french ~ cooking')

На этот раз вы получите сообщение об ошибке, поскольку столбец 'title' не был зарегистрирован для полнотекстового поиска.

13.   [Столбец]   Попробуйте выяснить, в чем ошибка. Оператор:

SELECT ColumnProperty ( ObjectId('titles'),

                        'titles',

                        'IsFulltextIndexed' )

вернет 1, если столбец title включен в полнотекстовый индекс для таблицы books и 0, если нет.  В нашем случае, будет возвращено значение 0.

14.   [Таблица]   Получите список столбцов, участвующих в полнотекстовом индексировании таблицы 'titles':

sp_help_fulltext_columns 'titles'

Результат покажет вам причину ошибки: вместо столбца 'title’ в определение полнотекстового индекса включен столбец 'type'.

15.    [Таблица]   Деактивируйте таблицу 'titles', чтобы можно было добавить к списку индексируемых столбцов 'title' и убрать 'type', с помощью следующей хранимой процедуры:

sp_fulltext_table 'titles', 'deactivate'

Это не только позволит добавлять и убирать столбцы, но также исключит таблицу 'titles' из числа таблиц, участвующих в заполнении полнотекстового каталога PubsCatalog. Однако метаданные сохраняются и таблица может быть активирована снова. Существующий полнотекстовый индекс для таблицы 'titles' сохранится до следующей полной загрузки каталога PubsCatalog, но пользоваться им нельзя, поскольку SQL Server отвергает запросы к деактивированным таблицам.

16.   [Столбец]    Добавьте к метаданным для полнотекстового индекса таблицы 'titles’ столбец 'title' и уберите 'type'. Это делается через хранимую процедуру sp_fulltext_column, запускаемую отдельно для каждой операции:

sp_fulltext_column 'titles', 'type', 'drop'

sp_fulltext_column 'titles', 'title', 'add'

17.    [Таблица]   Снова активируйте таблицу книг, запустив хранимую процедуру:

sp_fulltext_table 'titles', 'activate'

Заметьте, что таблица активирована, но индекс не перестроен. Используя старый индекс, можно по-прежнему запрашивать поиск в оставшихся столбцах, но, естественно, не в том, который только что был зарегистрирован. Кроме того, следует иметь в виду, что до перезагрузки индекса данные об убранном столбце будут участвовать в запросах со звездочкой (* -- символ, который, в данном случае, соответствует всем столбцам в таблице, зарегистрированным для полнотекстового использования).

18.   [Каталог]   Теперь запустите инкрементное заполнение полнотекстового каталога PubsCatalog с помощью следующей хранимой процедуры:

sp_fulltext_catalog 'PubsCatalog',

                    'start_incremental'


Инкрементное заполнение обновит данные в каталоге. При этом будут проиндексированы данные в зарегистрированных для полнотекстового поиска столбцах, удовлетворяющие одному из следующих критериев:

-         Данные из строк, которые были изменены с момента последнего индексирования

-         в таблицах, в которых есть столбцы типа TIMESTAMP.

-        

3

 
Данные из строк:

-         в таблицах, в которых нет  столбцов типа TIMESTAMP.

-         в таблицах, которые были активированы для полнотекстового поиска с момента последнего индексирования.

-         в таблицах, схема которых каким-либо образом изменилась с момента последнего индексирования – данные из всех столбцов.

19.    [Проверка]  Дождавшись конца заполнения полнотекстового каталога PubsCatalog, повторите запрос из шага 12. На этот раз ошибки не будет.

Теперь займемся графическими интерфейсами пользователя. Они очень просты и незамысловаты, поэтому мы сосредоточимся на том, как они вписаны в остальные GUI, предоставляемые SQL Server Enterprise Manager. Пять главных «точек входа» в администрирование полнотекстового поиска [KT3] показаны крупными нумерованными стрелками поверх фрагментов экрана на следующих картинках. В отличие от остальных мест в этом документе, здесь цифры не имеют отношения к порядку действий: они поставлены просто для удобной организации ссылок.

A)    Дерево объектов консоли SQL Server Enterprise Manager's


На дереве отмечено два объекта, имеющих отношение к полнотекстовому поиску[KT4] :

1    Full-Text Search.  Щелчок правой кнопкой мыши вызывает меню, через которое можно, например, запускать и останавливать службу полнотекстового поиска.

2    Full-Text Catalogs. Если выбрать этот объект, в сегменте окна «details» появится список полнотекстовых каталогов для этой базы данных (см. фрагмент экрана E).

      Щелчок правой кнопкой вызывает контекстное меню, через которое можно, например, создавать новые полнотекстовые каталоги и перестраивать все существующие полнотекстовые каталоги для этой базы данных.

B)  Меню Tools SQL Server Enterprise Manager

Здесь интересен следующий пункт:

3    Full-Text Indexing — запускает мастер подсказок для полнотекстового индексирования (см. фрагмент экрана H). 

 C)  Контекстное меню типичной таблицы


1

 
Пункт 4 Full-Text Index Table имеет подпункты с помощью которых можно вызывать мастер подсказок для полнотекстового индексирования, чтобы определять или изменять спецификации полнотекстовых индексов для таблицы или отменять в ней полнотекстовый поиск.

5

 

D)  Закладки свойств типичной таблицы (частично)

2

 
 Новая закладка:

5    Full-Text Indexing  Дает доступ к странице свойств. Фрагмент экрана показывает часть типичной страницы свойств.   

 

 


E) Типичный полнотекстовый каталог и контекстное меню

Вызвать меню можно в следующем порядке:

1)     Выбрать объект Full-Text Catalogs (фрагмент экрана A) и получить список полнотекстовых каталогов.

2)     Щелкнуть правой кнопкой на PubsCatalog и получить контекстное меню, показанное на этом фрагменте экрана. 

Выбор пункта Properties ведет к фрагменту экрана F.

Выбор пункта Schedules ведет к фрагменту экрана G.

F)  Страница свойств Status Property Page для типичного полнотекстового каталога


Это фрагмент страницы свойств, полученной после выбора пункта Properties в меню, показанном на фрагменте экрана E.

G)  Страница свойств Schedules Property Page для типичного полнотекстового каталога


Это фрагмент страницы свойств, полученной после выбора закладки Schedules на фрагменте экрана E.

 

H)  Мастер подсказок полнотекстового индексирования


Этот мастер подсказок может быть вызван из многих мест. Выше были показаны два способа: выбор пункта Full-Text Indexing на фрагменте экрана B или пункта Full-Text Index Table на фрагменте экрана C. Мастер подсказок собирает всю информацию, необходимую для создания и сопровождения полнотекстового индекса для данной таблицы. 

Имейте в виду, что регистрация и активация таблицы еще не означают, что можно выполнять полнотекстовые запросы. Сначала надо создать полнотекстовый индекс, а мастер подсказок не запускает этот процесс. Поэтому, зарегистрировав одну или несколько таблиц, имеет смысл инициировать заполнение их каталогов. Это можно сделать, выбрав пункт Start Population на фрагменте экрана E.

Выводы

Мы рады, что смогли ввести возможность полнотекстового поиска в SQL Server 7.0. Реализованы только простейшие средства его поддержки, но и они послужат многим очень полезным для наших клиентов целям.  

Очень важно, что даже эта простейшая реализация позволяет интегрировать информацию, находящуюся как внутри, так и вне базы данных. Усовершенствованный процессор распределенных запросов SQL Server 7.0 может объединять результаты полнотекстовых запросов к базе данных с результатами запросов к Index Server 2.0, работающему с файловой системой. Мы уверены, что включение Microsoft Information Retrieval Technologies в SQL Server 7.0 закладывает прекрасный фундамент: технологии, которые уже поставляются в составе нескольких продуктов Microsoft послужили основой для других продуктов Microsoft, поддерживающих текстовый поиск.

Наша стратегия повторного использования компонентов идет на пользу клиентам, поскольку дает им возможность органично обновлять средства, обеспечивающие   индексирование и поиск, при этом гарантируя совместимость между продуктами.



[1]     В контексте SQL Server это называется «полнотекстовым поиском».

[2]     Называемых также stop-words.

[3]     Называемый также Microsoft Search или «полнотекстовый поиск»

[4]     Кроме того, тем самым для каждой таблицы создается population start seed в Full-Text Service.