Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..) / 23 сообщений из 23, страница 1 из 1
16.01.2014, 14:03:27
    #38528227
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Добрый день!

Задача:
Нужно перевести текст `text` из таблицы text по словарю dict.

Исходные данные:

dict
word_en word_rublack черныйwhite белыйgreen зеленыйblue синийbrown коричневыйred красный

text
idtext1Цвета обивки: brown red white и другие цвета2Цвета ткани: brown white red black и другие цвета3Цвета: red white green и другие цвета4Цвета: blue white black и другие цвета

Требуемый результат:

Нужно получить такой `text`
textЦвета обивки: brown (коричневый) red (красный) white (белый) и другие цветаЦвета ткани: brown (коричневый) white (белый) red (красный) black (черный) и другие цветаЦвета: red (красный) white (белый) green (зеленый) и другие цветаЦвета: blue (синий) white (белый) black (черный) и другие цвета

Решение:

В качестве решения был выбран такой запрос, но он не работает. Переводит только первое по словарю слово (как многопроходный пример ниже). Почему?
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
DROP TABLE IF EXISTS `text_temp`;
CREATE TABLE `text_temp` LIKE `text`;
INSERT INTO `text_temp`
SELECT * FROM `text`;

#сам запрос
UPDATE text_temp as t
INNER JOIN dict as d
ON t.text like CONCAT('%',d.word_en,'%')
SET t.text=IF(t.text=@text_old,
			@temp_str:=replace(@temp_str,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')),	
			@temp_str:=replace(@text_old:=t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')'))
			)		



Сейчас использую много-проходную схему. Работает, но долго, т.к. много проходов.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#Проход 1 (переводим первое слово)
UPDATE text_temp as t
INNER JOIN dict as d
ON t.text like CONCAT('%',d.word_en,'%')
AND t.text not like CONCAT('%','(',d.word_ru,')','%')
SET t.text=replace(t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')) 	

#Проход 2 (переводим второе слово)
UPDATE text_temp as t
INNER JOIN dict as d
ON t.text like CONCAT('%',d.word_en,'%')
AND t.text not like CONCAT('%','(',d.word_ru,')','%')
SET t.text=replace(t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')) 		

...
# Проход N (переводим N-ное слово)
...




Исходные таблицы:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE TABLE IF NOT EXISTS `dict` (
  `word_en` varchar(64) NOT NULL,
  `word_ru` varchar(64) NOT NULL
);

INSERT INTO `dict` (`word_en`, `word_ru`) VALUES
('black', 'черный'),
('white', 'белый'),
('green', 'зеленый'),
('blue', 'синий'),
('brown', 'коричневый'),
('red', 'красный');



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE IF NOT EXISTS `text` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `text` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ;

INSERT INTO `text` (`id`, `text`) VALUES
(1, 'Цвета обивки: brown red white  и другие цвета'),
(2, 'Цвета ткани: brown white red black  и другие цвета'),
(3, 'Цвета: red, white green и другие цвета'),
(4, 'Цвета:  blue, white black и другие цвета');


данных в таблице text 300 000 строк, словарь dict 500 слов


Вопрос:

Как сделать запрос с переменными рабочим и за один раз перевести всю таблицу?
(т.е. нужно обойтись без многопроходности)
...
Рейтинг: 0 / 0
16.01.2014, 16:38:43
    #38528525
artas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
diego8807,

мне чего-то видится только вариант, каким-нибудь клиентским языком составить запрос где будет 500 этих самых вложенных реплейсов. Но если нужно постоянно обновлять, то конечно-же не вариант
...
Рейтинг: 0 / 0
16.01.2014, 16:47:09
    #38528540
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
diego8807Переводит только первое по словарю слово (как многопроходный пример ниже). Почему?
Потому что связывание таблиц соопоставляет ОДНУ запись из таблицы dict и ОДНУ из таблицы text. Переходя к другой записи из таблицы, он берёт запись ИЗ ДРУГОЙ ТАБЛИЦЫ, а не с предыдущей итерации. Неизменённую предыдущей итерацией. Изменения на предыдущей итерации, таким образом, потеряны.

Для реализации требуемого функционала придётся задействовать переменные - точно так, как они исползуются в ФАКе по нумерации записи в группе. Читай, вникай...
...
Рейтинг: 0 / 0
16.01.2014, 16:54:31
    #38528556
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Akinadiego8807Переводит только первое по словарю слово (как многопроходный пример ниже). Почему?
Потому что связывание таблиц соопоставляет ОДНУ запись из таблицы dict и ОДНУ из таблицы text. Переходя к другой записи из таблицы, он берёт запись ИЗ ДРУГОЙ ТАБЛИЦЫ, а не с предыдущей итерации. Неизменённую предыдущей итерацией. Изменения на предыдущей итерации, таким образом, потеряны.

Для реализации требуемого функционала придётся задействовать переменные - точно так, как они исползуются в ФАКе по нумерации записи в группе. Читай, вникай...

Этот запрос как раз и использует переменные, но не работает всеравно.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
DROP TABLE IF EXISTS `text_temp`;
CREATE TABLE `text_temp` LIKE `text`;
INSERT INTO `text_temp`
SELECT * FROM `text`;

#сам запрос
UPDATE text_temp as t
INNER JOIN dict as d
ON t.text like CONCAT('%',d.word_en,'%')
SET t.text=IF(t.text=@text_old,
			@temp_str:=replace(@temp_str,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')),	
			@temp_str:=replace(@text_old:=t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')'))
			);		


Что тут не так?
...
Рейтинг: 0 / 0
16.01.2014, 16:58:36
    #38528561
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
diego8807Что тут не так?1) Нет понимания, как именно MySQL-сервер использует переменные. Это ни разу не PHP и не VBA, тут всё иначе...
2) Запрос написан без предварительного построения алгоритма работы. Причём алгоритма с учётом особенностей по п. 1.

У тебя тупо инициализации переменных для группы нет... да что инита - самой группировки нет! о чём вообще речь... Читай ФАК ещё раз, что ли...
...
Рейтинг: 0 / 0
16.01.2014, 17:17:11
    #38528592
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Akina,
если можно, по подробнее, Фак читал, но не понял. Разъясните теорию.

Как должен выглядеть этот запрос? Хотя бы примерно.
...
Рейтинг: 0 / 0
16.01.2014, 17:24:28
    #38528601
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Берём ФАК. Отображаем на него задачу.

В ФАКе считается номер. Переменная для номера инитится нулём (или единицей? а какая в общем разница...).
У тебя же должна посчитаться строка с подстановками. Значит, переменную надо инитить исходной строкой.

В ФАКе для каждой записи в группе к переменной прибавляется единица.
У тебя же для каждой записи должен выполняться реплейс содержимого переменной.

Поскольку у тебя в группе выполняется реплейс, т.е. для строки перебираются переводы, значит, группа - при группировке по строке из text.
...
Рейтинг: 0 / 0
16.01.2014, 17:37:46
    #38528626
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
--инит переменных
SET @temp_str:='';
SET @text_old:='';

SELECT t.text, IF(t.text=@text_old, #если текст не новый, то
	@temp_str:=replace(@temp_str,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')),	--присваиваем @temp_str:=replace(@temp_str,...)
	@temp_str:=replace(@text_old:=t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')) --присваиваем  @temp_str:=replace(text,...)
			) as text_new
FROM text_temp as t
INNER JOIN dict as d
ON t.text like CONCAT('%',d.word_en,'%')
GROUP BY text --про эту группировку идет речь?
;


не работает
...
Рейтинг: 0 / 0
16.01.2014, 17:40:17
    #38528631
artas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
diego8807,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
set @c:=0;

select max(c),id, repl from (
select * from(
select 
@c := @c + 1 as c,
if(@b!= t.id, @a:=null,@b:= t.id ),
@b:=t.id, 
t.id, 
if(@a is NULL, @a := t.`text`,@a) as q ,
@a := replace(@a,t.word_en,t.word_ru) as repl
from (
select * from text t, dict d
order by t.id
) t
) zz 
order by id, c desc
) d group by id


типа так, красоту - сам наведи
...
Рейтинг: 0 / 0
16.01.2014, 17:41:09
    #38528634
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
15425811 , пункт 1. Пока не ликвидируете этот пробел, успеха не будет.

PS. Я писАть для Вас запрос не буду. Мне достаточно видеть, как это нужно сделать, а дальше лень и неинтересно. Может, кто другой...
...
Рейтинг: 0 / 0
16.01.2014, 17:42:19
    #38528640
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
О! artas нарисовал.
ТС - везучий...
...
Рейтинг: 0 / 0
16.01.2014, 18:11:15
    #38528685
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
artas,

большое спасибо.
...
Рейтинг: 0 / 0
16.01.2014, 18:39:33
    #38528731
Arhat109
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Akina,

Заинтриговало, а почто update на сделал всё самостоятельно? Загнал пример в мускуль, попробовал и точно, заменяет только одно значение. Или я чего-то подзабыть успел?

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
--UPDATE
SELECT *, replace(t.text, d.word_en, CONCAT_WS('',d.word_en,' (',d.word_ru,')') ) AS result
FROM
text_temp as t
INNER JOIN dict as d ON t.text like CONCAT('%',d.word_en,'%')
/*
SET t.text=IF(t.text=@text_old,
	@temp_str:=replace(@temp_str,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')')),	
	@temp_str:=replace(@text_old:=t.text,d.word_en,CONCAT_WS('',d.word_en,' (',d.word_ru,')'))
)
*/		



Выборка - отработала на примере корректно: 13 записей. Да, в каждой из них заменяется только одно значение... последовательно.

Вопрос, почему update пишет обновлено ... 4 записи? По идее, он должен был пробежаться столько раз по каждой, сколько раз она сджойнилась... нет? или я чего забыть успел пока с ПХП вожусь...
...
Рейтинг: 0 / 0
16.01.2014, 18:42:23
    #38528738
Arhat109
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
вот такой update:

Код: sql
1.
2.
3.
4.
5.
6.
UPDATE
--SELECT *, replace(t.text, d.word_en, CONCAT_WS('',d.word_en,' (',d.word_ru,')') ) AS result FROM
text_temp as t
INNER JOIN dict as d ON t.text like CONCAT('%',d.word_en,'%')

SET t.text=replace(t.text, d.word_en, CONCAT_WS('',d.word_en,' (',d.word_ru,')') )
...
Рейтинг: 0 / 0
16.01.2014, 19:50:39
    #38528813
artas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
AkinaО! artas нарисовал.

что-то на работе не рабочее настроение...
...
Рейтинг: 0 / 0
16.01.2014, 22:57:31
    #38528993
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
На больших объемах (300 000 строк и словарь 500 слов) процедура оказалась быстрее
и скорость 5-ти проходной процедуры оказалась равна 1.5 скорости одного прохода по многопроходной схеме из задания. Остановился на процедуре translate:
Код: sql
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.
BEGIN
  DECLARE var CHAR(255);


  SELECT replace(lcase(text), t.word_en, concat_ws('', t.word_en, ' (', t.word_ru, ')'))
  INTO
    var
  FROM
    price.translate AS t
  WHERE
    lcase(text) LIKE concat_ws('', '%', t.word_en, ' %')
  LIMIT
    1;

  SELECT replace(var, t.word_en, concat_ws('', t.word_en, ' (', t.word_ru, ')'))
  INTO
    var
  FROM
    price.translate AS t
  WHERE
    var LIKE concat_ws('', '%', t.word_en, ' %')
    AND var NOT LIKE concat_ws('', '%(', t.word_ru, ')%')
  LIMIT
    1;

--  и так далее... (4 раза повторить предыдущий запрос)

  IF (var IS NULL) THEN
    SELECT text
    INTO
      var;
  END IF;

  RETURN var;
END



Запрос от Artas - не дождался выполнения на больших объемах (>2000 сек)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
set @c:=0;

select max(c),id, repl from (
select * from(
select 
@c := @c + 1 as c,
if(@b!= t.id, @a:=null,@b:= t.id ),
@b:=t.id, 
t.id, 
if(@a is NULL, @a := t.`text`,@a) as q ,
@a := replace(@a,t.word_en,t.word_ru) as repl
from (
select * from text t, dict d
order by t.id
) t
) zz 
order by id, c desc
) d group by id



думаю дальше...
...
Рейтинг: 0 / 0
16.01.2014, 23:40:33
    #38529019
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
diego8807На больших объемах (300 000 строк и словарь 500 слов) процедура оказалась быстрее
и скорость 5-ти проходной процедуры оказалась равна 1.5 скорости одного прохода по многопроходной схеме из задания.
Стоп! я не понял... эту хрень с подстановкой надо делать каждый раз?

Мне с самого начала казалось, что требуется одноразово обновить данные в таблице.

Кстати, это разумнее - обновить, а потом при надобности ВЫРЕЗАТЬ нахрен переводы, восстанавливая предыдущий вид. Только вместо скобок вставить что-нить залихватское, что по тексту отсутствует в принципе. Тогда если нужен перевод - заменяем это что-то на соотв. скобки, а если не нужен - вырезаем вместе с серединкой.
...
Рейтинг: 0 / 0
16.01.2014, 23:55:07
    #38529029
diego8807
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Akina, это обновления прайс-листов инет магазина. Каждый день описание товаров перевожу из прайса поставщика.

Добился более быстрого выполнения совместив оба варианта в процедуре.. в два раза быстрее и переводит точно все слова.
...
Рейтинг: 0 / 0
17.01.2014, 08:56:31
    #38529144
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
ааа... тогда навылет не понимаю, почему для редкой операции (раз в сутки небось, а то и реже) так важна скорость. Ну пусть пыхтит минуту, да пусть хоть две...
...
Рейтинг: 0 / 0
17.01.2014, 15:05:22
    #38529698
OlegROA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
Akinaааа... тогда навылет не понимаю, почему для редкой операции (раз в сутки небось, а то и реже) так важна скорость. Ну пусть пыхтит минуту, да пусть хоть две...Я вообще не понимаю, зачем реализовывать такой тормозной алгоритм - перебор каждого значения из словаря и поиск с заменой этого значения в строке текста!? Т.е., для КАЖДОГО из 500 слов словаря производится ПОЛНЫЙ проход по строке!!!

Стандартный метод - разбиваем строку текста на слова и после просты циклом проходим по этим словам, ищем их вхождение в словаре и, если нашли, заменяем. После цикла склеиваем все слова обратно в строку. Все!
Т.е., получаем не 500 проходов по каждой строке текста, а всего лишь столько, сколько в этой строке слов. Кроме этого, на каждом проходе не сканим всю строку заново, а всего лишь быстро из словаря по индексу ищем нужное слово.

Можно это сделать или в клиентской программе или в хранимке - кому, как нравится.
Если в клиентской программе, то перед переводом загружаем весь словарь в таблицу в памяти и, соответственно, не будем по каждому слову лишний раз "дергать" сервер - т.е., к базе по каждой строке текста будет всего два запроса - считать очередную строку и апдейтить её после перевода.
Если в хранимке, то слова после разбора очередной строки текста хранить во временной таблице на движке MEMORY - получаем массив в памяти, с которым работаем в обычном цикле по fetch.

Гарантирую - такой алгоритм во много раз будет быстрее любого из вышеприведенных или вновьпридуманных, которые пытаются приспособить SQL-запросы под несвойственные для них задачи!
...
Рейтинг: 0 / 0
17.01.2014, 15:50:29
    #38529795
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
OlegROAСтандартный метод - разбиваем строку текста на слова и после просты циклом проходим по этим словам, ищем их вхождение в словаре и, если нашли, заменяем. После цикла склеиваем все слова обратно в строку. Все!
Т.е., получаем не 500 проходов по каждой строке текста, а всего лишь столько, сколько в этой строке слов. Кроме этого, на каждом проходе не сканим всю строку заново, а всего лишь быстро из словаря по индексу ищем нужное слово.
Можно пойти ещё дальше, и хранить не всю строку, а разбить её на слова и хранить сами слова. Соответственно собирать строку, когда название понадобится. А в таблице слов хранить все языки, и в зависимости от параметров брать либо один язык, либо несколько. Тогда замен делать вообще не потребуется.
...
Рейтинг: 0 / 0
17.01.2014, 16:08:19
    #38529827
OlegROA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
AkinaМожно пойти ещё дальше, ...Судя по первоначальным репликам ТС, он получает уже готовый текст, который и переводит.
...
Рейтинг: 0 / 0
17.01.2014, 16:53:47
    #38529917
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
OlegROAAkinaМожно пойти ещё дальше, ...Судя по первоначальным репликам ТС, он получает уже готовый текст, который и переводит.Хранит он полученный текст у себя. Распарсить его для хранения на слова - дело плёвое.
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..) / 23 сообщений из 23, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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