Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача. Классификация строк по шаблону / 16 сообщений из 16, страница 1 из 1
13.01.2013, 20:59
    #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
13.01.2013, 22:30
    #38108546
init.ora
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача. Классификация строк по шаблону
все ли шаблоны такого типа ????*??? ?

лучше использовать substr()
...
Рейтинг: 0 / 0
13.01.2013, 22:54
    #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
13.01.2013, 23:02
    #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
13.01.2013, 23:07
    #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
13.01.2013, 23:13
    #38108571
andreymx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача. Классификация строк по шаблону
В топорном виде - для 8-ки или 9-ки, без FBI и с доп. полями, это выглядело бы так:
добавляем в А два поля: start_A и end_A
в триггере, если все число - цифры, заполняем start_A первыми цифрами, end_A - последними
в противном случае - Null-ами
и индексируем эти поля

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

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

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


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

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

шаблоны ваши легко переписываются для использования с (обычным) like .
имхо, это всё решит
...
Рейтинг: 0 / 0
15.01.2013, 19:43
    #38111346
andreymx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача. Классификация строк по шаблону
Regexp_likeЕсть условие:
3) Обязательное условие: 1 тип - 1 строка шаблонов.никто не мешает сделать мастер-деталь
...
Рейтинг: 0 / 0
16.01.2013, 01:04
    #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
18.01.2013, 12:12
    #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
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача. Классификация строк по шаблону / 16 сообщений из 16, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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