powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача. Классификация строк по шаблону
16 сообщений из 16, страница 1 из 1
Задача. Классификация строк по шаблону
    #38108476
Regexp_like
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Дано:
Есть таблица А, которая содержит помимо прочих поле str_numb varchar2(16), в строке только цифры. Примерный объём таблицы ~ 10 млн строк, под условие выборки попадают ~ 1 млн. Каждой такой строке нужно поставить в соответствие ТИП, который описывается набором шаблонов вида ????*???, например для 1234*099 подходит 1234111111111099. Шаблоны хранятся в таблице S (~ 100 строк): тип; набор шаблонов, который можно описать удобным способом (возможны варианты).

Необходимо:
Для каждой строки (~ 1 млн) определить тип (предполагаем, что подойдёт только 1).

Простое решение:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
 with A as
(
  select 
    substr((mod(rownum,999)+1)*1000,1,4)||'000000000'||substr((mod(rownum,55)+1)*100,1,3) as str_numb
  from dual
  connect by level <= 1000000
),
S as
(
  select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
   union all
  select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
   union all
  select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual 
) 
select
 A.str_numb,
 S.N_CLASS
from A 
join S on regexp_like(str_numb,S.SETTING)



Решение подходит, но есть проблемы:
1 - основная: Производительность - 10-ки минут.
2 - У regexp_like ограничение на длину строки (шаблона) 512 байт - может не уместиться.

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

Спасибо!
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108546
init.ora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
все ли шаблоны такого типа ????*??? ?

лучше использовать substr()
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108560
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Regexp_likeСпособ описания шаблона можно менятьСудя по шаблону, интересуют строки состоящие из цифр, где первые и последние четыре цифры определены.
В таком случае можно шаблон составлять из набора строк (1 тип - несколько строк), состоящих из 8 цифр и в условии соединения:
Код: plsql
1.
substr(a.str_numb,1,4)||substr(a.str_numb,-4)=s.setting and translate(a.str_numb,'_1234567890','_') is null
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108566
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopRegexp_likeСпособ описания шаблона можно менятьСудя по шаблону, интересуют строки состоящие из цифр, где первые и последние четыре цифры определены.
В таком случае можно шаблон составлять из набора строк (1 тип - несколько строк), состоящих из 8 цифр и в условии соединения:
Код: plsql
1.
substr(a.str_numb,1,4)||substr(a.str_numb,-4)=s.setting and translate(a.str_numb,'_1234567890','_') is null

если в каждой маске ровно по три штуки (или не более трех), то, возможно, лучше не бить на строки, а сделать три поля с шаблонами и написать тройную проверку
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108569
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а если задача выполняется часто, то лучше сделать FBI или вычисляемые поля для
- substr(a.str_numb,1,4)
- substr(a.str_numb,-4)
- translate(a.str_numb,'_1234567890','_') is null
ну и каждый шаблон вида ^3330\d+0300$ тоже разбить на части - на 3330 и на 0300
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108571
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В топорном виде - для 8-ки или 9-ки, без FBI и с доп. полями, это выглядело бы так:
добавляем в А два поля: start_A и end_A
в триггере, если все число - цифры, заполняем start_A первыми цифрами, end_A - последними
в противном случае - Null-ами
и индексируем эти поля

И в конце обычный самый джойн

Еснно, это если шаблоны действительно вида 9999%9999 и других не будет.
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108572
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxв триггере, если все число - цифры , заполняем start_A первыми цифрами, end_A - последними
сорри
если вся строка - цифры
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108582
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymxесли в каждой маске ровно по три штуки (или не более трех), то, возможно, лучше не бить на строки, а сделать три поля с шаблонами и написать тройную проверкуТройная проверка в лучшем случае сделает возможным hash join развернутый в concatenation. А это уже усложнение.
andreymxа если задача выполняется часто, то лучше сделать FBI или вычисляемые поляНе вижу смысла, если надо проверить ВСЕ строки.
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108593
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopandreymxа если задача выполняется часто, то лучше сделать FBI или вычисляемые поляНе вижу смысла, если надо проверить ВСЕ строки.меньше вычислительных операций
однозначно взлетит
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38108603
Regexp_like
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не увидел пока подходящего варианта, хотя возможно не понял их. Уточню условия:

1) Все шаблоны пока одинаковые (9999%999 или ????*???). Но потенциально могут появится и другие схожие (настройка может менятся и поэтому вынесена). С этой т.з. regexp_like идеально подходит.
2) Для 1 типа может быть произвольное их количество (потому есть проблема по длине regexp_like).
3) Обязательное условие: 1 тип - 1 строка шаблонов.
4) Допустимо использование динамического SQL.
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38109545
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Regexp_likeНе увидел пока подходящего варианта, хотя возможно не понял их. Уточню условия:

1) Все шаблоны пока одинаковые (9999%999 или ????*???). Но потенциально могут появится и другие схожие (настройка может менятся и поэтому вынесена). С этой т.з. regexp_like идеально подходит.
2) Для 1 типа может быть произвольное их количество (потому есть проблема по длине regexp_like).
3) Обязательное условие: 1 тип - 1 строка шаблонов.
4) Допустимо использование динамического SQL.Если известно максимальное число символов шаблона в начале строки и в конце, то можешь использовать мой подход.
regexp_like - это, конечно, красиво, но это только nested loops и сильная загрузка CPU.
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38111231
Regexp_like
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopЕсли известно максимальное число символов шаблона в начале строки и в конце, то можешь использовать мой подход.


Есть условие:
3) Обязательное условие: 1 тип - 1 строка шаблонов.

Предлагаешь транспонировать в запросе строку из настройки, чтобы разнести по разным строкам каждый отдельный шаблон?
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38111273
Фотография orawish
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Regexp_like,

шаблоны ваши легко переписываются для использования с (обычным) like .
имхо, это всё решит
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38111346
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Regexp_likeЕсть условие:
3) Обязательное условие: 1 тип - 1 строка шаблонов.никто не мешает сделать мастер-деталь
...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38111566
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Regexp_likedbms_photoshopЕсли известно максимальное число символов шаблона в начале строки и в конце, то можешь использовать мой подход.


Есть условие:
3) Обязательное условие: 1 тип - 1 строка шаблонов.

Предлагаешь транспонировать в запросе строку из настройки, чтобы разнести по разным строкам каждый отдельный шаблон?Если поставлено требование "1 тип - 1 строка шаблонов" - никто ведь не запрещает в базе хранить в таком виде, как удобно разработчику?
Даже если и запрещает, то модифицируй на лету.
Как я уже сказал, всякие regexp_like, like - это всегда nested loops, что при более менее заметном числе шаблонов приводит к большим проблемам.
Код: plsql
1.
2.
3.
4.
5.
6.
create table a as
select
substr((mod(rownum,999)+1)*1000,1,4)||'000000000'||substr((mod(rownum,55)+1)*100,1,3) as str_numb
from dual
where rownum > 0
connect by level <= 1000000;

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  ),
 10  S_MOD as
 11  (
 12    select
 13    distinct
 14    N_CLASS,
 15    translate(substr(setting,instr(setting,'^',1,column_value),instr(setting,'$',1,column_value)-instr(setting,'^',1,column_value)),'d^\+','%') SET
TING
 16    from s, table(cast(multiset(select rownum from dual connect by level <= length(setting)-length(replace(setting,'|'))+1) as sys.odcinumberlist))

 17  )
 18  select
 19    count(*)
 20  from A
 21  join S_MOD S on a.str_numb like S.SETTING;

  COUNT(*)
----------
       183

Elapsed: 00:00:00.87
SQL>
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  ),
 10  S_MOD as
 11  (
 12    select
 13    distinct
 14    N_CLASS,
 15    translate(substr(setting,instr(setting,'^',1,column_value),instr(setting,'$',1,column_value)-instr(setting,'^',1,column_value)),'_^\d+','_') SE
TTING
 16    from s, table(cast(multiset(select rownum from dual connect by level <= length(setting)-length(replace(setting,'|'))+1) as sys.odcinumberlist))

 17  )
 18  select
 19    count(*)
 20  from A
 21  join S_MOD S on substr(a.str_numb,1,4)||substr(a.str_numb,-4)=s.setting;

  COUNT(*)
----------
       183

Elapsed: 00:00:00.64
SQL>
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  ),
 10  S_MOD as
 11  (
 12    select
 13    distinct
 14    N_CLASS,
 15    translate(substr(setting,instr(setting,'^',1,column_value),instr(setting,'$',1,column_value)-instr(setting,'^',1,column_value)),'_^\d+','_') SE
TTING
 16    from s, table(cast(multiset(select rownum from dual connect by level <= length(setting)-length(replace(setting,'|'))+1) as sys.odcinumberlist))

 17  )
 18  select --+ use_nl(s a) leading(s)
 19    count(*)
 20  from A
 21  join S_MOD S on substr(a.str_numb,1,4)||substr(a.str_numb,-4)=s.setting;

  COUNT(*)
----------
       183

Elapsed: 00:00:03.43
SQL>
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  ),
 10  S_MOD as
 11  (
 12    select
 13    distinct
 14    N_CLASS,
 15    translate(substr(setting,instr(setting,'^',1,column_value),instr(setting,'$',1,column_value)-instr(setting,'^',1,column_value)),'d^\+','%') SET
TING
 16    from s, table(cast(multiset(select rownum from dual connect by level <= length(setting)-length(replace(setting,'|'))+1) as sys.odcinumberlist))

 17    union all
 18    select 'dummy', 'padding' from dual connect by rownum <= 1000
 19  )
 20  select
 21    count(*)
 22  from A
 23  join S_MOD S on a.str_numb like S.SETTING;

  COUNT(*)
----------
       183

Elapsed: 00:01:22.67
SQL>
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  ),
 10  S_MOD as
 11  (
 12    select
 13    distinct
 14    N_CLASS,
 15    translate(substr(setting,instr(setting,'^',1,column_value),instr(setting,'$',1,column_value)-instr(setting,'^',1,column_value)),'_^\d+','_') SE
TTING
 16    from s, table(cast(multiset(select rownum from dual connect by level <= length(setting)-length(replace(setting,'|'))+1) as sys.odcinumberlist))

 17    union all
 18    select 'dummy', 'padding' from dual connect by rownum <= 1000
 19  )
 20  select
 21    count(*)
 22  from A
 23  join S_MOD S on substr(a.str_numb,1,4)||substr(a.str_numb,-4)=s.setting;

  COUNT(*)
----------
       183

Elapsed: 00:00:00.67

Как видно из воспроизведения, если шаблонов очень мало, то like раобтает соизмеримо с моим вариантом. Мой вариант, захинтованый как nested loops немного уступает, что говорит о том, что substr + || более дорогостоящие операции чем like. Если шаблонов достаточно много то 00:01:22.67 vs 00:00:00.67 достаточно красноречиво говорит о том какой подход избирать.
Для полноты картины, оригинальный подход
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
SQL> with
  2  S as
  3  (
  4    select 'TYPE_1' N_CLASS, '^3330\d+0300$|^3330\d+0500$|^3330\d+0550$' SETTING from dual
  5     union all
  6    select 'TYPE_2' N_CLASS, '^5550\d+0300$|^5550\d+0300$|^8880\d+0660$' SETTING from dual
  7     union all
  8    select 'TYPE_3' N_CLASS, '^9990\d+0440$|^1230\d+0100$|^3330\d+0770$' SETTING from dual
  9  )
 10  select
 11   count(*)
 12  from A
 13  join S on regexp_like(str_numb,S.SETTING);

  COUNT(*)
----------
       183

Elapsed: 00:01:00.25

...
Рейтинг: 0 / 0
Задача. Классификация строк по шаблону
    #38115102
Regexp_like
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Итоговый приемлемый вариант пока - транспонирование настройки + substr. Отлично по условиям подходил вариант транспонирования + like (чтобы настройку записывать в формате like), но like в моем случае оказался на несколько порядков медленнее substr. Но при этом имеем жёсткий формат записи настройки.
Запрос примерно такой:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
  with A as
(
  select 
    substr((mod(rownum,999)+1)*1000,1,4)||'000000000'||substr((mod(rownum,55)+1)*100,1,3) as str_numb
  from dual
  connect by level <= 100000
), 
S as
(
  select 'TYPE_1' N_CLASS, '3330*0300,3330*0500,3330*0550' SETTING from dual
   union all
  select 'TYPE_2' N_CLASS, '5550*0300,7550*0300,8880*0660' SETTING from dual
   union all
  select 'TYPE_3' N_CLASS, '9990*0440,1230*0100,3330*0770' SETTING from dual 
)
select
 A.str_numb,
 TRANSP.N_CLASS
from A 
join 
(select
   S.N_CLASS,
   to_char(substr(SETTING,instr(','||SETTING||',',',',1,lvl),instr(','||SETTING||',',',',1,lvl +1) - instr(','||SETTING||',',',',1,lvl)-1)) TR_SET
 from S,
 (select level lvl
 from  dual
 connect by level <= (select max(length(SETTING) - length(replace(SETTING,',')) + 1) from S))) TRANSP
 on substr(A.str_numb,1,4)||'*'||substr(A.str_numb,-4,4) = TRANSP.TR_SET



Всем спасибо, особенно dbms_photoshop!
...
Рейтинг: 0 / 0
16 сообщений из 16, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача. Классификация строк по шаблону
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]