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

Задача:
Нужно перевести текст `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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528525
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
diego8807,

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

Для реализации требуемого функционала придётся задействовать переменные - точно так, как они исползуются в ФАКе по нумерации записи в группе. Читай, вникай...
...
Рейтинг: 0 / 0
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528556
diego8807
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528561
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
diego8807Что тут не так?1) Нет понимания, как именно MySQL-сервер использует переменные. Это ни разу не PHP и не VBA, тут всё иначе...
2) Запрос написан без предварительного построения алгоритма работы. Причём алгоритма с учётом особенностей по п. 1.

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

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

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

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

Поскольку у тебя в группе выполняется реплейс, т.е. для строки перебираются переводы, значит, группа - при группировке по строке из text.
...
Рейтинг: 0 / 0
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528626
diego8807
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: 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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528631
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528634
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
15425811 , пункт 1. Пока не ликвидируете этот пробел, успеха не будет.

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

большое спасибо.
...
Рейтинг: 0 / 0
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528731
Arhat109
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528738
Arhat109
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот такой 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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528813
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AkinaО! artas нарисовал.

что-то на работе не рабочее настроение...
...
Рейтинг: 0 / 0
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38528993
diego8807
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
На больших объемах (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
Перевод текста по словарю (UPDATE .. INNER JOIN .. SET ..)
    #38529019
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
diego8807На больших объемах (300 000 строк и словарь 500 слов) процедура оказалась быстрее
и скорость 5-ти проходной процедуры оказалась равна 1.5 скорости одного прохода по многопроходной схеме из задания.
Стоп! я не понял... эту хрень с подстановкой надо делать каждый раз?

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

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

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

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

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

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


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