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)
для классификации новых потоков документов.
Полезные ссылки (вендор)
- Oracle — CTX_CLS Package (Reference)
- Oracle Text — Supervised Classification
- MATCHES оператор и CTXRULE
- Classifier & Cluster Types (RULE/SVM/KMEAN)