Oracle Text и PL/SQL: многоязыковой информационный поиск

Oracle Text и PL/SQL: многоязыковой информационный поиск

Разработчикам приложений PL/SQL, работающим с каталогами, цифровыми библиотеками и ре­позиториями, часто решают задачу поиска записей или документов, ближе всего соответствующих заданному критерию и намерениям пользователя. Это одно из принципиальных отличий получения информации от стандартных запросов SQL, которые либо находят совпадения для критерия запроса, либо не находят их. Хорошая система информационного поиска может определить содержимое документа и вернуть документы, в наибольшей степени относящиеся к критерию поиска, даже при отсутствии точного совпадения. Вероятно, самой сложной задачей в области информационного поиска является поддержка индексирования и запросов на разных языках. Например, однобайтовый английский язык использует пробелы для разделения слов. При работе с японским языком, использующим многобайтовый набор символов без пробелов-разделителей, информационный поиск производится совершенно иначе.

Oracle Text — программа, входящая и в Oracle Enterprise Edition, и в Oracle Standard Edition — обеспечивает функциональность полнотекстового информационного поиска. Благодаря использованию SQL для создания индексов, поиска и операций сопровождений, Oracle Text очень хорошо работает в сочетании с приложениями на базе PL/SQL. Программа Oracle Text (в предыдущих версиях называвшаяся ConText and interMedia) стала полноценным решением в области информационного поиска с выходом Oracle9i. Oracle Text:

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

Прежде чем писать приложение PL/SQL для поиска в источнике данных, необходимо создать индексы Oracle Text. Я создал индекс Oracle Text по столбцу publication. short_description в составе схемы glln. Чтобы обеспечить поддержку нескольких языков, я определил настройки для разных языков, а также настройку MULTI_LEXER, позволяющую проводить поиск по нескольким языкам в одном запросе.

 

Индексы Oracle Text

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

FUNCTION text_search_func (v_keyword IN VARCHAR2)
   RETURN sys_refcursor
IS
   v_title   sys_refcursor;
BEGIN
   OPEN v_title
    FOR
       SELECT   title, LANGUAGE, score (1)
         FROM publication
         WHERE contains (short_description, v_keyword, 1) > 0
      ORDER BY score (1) DESC;

   RETURN v_title;
END text_search_func;

Вызов этой функции с передачей ключевого слова «pl»:

variable x refcursor;
call text_search_func('pl') into :x;
print x;

возвращает следующий результат:

TITLE                                             LANGUAGE  SCORE(1)
----------------------------------------          --------  --------
Oracle PL/SQLプログラミング 基礎編 第3版               JA        18
Oracle PL/SQL Programming, 3rd Edition             EN        13
Oracle PL/SQL Programmierung, 2. Auflage           DE        9

Книга находится на всех трех языках, потому что «pl» присутствует во всех вариантах ее названия. Обратите внимание: я провожу поиск по строке «pl» в нижнем регистре, но в записи символы «PL» хранятся в верхнем регистре. По умолчанию поиск проводится без учета регистра, несмотря на использование функции UPPER.

Может оказаться, что в одних языках регистр символов должен игнорироваться, а в других — нет. Признак игнорирования регистра можно задать на уровне отдельных языков в языковых настройках. Просто добавьте атрибут mixed_case со значением yes; лексемы будут создаваться в том виде, в котором они хранятся в документе или столбце, — но только для языка, указанного в настройке.

В Oracle Database 11g многоязыковой информационный поиск упростился с появлением реализации AUTO_LEXER. По количеству функций уровня отдельных языков она уступает MULTI_LEXER, но зато почти не требует лишних усилий со стороны разработчика. Вместо того чтобы полагаться на содержимое столбца language, AUTO_LEXER идентифицирует текст на основании кодовых точек.

Oracle также поддерживает реализацию WORLD_LEXER. По широте функций она уступает MULTI_LEXER и, как и AUTO_LEXER, не предусматривает настройки на уровне отдельных языков. С другой стороны, она очень проста в настройке.

При использовании WORLD_LEXER текст разбивается на лексемы в зависимости от категории, к которой он относится. Разбивка текстов на языках арабских и латинских категорий, в которых лексемы разделяются пробелами, не создает проблем. С азиатскими символами дело обстоит сложнее, потому что в них разделители-пробелы не используются, поэтому разбивка осуществляется с перекрытием. Например, трехсимвольная строка 尼崎市 разбивается на две лексемы, 尼崎 и 崎市.

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

 

Информационный поиск и PL/SQL

Мне доводилось проектировать и реализовывать исключительно большие и сложные системы управления записями и цифровые библиотеки. По собственному опыту могу сказать, что ничто не сравнится с PL/SQL для операций поиска и сопровождения в Oracle Text. Тесная интеграция PL/SQL с сервером базы данных, а также улучшение его быстродействия в последних версиях делают хранимые программы PL/SQL идеальным вариантом для программ такого рода.

Преимущества становятся еще более очевидными при работе на нескольких языках. Общий разбор SQL и PL/SQL означает логически последовательную обработку сим­волов и символьной семантики независимо от языка, на котором производятся индек­сирование и поиск.

 Один из первых проектов, за которые обычно берутся программисты Oracle Text, — форматирование строк для поиска. В следующем примере создается функция, которая форматирует поисковые строки для Oracle Text:


FUNCTION format_string (p_search IN VARCHAR2)
   RETURN VARCHAR2
AS
-- Определение ассоциативного массива
   TYPE token_table IS TABLE OF VARCHAR2 (500 CHAR)
      INDEX BY PLS_INTEGER;

-- Определение переменной ассоциативного массива
   v_token_array           token_table;
   v_temp_search_string    VARCHAR2 (500 CHAR);
   v_final_search_string   VARCHAR2 (500 CHAR);
   v_count                 PLS_INTEGER         := 0;
   v_token_count           PLS_INTEGER         := 0;
BEGIN
   v_temp_search_string := TRIM (UPPER (p_search));
   -- Определение максимального количества лексем
   v_token_count :=
        lengthc (v_temp_search_string)
      - lengthc (REPLACE (v_temp_search_string, ' ', ''))
      + 1;

   -- Заполнение ассоциативного массива
   FOR y IN 1 .. v_token_count
   LOOP
      v_count := v_count + 1;
      v_token_array (y) :=
            regexp_substr (v_temp_search_string, '[^[:space:]]+', 1, v_count);
      -- Обработка зарезервированных слов
      v_token_array (y) := TRIM (v_token_array (y));

      IF v_token_array (y) IN ('ABOUT', 'WITHIN')
      THEN
         v_token_array (y) := '{' || v_token_array (y) || '}';
      END IF;
   END LOOP;

   v_count := 0;

   FOR y IN v_token_array.FIRST .. v_token_array.LAST
   LOOP
      v_count := v_count + 1;

      -- Обработана первая лексема
      IF (    (v_token_array.LAST = v_count OR v_count = 1)
          AND v_token_array (y) IN ('AND', '&', 'OR', '|')
         )
      THEN
         v_final_search_string := v_final_search_string;
      ELSIF (v_count <> 1)
      THEN
         -- Разделение запятой (если разделителя еще нет)
         IF    v_token_array (y) IN ('AND', '&', 'OR', '|')
            OR v_token_array (y - 1) IN ('AND', '&', 'OR', '|')
         THEN
            v_final_search_string :=
                            v_final_search_string || ' ' || v_token_array (y);
         ELSE
            v_final_search_string :=
                           v_final_search_string || ', ' || v_token_array (y);
         END IF;
      ELSE
         v_final_search_string := v_token_array (y);
      END IF;
   END LOOP;

   -- Экранирование специальных символов в строке
   v_final_search_string :=
      TRIM (REPLACE (REPLACE (v_final_search_string,
                               '&',
                               ' & '
                              ),
                     ';',
                     ' ; '
                    )
           );
   RETURN (v_final_search_string);
END format_string;

 

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

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

SELECT format_string('oracle PL/SQL') AS "Formatted String"
  FROM dual

Команда возвращает следующий результат:

Formatted String
-----------------
ORACLE, PL/SQL

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

SELECT format_string('Oracle PL/SQLプログラミング 基礎編 第3版') AS
"Formatted String" FROM dual;

При передаче этой смешанной строки функции F0RMAT_STRING возвращается следующий результат:

Formatted String
-----------------
ORACLE, PL/SQLプログラミング, 基礎編, 第3版

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

Следующий поиск CONTAINS использует функцию F0RMAT_STRING:

SELECT score (1) "Rank", title
  FROM publication
  WHERE contains (short_description, format_string('プログラム'), 1) > 0;

Результат выглядит так:

      Rank     TITLE
------------   ------------
          12   Oracle SQL*Plus デスクトップリファレンス

Использование PL/SQL и Oracle Text позволяет выполнять индексирование и полнотекстовый поиск в данных независимо от набора символов или языка.

Вас заинтересует / Intresting for you:

Сопровождение объектных типов ...
Сопровождение объектных типов ... 3732 просмотров Максим Николенко Sun, 03 Nov 2019, 09:18:04
Значения NULL в PL/SQL Oracle
Значения NULL в PL/SQL Oracle 4823 просмотров Дэн Wed, 01 Jul 2020, 08:10:56
 Версии PL/SQL и Oracle 12c
Версии PL/SQL и Oracle 12c 3428 просмотров Александров Попков Tue, 21 Nov 2017, 13:28:01
Использование SQL*Plus и Oracl...
Использование SQL*Plus и Oracl... 13435 просмотров aleksandr Tue, 21 Nov 2017, 13:19:25
Войдите чтобы комментировать