CTX_CLS в PL/SQL — полное руководство с 50 примерами

🟢 CTX_CLS в PL/SQL. Введение

Пакет CTX_CLS в PL/SQL отвечает за обучение и применение классификации в Oracle Text.
Он умеет: supervised (обучение на размеченных документах через TRAIN) и unsupervised (кластеризацию через CLUSTERING). Сгенерированные правила используются через индекс CTXRULE и оператор MATCHES.

Введение

Ниже — 50 практических примеров: подготовка данных и индексов, обучение по двум вариантам
(RULE_CLASSIFIER, SVM_CLASSIFIER), использование MATCHES, кластеризация
KMEAN_CLUSTERING, и базовые сценарии эксплуатации. Во всех PL/SQL-блоках нет строки
/ после END;.

Подготовка данных и базовых объектов

CREATE TABLE trainingdoc (
  docid NUMBER PRIMARY KEY,
  text  CLOB
);
INSERT INTO trainingdoc (docid, text) VALUES (1, 'Oracle Text classification for databases and indexing rules.');
INSERT INTO trainingdoc (docid, text) VALUES (2, 'Delicious pizza, burgers and fries at the fast food chain.');
INSERT INTO trainingdoc (docid, text) VALUES (3, 'New CPU and GPU benchmarks for modern computers.');
INSERT INTO trainingdoc (docid, text) VALUES (4, 'Healthy salads and vegan bowls menu.');
COMMIT;
CREATE TABLE category (
  docid      NUMBER,
  categoryid NUMBER
);
-- 1 и 3 — компьютеры (cat=10); 2 и 4 — еда (cat=20)
INSERT INTO category VALUES (1, 10);
INSERT INTO category VALUES (3, 10);
INSERT INTO category VALUES (2, 20);
INSERT INTO category VALUES (4, 20);
COMMIT;
-- Результирующая таблица для RULE_CLASSIFIER (строковые правила)
CREATE TABLE rules (
  cat_id     NUMBER,
  query      CLOB,
  confidence NUMBER
);
-- Результирующая таблица для SVM_CLASSIFIER (бинарные правила)
CREATE TABLE svm_rules (
  cat_id NUMBER,
  type   NUMBER,
  rule   BLOB
);
BEGIN
  -- Лексер и преференсы для индекса обучающей коллекции
  CTX_DDL.CREATE_PREFERENCE('lex_ru','BASIC_LEXER');
  CTX_DDL.SET_ATTRIBUTE('lex_ru','MIXED_CASE','YES');
  CTX_DDL.CREATE_PREFERENCE('wl_ru','BASIC_WORDLIST');
  CTX_DDL.SET_ATTRIBUTE('wl_ru','STEMMER','RUSSIAN');
END;
CREATE INDEX idx_trainingdoc ON trainingdoc(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS (
  'LEXER lex_ru WORDLIST wl_ru'
);

50 примеров по CTX_CLS

1. Создать преференс RULE_CLASSIFIER

BEGIN
  CTX_DDL.CREATE_PREFERENCE('rule_cls','RULE_CLASSIFIER');
END;

2. Обучение CTX_CLS.TRAIN (query-compatible синтаксис)

BEGIN
  CTX_CLS.TRAIN(
    index_name => 'IDX_TRAININGDOC',
    docid      => 'DOCID',
    cattab     => 'CATEGORY',
    catdocid   => 'DOCID',
    catid      => 'CATEGORYID',
    restab     => 'RULES',
    rescatid   => 'CAT_ID',
    resquery   => 'QUERY',
    resconfid  => 'CONFIDENCE',
    preference => 'RULE_CLS'
  );
END;

3. Построить CTXRULE-индекс по таблице правил (строки)

CREATE INDEX rules_idx ON rules(query)
INDEXTYPE IS CTXSYS.CTXRULE;

4. Классификация строки на лету (MATCHES)

SELECT cat_id, confidence
FROM rules
WHERE MATCHES(query, 'This computer has a fast GPU and CPU for gaming') > 0;

5. Классифицировать набор новых документов из таблицы

CREATE TABLE newdocs AS
SELECT 1001 AS docid, TO_CLOB('Order the best burgers and pizza') AS text FROM dual
UNION ALL
SELECT 1002, TO_CLOB('Database indexing and query optimization') FROM dual;

SELECT n.docid, r.cat_id
FROM rules r
JOIN newdocs n
  ON MATCHES(r.query, n.text) > 0;

6. Получить оценку соответствия через MATCH_SCORE

SELECT n.docid, r.cat_id, MATCH_SCORE(1) AS score
FROM rules r, newdocs n
WHERE MATCHES(r.query, n.text) > 0;

7. Фильтр по доверительной оценке (из обучающей выборки)

SELECT r.cat_id, r.query, r.confidence
FROM rules r
WHERE r.confidence >= 0.6
ORDER BY r.confidence DESC;

8. Добавить новые размеченные документы и переобучить

INSERT INTO trainingdoc (docid, text) VALUES (5, 'New laptop review and CPU specs');
INSERT INTO category    (docid, categoryid) VALUES (5, 10);
COMMIT;

TRUNCATE TABLE rules;

BEGIN
  CTX_CLS.TRAIN('IDX_TRAININGDOC','DOCID','CATEGORY','DOCID','CATEGORYID',
                 'RULES','CAT_ID','QUERY','CONFIDENCE','RULE_CLS');
END;

9. Просмотр сгенерированных правил (top-3)

SELECT * FROM (
  SELECT cat_id, SUBSTR(query,1,140) AS query_sample, confidence
  FROM rules
  ORDER BY confidence DESC
) WHERE ROWNUM <= 3;

10. Обновление CTXRULE-индекса после переобучения

ALTER INDEX rules_idx REBUILD;

11. Создать преференс SVM_CLASSIFIER

BEGIN
  CTX_DDL.CREATE_PREFERENCE('svm_cls','SVM_CLASSIFIER');
END;

12. Обучение CTX_CLS.TRAIN по SVM (бинарные правила -> BLOB)

BEGIN
  CTX_CLS.TRAIN(
    index_name => 'IDX_TRAININGDOC',
    docid      => 'DOCID',
    cattab     => 'CATEGORY',
    catdocid   => 'DOCID',
    catid      => 'CATEGORYID',
    restab     => 'SVM_RULES',
    preference => 'SVM_CLS'
  );
END;

13. CTXRULE-индекс по BLOB-колонке правил SVM

CREATE INDEX svm_rules_idx ON svm_rules(rule)
INDEXTYPE IS CTXSYS.CTXRULE;

14. Классификация строки по SVM-правилам

SELECT cat_id
FROM svm_rules
WHERE MATCHES(rule, 'Fresh salads and bowls for a healthy diet') > 0;

15. Сравнить результаты RULE vs SVM для одного текста

WITH doc AS (
  SELECT TO_CLOB('GPU benchmark for high performance gaming computer') AS t FROM dual
)
SELECT 'RULE' AS kind, r.cat_id
  FROM rules r, doc d
 WHERE MATCHES(r.query, d.t) > 0
UNION ALL
SELECT 'SVM'  AS kind, s.cat_id
  FROM svm_rules s, doc d
 WHERE MATCHES(s.rule, d.t) > 0;

16. Очистка и повторное SVM-обучение

TRUNCATE TABLE svm_rules;
BEGIN
  CTX_CLS.TRAIN('IDX_TRAININGDOC','DOCID','CATEGORY','DOCID','CATEGORYID',
                 'SVM_RULES','SVM_CLS');
END;

17. Извлечь число правил на категорию (SVM)

SELECT cat_id, COUNT(*) AS rules_cnt
FROM svm_rules
GROUP BY cat_id;

18. Переиндексация CTXRULE (SVM) для быстрого поиска

ALTER INDEX svm_rules_idx REBUILD;

19. Коллекция для кластеризации

CREATE TABLE collection (
  docid NUMBER PRIMARY KEY,
  text  CLOB
);

20. Данные для кластеризации

INSERT INTO collection VALUES (101, TO_CLOB('pizza burger taco fries food menu'));
INSERT INTO collection VALUES (102, TO_CLOB('cpu gpu motherboard memory benchmark'));
INSERT INTO collection VALUES (103, TO_CLOB('vegan salad bowl healthy fresh food'));
INSERT INTO collection VALUES (104, TO_CLOB('graphics card overclock driver compute'));
INSERT INTO collection VALUES (105, TO_CLOB('sandwich pasta dessert coffee restaurant'));
COMMIT;

21. CONTEXT-индекс для коллекции

CREATE INDEX idx_collection ON collection(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER lex_ru WORDLIST wl_ru');

22. Преференс KMEAN_CLUSTERING с 3 кластерами

BEGIN
  CTX_DDL.CREATE_PREFERENCE('my_cluster','KMEAN_CLUSTERING');
  CTX_DDL.SET_ATTRIBUTE('my_cluster','CLUSTER_NUM','3');
END;

23. Табличный вывод кластеризации (создаст doc_assign/cluster_desc)

BEGIN
  CTX_CLS.CLUSTERING(
    index_name  => 'IDX_COLLECTION',
    docid       => 'DOCID',
    doctab_name => 'DOC_ASSIGN',
    clstab_name => 'CLUSTER_DESC',
    pref_name   => 'MY_CLUSTER'
  );
END;

24. Смотреть назначения документов по кластерам

SELECT * FROM doc_assign ORDER BY docid;

25. Смотреть описания кластеров

SELECT clusterid, SUBSTR(descript,1,120) AS descr, label, quality_score, parent
FROM cluster_desc
ORDER BY clusterid;

26. Включить тематику (THEME_ON=TRUE) и повторить

BEGIN
  CTX_DDL.SET_ATTRIBUTE('my_cluster','THEME_ON','TRUE');
END;

BEGIN
  CTX_CLS.CLUSTERING('IDX_COLLECTION','DOCID','DOC_ASSIGN2','CLUSTER_DESC2','MY_CLUSTER');
END;

27. Вариант: кластеризация в память (in-memory)

DECLARE
  ids   CTX_CLS.DOCID_TAB;
  docs  CTX_CLS.DOC_TAB;
  descr CTX_CLS.CLUSTER_TAB;
BEGIN
  ids(1) := 101; ids(2) := 102; ids(3) := 103; ids(4) := 104; ids(5) := 105;
  CTX_CLS.CLUSTERING('IDX_COLLECTION','DOCID', ids, docs, descr, 'MY_CLUSTER');
  -- выборка первых двух результатов
  DBMS_OUTPUT.PUT_LINE('Docs count: '||docs.COUNT||', Clusters: '||descr.COUNT);
END;

28. Увеличить признак MAX_FEATURES

BEGIN
  CTX_DDL.SET_ATTRIBUTE('my_cluster','MAX_FEATURES','10000');
END;

29. Ограничить количество термов на документ

BEGIN
  CTX_DDL.SET_ATTRIBUTE('my_cluster','MAX_DOCTERMS','200');
END;

30. Настроить STEM_ON / TOKEN_ON / MEMORY_SIZE

BEGIN
  CTX_DDL.SET_ATTRIBUTE('my_cluster','STEM_ON','TRUE');
  CTX_DDL.SET_ATTRIBUTE('my_cluster','TOKEN_ON','TRUE');
  CTX_DDL.SET_ATTRIBUTE('my_cluster','MEMORY_SIZE','256M');
END;

31. Использовать секции (HTML_SECTION_GROUP) в обучении

BEGIN
  CTX_DDL.CREATE_SECTION_GROUP('sg_html','HTML_SECTION_GROUP');
  CTX_DDL.ADD_FIELD_SECTION('sg_html','title','TITLE', TRUE);
END;

DROP INDEX idx_trainingdoc;

CREATE INDEX idx_trainingdoc ON trainingdoc(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER lex_ru WORDLIST wl_ru SECTION GROUP sg_html');

32. Переобучение с учётом секций (RULE_CLASSIFIER)

TRUNCATE TABLE rules;
BEGIN
  CTX_CLS.TRAIN('IDX_TRAININGDOC','DOCID','CATEGORY','DOCID','CATEGORYID',
                 'RULES','CAT_ID','QUERY','CONFIDENCE','RULE_CLS');
END;

33. MULTI_COLUMN_DATASTORE: собрать title+body

ALTER TABLE trainingdoc ADD (title VARCHAR2(400));
UPDATE trainingdoc SET title = 'Doc '||docid;
COMMIT;

BEGIN
  CTX_DDL.CREATE_PREFERENCE('mc_ds','MULTI_COLUMN_DATASTORE');
  CTX_DDL.SET_ATTRIBUTE('mc_ds','COLUMNS','title, text');
END;

DROP INDEX idx_trainingdoc;

CREATE INDEX idx_trainingdoc ON trainingdoc(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('DATASTORE mc_ds LEXER lex_ru WORDLIST wl_ru');

34. Стоп-слова: отфильтровать общеупотребительные

BEGIN
  CTX_DDL.CREATE_PREFERENCE('stop_ru','BASIC_STOPLIST');
  CTX_DDL.ADD_STOPWORD('stop_ru','и');
  CTX_DDL.ADD_STOPWORD('stop_ru','в');
END;

DROP INDEX idx_trainingdoc;

CREATE INDEX idx_trainingdoc ON trainingdoc(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('DATASTORE mc_ds LEXER lex_ru WORDLIST wl_ru STOPLIST stop_ru');

35. Пересоздать CTXRULE-индекс после обновления правил

DROP INDEX rules_idx;
CREATE INDEX rules_idx ON rules(query) INDEXTYPE IS CTXSYS.CTXRULE;

36. Классификация с порогом и выбором топ-1 категории

WITH hits AS (
  SELECT n.docid, r.cat_id, MATCH_SCORE(1) AS score
  FROM rules r, newdocs n
  WHERE MATCHES(r.query, n.text) > 0
)
SELECT docid, cat_id
FROM (
  SELECT docid, cat_id, score,
         ROW_NUMBER() OVER (PARTITION BY docid ORDER BY score DESC) AS rn
  FROM hits
  WHERE score >= 5
)
WHERE rn = 1;

37. Оценка качества на обучающей выборке (упрощённо)

WITH hits AS (
  SELECT t.docid, r.cat_id
  FROM rules r, trainingdoc t
  WHERE MATCHES(r.query, t.text) > 0
)
SELECT c.categoryid AS true_cat, h.cat_id AS pred_cat, COUNT(*) AS cnt
FROM category c
LEFT JOIN hits h ON h.docid = c.docid
GROUP BY c.categoryid, h.cat_id
ORDER BY 1,2;

38. Протоколирование: писать лог CTX_CLS в CTX_OUTPUT

BEGIN
  CTX_OUTPUT.START_LOG('ctx_cls_training.log');
  CTX_CLS.TRAIN('IDX_TRAININGDOC','DOCID','CATEGORY','DOCID','CATEGORYID',
                 'RULES','CAT_ID','QUERY','CONFIDENCE','RULE_CLS');
  CTX_OUTPUT.END_LOG;
END;

39. Частичное переобучение: пересчитать только RULES

TRUNCATE TABLE rules;
BEGIN
  CTX_CLS.TRAIN('IDX_TRAININGDOC','DOCID','CATEGORY','DOCID','CATEGORYID',
                 'RULES','CAT_ID','QUERY','CONFIDENCE','RULE_CLS');
END;

ALTER INDEX rules_idx REBUILD;

40. Классификация XML/HTML благодаря секциям WITHIN

-- пример запроса по секции title (если такие правила сгенерированы)
SELECT cat_id
FROM rules
WHERE MATCHES(query, '<title>GPU overview</title><p>Specs inside</p>') > 0;

41. Создать SENTIMENT_CLASSIFIER (по необходимости)

BEGIN
  CTX_DDL.CREATE_PREFERENCE('sent_cls','SENTIMENT_CLASSIFIER');
END;

42. Обучить модель тональности (SA_TRAIN_MODEL)

BEGIN
  CTX_CLS.SA_TRAIN_MODEL(
    clsfier_name => 'SENTI_DEMO',
    index_name   => 'IDX_TRAININGDOC',
    docid        => 'DOCID',
    cattab       => 'CATEGORY',
    catdocid     => 'DOCID',
    catid        => 'CATEGORYID',
    pref_name    => 'SENT_CLS'
  );
END;

43. Удалить модель тональности (SA_DROP_MODEL)

BEGIN
  CTX_CLS.SA_DROP_MODEL('SENTI_DEMO');
END;

44. Пример pipeline: процедура массовой классификации

CREATE OR REPLACE PROCEDURE classify_newdocs AS
BEGIN
  MERGE INTO doc_categories d
  USING (
    SELECT n.docid, r.cat_id
    FROM rules r, newdocs n
    WHERE MATCHES(r.query, n.text) > 0
  ) s
  ON (d.docid = s.docid AND d.cat_id = s.cat_id)
  WHEN NOT MATCHED THEN INSERT (docid, cat_id) VALUES (s.docid, s.cat_id);
END;

45. Планировщик: еженощная переобучалка (DBMS_SCHEDULER)

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'JOB_CLS_RETRAIN',
    job_type        => 'PLSQL_BLOCK',
    job_action      => q'[BEGIN
      TRUNCATE TABLE rules;
      CTX_CLS.TRAIN(''IDX_TRAININGDOC'',''DOCID'',''CATEGORY'',''DOCID'',''CATEGORYID'',
                     ''RULES'',''CAT_ID'',''QUERY'',''CONFIDENCE'',''RULE_CLS'');
      ALTER INDEX rules_idx REBUILD;
    END;]',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY;BYHOUR=2;BYMINUTE=0;BYSECOND=0',
    enabled         => TRUE
  );
END;

46. Очистка: убрать кластерные таблицы

DROP TABLE doc_assign PURGE;
DROP TABLE cluster_desc PURGE;
DROP TABLE doc_assign2 PURGE;
DROP TABLE cluster_desc2 PURGE;

47. Очистка: удалить преференсы CLUSTER/CLASSIFIER

BEGIN
  CTX_DDL.DROP_PREFERENCE('my_cluster');
  CTX_DDL.DROP_PREFERENCE('rule_cls');
  CTX_DDL.DROP_PREFERENCE('svm_cls');
  CTX_DDL.DROP_PREFERENCE('sent_cls');
END;

48. Очистка: удалить служебные объекты демо

DROP INDEX rules_idx;
DROP INDEX svm_rules_idx;
DROP INDEX idx_trainingdoc;
DROP INDEX idx_collection;

49. Очистка: удалить таблицы демо

DROP TABLE rules PURGE;
DROP TABLE svm_rules PURGE;
DROP TABLE trainingdoc PURGE;
DROP TABLE category PURGE;
DROP TABLE newdocs PURGE;
DROP TABLE collection PURGE;

50. Рекомендация: минимальные привилегии

-- выполнять обучение/кластеризацию под учетной записью приложения;
-- для доступа к таблицам: выдать точечные SELECT/INSERT/UPDATE;
-- CTXSYS не требуется, кроме операций администрирования Oracle Text.
-- (проверьте роли CTXAPP/EXECUTE на нужные пакеты).

Заключение

CTX_CLS автоматизирует генерацию правил для CTXRULE и поддерживает кластеризацию.
После обучения индексируйте таблицу правил и используйте MATCHES (и при необходимости MATCH_SCORE)
для классификации новых потоков документов.

Полезные ссылки (вендор)


 

Понравилась статья? Поделиться с друзьями: