8 авг. 2015 г., 14:08

Организация хранения данных об изображениях галереи

Классическая схема физического хранения изображений галереи — набор папок для каждого ресурса, внутри — графические файлы. Для отображения на сайте изображений некоторого ресурса просто-напросто берём графические файлы из папки, соответствующей нашему ресурсу. Просто и логично.
Но в моём случае: а) каждый графический файл может быть связан с одним и более ресурсами одновременно (а в некоторые моменты времени может быть не связан ни с одним из ресурсов) б) каждый графический файл имеет с десяток характеристик (по которым будет выполняться сортировка/фильтрация) в) каждый графический файл будет иметь комментарии пользователей г) каждый графический файл будет иметь свою собственную страницу на сайте (с описанием, характеристиками, комментариями и пр.)
Очевидно, что простым хранением графических файлов в тех или иных папках здесь не обойтись — нужно ещё хранить данные о каждом изображении. Возможны 2 варианта:
ВАРИАНТ 1. Для каждого графического файла создаётся отдельный ресурс (типа «Документ» или «Статический ресурс») с TV-параметрами
Преимущества: 1.Обслуживание, управление и формирование характеристик изображений выполняется стандартными средствами modx (характеристики, вычисляемые автоматически путём анализа изображения, легко реализуются на уровне плагинов) 2.Загрузка страниц, посвящённых изображениям, будет выполняться без каких-либо проблем стандартными средствами modx (как и страницы любых других ресурсов) 3.Легко прикрутить готовые компоненты для работы с комментариями (при хранении в собственных таблицах придётся писать свою систему комментариев) 4.Число просмотров, число комментариев и прочие realtime-характеристики будут обрабатываться теми же средствами, которые работают в отношении прочих ресурсов
Недостатки: 1.Быстрее себя проявит проблема большой карты ресурсов 2.Чуть медленнее будет выполняться фильтрация и сортировка по TV этих изображений. Впрочем это проблема/особенность архитектуры modx (а вернее, т.н. универсальных БД), а никак не проблема выбранного варианта хранения данных изображений
ВАРИАНТ 2. Информация о каждом изображении хранится в отдельной таблице
Преимущества: 1. Проблема большой карты ресурсов будет проявляться в существенно меньшей степени 2. Чуть быстрее будет работать фильтрация и сортировка по характеристикам изображений
Недостатки: 1.Интерфейс для формирования и просмотра характеристик изображений придётся разрабатывать свой 2.Систему комментариев придётся разрабатывать свою 3.Существенно урезаются стандартные возможности modx по работе с изображениями на уровне чанков и сниппетов (например, использование тегов [[~id]]) 4.Для изображений придётся разрабатывать отдельную систему управления числом просмотров, числом комментариев и прочими realtime-характеристиками. Либо расширять возможности существующей системы (работающей со стандартными ресурсами modx) в направлении использования пользовательских таблиц.
— Склоняюсь к первому варианту. В случае с отдельной таблицей дофига всего писать придётся (и всё написанное придётся постоянно корректировать синхронно с изменениями архитектуры/ядра и логики работы modx). Ваше видение ситуации? Собственно, интересует не только оптимальный с вашей точки зрения вариант, но и другие ньюансы и потенциальные проблемы (в обоих вариантах), которые я не учёл.
2.Чуть медленнее будет выполняться фильтрация и сортировка по TV этих изображений. Впрочем это проблема/особенность архитектуры modx (а вернее, т.н. универсальных БД), а никак не проблема выбранного варианта хранения данных изображений
Если речь о десятках и более тысяч документов, то это поможет: habrahabr.ru/post/253737/
Здравствуйте, Николай. В тему по Вашей ссылке задам вопрос. Недавно реализовывал то, о чём Вы там писали. Возможности значительно расширяются с подобным подходом. БлагоДарю Вас от всей Души! Однако, не удалось обращаться к своим данным из таблицы site_content, как к стандартным, через плейсхолдеры. К примеру так [[*logo]], пришлось писать сниппет, который восполнил мои нужды (подтягивал данные полей отмеченных в параметре у указанного ресурса). Отсюда вопрос: так и должно быть, или я что-то не так сделал?
P.S.: Немножко дописывал Ваш плагин, который Вы указали на Хабре. Хотел сначало выложить куда-то и скинуть Вам, а потом подумал — зачем Вам нужен мой ГК. :) И раз уж пишу тут, всё-таки предложу. Если интересно — напишите, я выложу куда-нибудь.
ВАРИАНТ 1. Для каждого графического файла создаётся отдельный ресурс (типа «Документ» или «Статический ресурс») с TV-параметрами
Пожалейте тех, кому потом придется с такой галереей работать.
К примеру так [[*logo]], пришлось писать сниппет, который восполнил мои нужды (подтягивал данные полей отмеченных в параметре у указанного ресурса). Отсюда вопрос: так и должно быть, или я что-то не так сделал?
Так вы в смарти-шаблоне попробуйте прописать {$modx->resource->logo}. Так же getdata-процессоры вернут массивы данных ресурсов, содержащих элемент logo. Собственно, мы плейсхолдеры особо не юзаем.
C другой стороны, если «каждый графический файл будет иметь свою собственную страницу на сайте (с описанием, характеристиками, комментариями и пр.)», то разве это галерея? В моем понимании, в галерее создаются изображения, а тут получается, что создаются страницы.
Если речь о десятках и более тысяч документов, то это поможет: habrahabr.ru/post/253737/
Вариант хороший. На первый взгляд, даже идеальный: а) никакие join'ы не требуются б) каждое поле индивидуально типизировано и проиндексировано — как следствие, сортировка и фильтрация будут выполняться максимально быстро и корректно (для строковых значений сравнение строковое, для числовых — числовое) в) данные занимают меньше места за счёт индивидуальной типизации (верно, только если оригинальные значения TV-параметров из стандартной таблицы с TV будут удаляться)
Но этот вариант не всегда реализуем. Как, например, в моём случае. У меня более десяти типов ресурсов, у каждого — по 15-20 TV. Итого — сотни TV. Сортировка и фильтрация выполняется по большинству из них. Да, можно все эти TV (по которым выполняется сортировка и фильтрация) автоматом закинуть в (site_content) и индивидуально типизировать на основе характеристик TV. И сделать всё это программно (имя поля = tv_{id}). В mySQL допускается 4 тысячи полей в таблице. Этого с головой хватит и на текущий, и на будущий функционал. Но проблема в том, что работать с этими полями без индексов не имеет смысла, а максимально допустимое число индексов в таблице mySQL — 64. Вот это ограничение и является определяющим. Даже если для некоторых полей создавать составные индексы, всё равно индексов понадобится более 100. К тому же со временем функционал будет только расширяться, добавляться новые типы ресурсов и новые TV-поля.
Сейчас у меня реализован следующий вариант: а) все TV-поля дублируются в поле (properties) таблицы ресурсов (в формате json) — это поле используется для выборки TV б) при фильтрации и сортировках подключаются через JOIN только те TV, которые участвуют в этих фильтрах/сортировках (как правило, их не более 3 за раз, а 3 JOIN'а выполняются вполне себе быстро) в) в случаях, когда ресурс имеет большое количество TV, а в конечной выборке необходимо получить 2-3 TV-ки, эти TV join'ятся (так быстрее: на json-декодирование большого числа TV нужно время), в остальных случаях для выборки использую поле (properties) с последующим json-декодированием
Если вся суть проекта крутится вокруг этой галереи, то такой подход предпочтительней. УРЛы, параметры индексации, ТВ-параметры и все такое.
И раз уж пишу тут, всё-таки предложу. Если интересно — напишите, я выложу куда-нибудь.
Чессказать времени совсем нет что-то смотреть. Сорри.
в) данные занимают меньше места за счёт индивидуальной типизации (верно, только если оригинальные значения TV-параметров из стандартной таблицы с TV будут удаляться)
Они удаляются.
В целом по проекту: сочувствую…
Пожалейте тех, кому потом придется с такой галереей работать.
Например, Василий, я уверен, выбрал бы именно такой вариант (отдельная таблица). А что там за проблемы возникнут при работе с такой галереей?
то разве это галерея? В моем понимании, в галерее создаются изображения, а тут получается, что создаются страницы.
Ну так комментарии к изображению, описание изображения, списки ресурсов, с которыми связано изображение и прочая информация, касающаяся конкретного изображения должна же на какой-то странице отображаться. Можно и для такой страницы создать один специальный ресурс+шаблон и выводить там запрошенное изображение со всей информацией. Но в плане SEO эффективнее будет оформить в виде таких страниц сами ресурсы, отвечающие за изображения. Других вариантов нет. Впрочем, это уже не суть важно, как это всё организовать. Кому как нравится. Важно то, как и где организовать хранение данных об изображениях.
В целом по проекту: сочувствую…
В смысле, я что-то не то делаю? Или проект на modx труднореализуем?
Он просто труднореализуем:) Не важно на чем. Но не безнадежен.
Моя реплика относится к «Для каждого графического файла создаётся отдельный ресурс (типа «Документ» или «Статический ресурс») с TV-параметрами» — у Василия я кину на страницу 100 файлов и готово, а тут 100 раз «создать ресурс» — «открыть файл-браузер» — «загрузить картинку» — «выбрать картинку» — «сохранить ресурс».
У Василия вариант 2 получается, потому что ms2Gallery рассчитана на то, чтобы на странице ресурса вывести много картинок. И я бы тоже выбрал вариант 2, но в вашем случае получается, что отдельная страница на картинку, куча характеристик, комментарии — то есть скорость работы с картинками в ms2Gallery нивелируется скоростью заполнения характеристик для каждой картинки. То есть для пользователя будет почти одинаково, что вариант 1, что вариант 2, зато для вас быстрее будет сделать вариант 1.
а) все TV-поля дублируются в поле (properties) таблицы ресурсов (в формате json) — это поле используется для выборки TV
Есть еще вариант дублировать их в отдельную таблицу (:
Чем сложнее проект, тем меньше потенциальных конкурентов
Есть еще вариант дублировать их в отдельную таблицу (:
Тогда для каждого типа ресурсов придётся свою таблицу создавать с TV (из-за ограничения на число индексов в одной таблице). Ну а коли для каждого типа ресурсов будет своя таблица, то и сами ресурсы логично будет хранить в этих таблицах. А коли ресурсы будут храниться в отдельных таблицах, тогда и modx не нужен.
А еще тем выше риски, издержки и т.п., и соответственно ниже профит и больше срок окупаемости. Тут не все так однозначно.
В своём проекте я не использую какие-либо сторонние сниппеты и компоненты (кроме компонентов для работы с комментариями), поскольку ни один компонентов не обеспечивает требуемого функционала проекта. Даже элементарно хлебные крошки, пагинация, баннеры, псевдонимы, uri, ajax-подгрузка, редиректы, SEO и многое другое — всё это реализовано собственным кодом с индивидуальной логикой. Соответственно, и сабжевый вопрос подразумевает написание собственного интерфейса для загрузки изображений (но только для загрузки). Именно поэтому, я и не рассматриваю здесь возможность использования сторонних компонентов в качестве критерия выбора. Ну а собственный интерфейс для загрузки изображений будет обеспечивать возможность загрузки и одного изображения, и нескольких одновременно (с указанием характеристик для каждой из них).
У Василия вариант 2 получается, потому что ms2Gallery рассчитана на то, чтобы на странице ресурса вывести много картинок.
И в вариантах 1 тоже просто вывести много картинок на странице. Только браться они будут не из одной папки на диске (соответствующей одному ресурсу), а из нескольких (зависит от физической организации папок с изображениями) — т.е. делаем выборку требуемых ресурсов-изображений по их TV-характеристикам и получаем url'ы физических файлов.
В случае с ms2Gallery — там ведь нет характеристик у каждого изображения? И связь изображений с ресурсами М:1, а у меня — М: М
> Если речь о десятках и более тысяч документов, то это поможет: habrahabr.ru/post/253737/ > Но этот вариант не всегда реализуем. Как, например, в моём случае. > В целом по проекту: сочувствую…
Некоторые TV всё-таки пришлось разместить в таблице ресурсов. А именно — числовые поля. И только те числовые, по которым выполняется фильтрация (на больше/меньше) и сортировка. Т.к.: а) во всех остальных случаях фильтрация и сортировка вполне себе нормально отработает и по строковым TV (с использованием индекса) б) с числовыми TV-полями при выполнении сортировки и фильтрации (на больше/меньше) пришлось бы выполнять преобразование на лету и как следствие, полный перебор БЕЗ использования индексов в) в нашем распоряжении имеется всего 44 индекса (64 минус 20 стандартных), соответственно, все TV в таблицу ресурсов не закинешь. Закидываю только необходимый минимум (числовая сортировка/фильтрация)
Но логику, описанную в статье, немного изменил (под свой проект): 1.Числовые TV не перемещаю в таблицу ресурсов, а копирую. Памяти уходит больше, но упрощается логика + повышается безопасность (если что «поломается», всегда можно восстановить значения из стандартных TV) 2.Схему (modx->map) дополняю новыми полями также на лету, но не вручную, а программно — на основе структуры таблицы в БД (использую генератор xPDOGenerator) 3.Описание индексов новых полей в (modx->map) не помещаю, т.к. индексы xpdo нужны только для генерации таблиц в БД (или нужны для чего-то ещё ?)
— Таким образом, получилась гибридная система TV-параметров: 1.Для выборки TV используется поле (properties) 2.Для фильтрации и сортировки по числовым полям используются собственные поля в таблице ресурсов (числовое сравнение) 3.Для фильтрации и сортировки по строковым полям — TV-поля подключаются через join (строковое сравнение)
При такой организации TV: а) и выборку большого числа TV можно будет сделать довольно быстро (без кучи JOIN'ов) б) можно быстро (с использованием индекса) выполнять фильтрацию и сортировку как по строковым полям (строковое сравнение), так и по числовым полям (числовое сравнение), исключая преобразование типов на лету в) можно не заморачиваться тем, что в таблице ресурсов остаётся всего 44 индекса для собственных полей (для числовых полей, по которым выполняется фильтрация/сортировка, их всем хватит)
И здесь как всегда проблема с индексами возникает. Если, например, в таблице ресурсов мы создаём числовое поле (sCount) и индекс idx_sCount по этому полю, то при выполнении запросов, в которых выполняется фильтрация и по полю published (или deleted), и по числовому полю (sCount) (не важно, в какой последовательности), то MySQL будет использовать индекс published, а не idx_sCount (как этого следовало бы ожидать) — это приведёт к почти полному перебору всех ресурсов (если положить, что почти все ресурсы являются опубликованными). Аналогично и с (deleted). При этом если в таблице будет индекс по обоим этим полям, то MySQL выберет именно этот индекс (как и должно быть).
Решить проблему можно 3 способами: 1.Для каждого запроса указывать необходимый индекс. Сложности этого способа очевидны: — сложна реализация (xpdo индексы не поддерживает) — необходимый индекс придётся указывать для каждого запроса и при изменении имени или структуры индекса придётся все эти запросы пересматривать
2.Для собственных полей указывать составные индексы, начинающиеся со стандартных полей и заканчивающиеся собственными полями (например: idx_published_sCount, idx_classKey_deleted_published_sCount). Но в этом случае часть существующих запросов может начать тормозить, поскольку при наличии 2, 3 и более индексов, начинающихся со стандартных полей, MySQL на некоторых запросах (предположительно, с конструкцией IN + может зависеть и от версии MySql) начинает очень долго выбирать оптимальный индекс: modxclub.ru/topics/vyiborka-iz-%28modtemplatevarresource%29-sushhestvennoe-uskorenie-pri-yavnom-ukazanii-indeksa-1759.html#comment-7177
3.Для собственных полей указывать составные индексы, начинающиеся с собственных полей и заканчивающиеся стандартными (например: idx_sCount_published, idx_sCount_classKey_deleted_published). В этом случае эти индексы MySQL будет рассматривать в качестве возможных только в тех запросах, в которых используются наши собственные поля. И при этом в тех запросах, в которых присутствуют условия и по стандартным полям, и по нашим полям, будет использовать именно эти (наши) составные индексы, а не простые стандартные.
3.Описание индексов новых полей в (modx->map) не помещаю, т.к. индексы xpdo нужны только для генерации таблиц в БД (или нужны для чего-то ещё ?)
Нужны только для генерации. Но если вдруг будете потом на основе мапы таблицу создавать, то конечно же они понадобятся.

Добавить комментарий