На рынке частой историей является поглощение глобальными игроками локальных интернет-сервисов и ресурсов, которые дублируют их функции. Так произошло в 2017 году и с парой «Овкусе» и Cookpad, когда последний решил зайти в русскоязычный сегмент. Тогда слияние произошло успешно: российский проект был куплен и органично влился в инфраструктуру кулинарного ресурса японского происхождения, где активно развивался все эти годы. Ровно до момента, пока головной офис не принял решение уйти из региона, полностью удалив русскоязычную часть Cookpad вместе со всем имеющимся контентом.

Сегодня мы расскажем о том, как нашей команде пришлось переносить данные целого проекта на новую платформу и с чем нам пришлось столкнуться при переезде 6 миллионов фото блюд из 700 тысяч рецептов, которые создали пользователи платформы за 15 лет.

Уход Cookpad


В январе этого года в сети появилась неприятная новость: головной офис Cookpad принял решение закрыть русскоязычную часть проекта, причем в кратчайшие сроки. Соответствующая новость на cookpad-russia появилась 11 января 2023 года, а полное прекращение работы планировалось уже к 31 января:

На днях иностранный офис Cookpad Inc. принял тяжелое решение закрыть Cookpad в России с 31 января. Это удар и для всего нашего сообщества, и для российской команды, которая на протяжении 5 лет была с вами каждый день. Мы вместе с вами потеряли любимое дело.

До 31 января вы еще можете пользоваться Кукпадом, но писать новые рецепты в ближайшее время уже не получится. 31 января все российские рецепты на Cookpad станут недоступны, никто уже не сможет войти на сайт или в приложение.

Русскоязычную часть проекта надо было как-то спасать и этим занялся Александр Кисленко, экс-генеральный директор ООО Кукпэд Рус. Ему удалось договориться с головной компанией о разводе российской и глобальной части ресурса. Времени на переговоры было мало, они проходили тяжело, но всего за неделю удалось достичь результата и заключить сделку.

По итогам сделки были получены все необходимые дампы и теперь начинался следующий этап — в кратчайшие сроки создать новый ресурс и перенести на него данные, чем и занялась команда ITSumma.

Ориентация в EXIF и обработка изображений


Самым сложным дампом данных для работы был тот, в котором содержались сделанные пользователями фотографии для рецептов, потому что без них весь переезд не имел никакого смысла, они составляли основную контент-ценность.

Каждый разработчик, который сталкивался с обработкой массива пользовательских изображений под новый движок, сайт или стандарты, рано или поздно бился головой об ориентацию в формате EXIF.

Основная проблема ориентации фотографий заключается в том, что большинство фото сейчас делаются с помощью смартфона, а он оснащен гироскопом и автоматически определяет, где «верх» и «низ» фотки и на какой угол повернут аппарат. В итоге когда пользователь делает снимок, реальная ориентация, зашитая в метаданные изображения во время сьемки, может принимать причудливые значения, потому что пользователь может держать телефон в этот момент как угодно криво. Фишка в том, что любой софт для просмотра изображений предварительно сканирует метаданные файла и, если там указан поворот под углом 90 градусов влево, под углом 90 вправо, или вообще на 180 градусов, софт знает, в какую сторону нужно повернуть фотографию для того, чтобы она выглядела для вас правильно. То есть, когда вы поворачиваете смартфон на 90 градусов для того, чтобы сделать широкоформатную фотографию, реально файл сохраняется в памяти просто «на боку», а правильно его увидеть позволяют те самые данные ориентации, зашитые в EXIF.


Пример из перевода еще за 2019 год о той самой проблеме

Эту проблему отлично знает каждый, кто занимался обучением нейросетей или систем машинного зрения, ведь обучение происходит через самописный софт, в котором, конечно же, такие тонкости не учитывались, пока проблема EXIF не стала достаточно популярной из-за повального снижения эффективности обучения.

Знали ли мы об этой проблеме, когда занялись распаковкой дампов? Конечно нет!

От японцев мы получили примерно 6 млн исходников изображений.

Если бы мы просто распаковали этот дамп и прикрутили к нему стандартное решение для просмотра изображений, никаких проблем не возникло бы. Но это было 6 миллионов исходных изображений, многие весом в несколько мегабайт или даже больше. Это — огромная нагрузка на серверную часть проекта, так что было решено дамп сначала обработать, пережать, и только потом — выгружать полученный результат. Плюс это все надо было разбить на этапы, потому что пытаться заресайзить весь дамп такого размера в один подход — не самое умное решение. Ну и плюс, все равно нужно проводить промежуточный контроль результата, а это должен делать кожаный мешок, а не машина.

Были ли учтены приколы с метаданными EXIF и ориентацией кадра в этом процессе? Ответ вы знаете.

Ремонт заваленного горизонта, ресайз, перезалив


Когда мы получили первую порцию абы как повернутых изображений, мы, конечно же, слегка удивились творящейся вакханалии. И стали искать проблему. И только когда мы поняли, в чем кроется проблема, мы смогли написать корректный скрипт по обработке сорцов изображений для последующей перезаливки.

Как это было реализовано:

Сначала мы создали промежуточную таблицу images_transfer вида:

```
id
image_old_id
image_id
image_extension
image_mime_type
is_rotate
status (cropped/checked/notfound/error)
entity_type (recipe/user/etc)
entity_id
```

После был создан отдельный бакет в S3, куда мы складывали финальные версии всех оптимизированных изображений.

Далее у нас запускается скрипт проверки изображений.
Вычисляем количество:
  • утерянных изображений,
  • битых изображений,
  • изображений, у которых mime-type не соответствует расширению,
  • изображений с ориентацией в EXIF.

Результаты по каждой картинке пишем в таблицу images_transfer. Здоровые изображения на этом этапе мы помечаем статусом checked.

Далее мы на основе полученных выше данных принимаем решение, какие файлы из дампа изображений мы отправляем на ресайз, для каких оставляем оригинал, а какие вообще придётся отправить в помойку, так как они имеют формат отличный, от формата изображений. Главный и каноничный пример — файл в дампе изображений, который имеет расширение docx — это явный кандидат для отправки в утиль.

После этого мы запускаем скрипт, который чинит сломанные изображения, выравнивает их по ориентации согласно метаданным EXIF, исправляет разрешение и т.д.

Проставляем новой порции отремонтированных изображений статус checked.

Когда сорцы обработаны и готовы к ресайзу, мы запускаем уже следующий скрипт, который меняет размер изображений к определенному нам стандарту, оптимизирует размер и сохраняет в формате webp.

В этот момент наша порция файлов получает статус cropped. Тут у нас получается следующий расклад: в новом бакете собраны финальные версии наших отсортированных и оптимизированных изображений, а к ним идет вся необходимая информация в images_transfer.

Если все в порядке, мы запускаем финальный скрипт миграции БД, для того, чтобы заменить старые сорцы на новые, свежие, красивые и правильные ресайзы с помощью той самой таблицы images_transfer по полю image_old_id. Если связь имеет статус error или notfound — удаляем и считаем, что они потерялись при переезде. Это все те файлы doc и docx, битые и недогруженные изображения.

Ниже полная статистика по утерянным файлам.

RECIPE: Found 691326 IMPORTED images.
RECIPE: 691326 images will be processed.
RECIPE: 4358 - Unsupported file format tif
RECIPE: 1496 - Unsupported file format cfb
RECIPE: 137 - Unsupported file format docx
RECIPE: 3 - Unsupported file format xlsx

STEP_ATTACHMENT: Found 2037243 IMPORTED images.
STEP_ATTACHMENT: 2037243 images will be processed.
STEP_ATTACHMENT: 8043 - Unsupported file format heic
STEP_ATTACHMENT: 6856 - Unsupported file format mp4
STEP_ATTACHMENT: 2344 - Unsupported file format tif
STEP_ATTACHMENT: 1348 - Unsupported file format avi
STEP_ATTACHMENT: 783 - Unsupported file format docx
STEP_ATTACHMENT: 32 - Unsupported file format xlsx

USER: Found 2170840 IMPORTED images.
USER: 2170840 images will be processed.
USER: 9400 - Unsupported file format tif

Как видите, потери не столь велики. Кстати, как можно увидеть выше, во время обработки дампа нашлось даже пять файлов таблиц Excel, которые заливались под видом фотографий. Как, зачем и почему — загадка, хотя определенные мысли на этот счет у нас есть.


В итоге на пользовательской стороне мы получаем сочное фото вот таких сырков весом всего в ~98 кб и в разрешении 805х576 когда сорц, очевидно, был в десять, а то и двадцать раз больше

Почему перенос изображений был так важен для нас? Ну, первое, любой кулинарный сайт держится на фото процесса приготовления и итогового результата. А в нашем случае это — почти 800 тысяч рецептов. Если мы говорим о чем-то сложнее, чем жарка яиц, без фото обойтись практически невозможно, а контент-мейкеры Cookpad, а теперь и «Овкусе» — весьма умелые кулинары. Так что изображения имели практически такую же ценность, как и учетные записи наиболее активных пользователей, которые занимались генерацией контента. Заливать же содержимое дампа в сорсе без обработки — это заложить бомбу под весь проект в надежде, что она никогда не взорвется. Так что да, мы потратили немало сил и времени на то, чтобы сделать все красиво, но оно того стоило.

Также стоит понимать, что основная разработка даже веб-версии ведется с учетом требований мобильной разработки. Если статистика большинства сайтов сейчас показывает 50-70% мобильных посещений, то в нашем случае эта цифра составляет более 90%, просто исходя из пользовательского сценария: найти нужный рецепт, открыть его на смартфоне, повторять за автором. Именно для мобильных пользователей с не самыми мощными смартфонами и был приведен в порядок массив изображений, а так же оптимизирован их размер.

Сейчас мы методично занимаемся разработкой самого сайта, поэтапно реализуя и внедряя базовые функции. В отличие от других веб-проектов, которые постоянно занимаются потогоном и прикручиванием новых фичей, которые просто есть у конкурентов, кулинарная тематика — вполне «вещь в себе» и ориентируемся мы исключительно на запрос, поступающий от пользователей. Так вели разработку японцы Cookpad, так продолжаем делать и мы. И это эффективно и, что самое главное, приятно — пилить фичи не ради фичей, а потому что они реально необходимы. Попробуйте, вам тоже понравится.

Пока сайт находится в состоянии бета-версии. Часть рецептов и коллекций уже доступны, но полноценного релиза еще не было, мы над этим активно работаем.

Комментарии (4)


  1. Tinkz
    12.10.2023 08:47
    +1

    вот интересно: если обучить модель на известных рецептах, может ли она потом сгенерить новый рецепт по описанию блюда?


    1. ITSumma Автор
      12.10.2023 08:47
      +1

      Наверное это будет похоже на то, что готовил Бендер в Футураме: https://youtu.be/KLit7q0-mqk?si=0qyuwljamTybVAlr


  1. consalt
    12.10.2023 08:47
    +1

    Респект за webp


  1. Demacr
    12.10.2023 08:47
    +3

    Было бы интересно почитать про техническую сторону дела: каким образом делали, как определяли насколько сильно пожать, как определяли качество итогового, сколько сэкономили места и т.д.