2010-04-14 1 views
8

Как создать хранилище данных для огромной системы тегов (например, digg или delicious)?Как создать хранилище данных для многораздельной системы тегов?

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

Система мечения в основном имеет 3 таблицы:

Item (item_id, item_content) 

Tag (tag_id, tag_title) 

TagMapping(map_id, tag_id, item_id) 

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

Для таблицы Item, мы можем разделить его содержимое с его ключом item_id. Для таблицы Тег, мы можем разделить его содержимое с его ключом tag_id. Например, мы хотим разбить таблицу тег на базы данных K. Мы можем просто выбрать номер (tag_id% K) базы данных для хранения данных тегов.

Но, как разбить стол TagMapping?

Таблица TagMapping представляет отношения "многие ко многим". Я могу только изображение, чтобы иметь дублирование. То есть, тот же контент TagMappping имеет две копии. Один разделен на tag_id, а другой разделен на item_id. В сценарии для поиска тегов для данного элемента мы используем раздел с tag_id. Если сценарий для поиска элементов для данного тега, мы используем раздел с item_id.

В результате имеется избыточность данных. И уровень приложений должен поддерживать согласованность всех таблиц. Это выглядит тяжело.

Есть ли какое-нибудь лучшее решение для решения этой проблемы раздела «многие-ко-многим»?

ответ

4

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

Находить Теги для данного элемента

A1. Вы собираетесь отобразить все из тегов для данного предмета сразу

A2. Вы собираетесь обеспечить, чтобы все тегов пункта, являются уникальными

Поиска элементов для данной категории

B1. Вам понадобится товаров для данного тега за раз (для заполнения страницы с результатами поиска)

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

B3. Вы будете сортировать предметы для данного тега (или тегов) с определенной степенью популярности

Учитывая вышеизложенное, я думаю, что хороший подход состоял бы в разделении TagMapping по предмету. Таким образом, все теги для данного элемента находятся на одном разделе. Разделение может быть более зернистым, так как существует гораздо больше предметов, чем тегов, и каждый элемент имеет только несколько тегов. Это упрощает поиск (A1) и уникальность в одном разделе (A2). Кроме того, этот единственный раздел может сообщить вам, соответствует ли элемент нескольким тегам (B2).

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

Порядок, в котором вы выбираете разделы, будет иметь важное значение, поскольку это повлияет на то, как сгруппированы результаты поиска. Если упорядочение не имеет значения (т. Е. B3 не имеет значения), произвольно выберите разделы, чтобы ни один из ваших разделов не стал слишком горячим. Если упорядочение важно, вы можете создать идентификатор элемента, чтобы он кодировал информацию, относящуюся к порядку, в котором результаты должны быть отсортированы. Соответствующая схема разбиения будет учитывать эту кодировку. Например, если результаты являются URL-адресами, отсортированными по популярности, то вы можете объединить идентификатор последовательного элемента с оценкой Google Page Rank для этого URL-адреса (или чего-то подобного).Схема разбиения должна гарантировать, что все элементы в данном разделе имеют одинаковый балл. Запросы будут выбирать разделы в порядке счета, чтобы сначала возвращать более популярные предметы (B3). Очевидно, что это разрешает только один вид сортировки, а задействованные свойства должны быть постоянными, поскольку они теперь являются частью ключа и определяют раздел записи. На самом деле это не новое ограничение, так как нелегко поддерживать множество разновидностей или сортировать по летучим свойствам, в любом случае с разделенными данными.

+0

Я не уверен, что идея комбинированных item_id хороша. Популярность меняется во времени. Также трудно угадать популярность/рейтинг страницы/независимо при создании записи (это момент времени, когда должен быть рассчитан комбинированный item_id). – Wacek

+0

Да, я согласен и обычно не рекомендую кодировать значения в ID. Популярность со временем меняется, но не слишком быстро. Если перемещение элементов между разделами не слишком сложно, это может быть подход OK. Вы можете использовать другой идентификатор для каждого элемента в «TagMapping», который со временем может меняться легче (вместо первичного ключа элемента, который, вероятно, используется во многих других местах). Фоновый процесс может постепенно пересчитывать эти новые идентификаторы и реорганизовывать записи в «TagMapping», чтобы отражать изменения в популярности. –

1

Правило заключается в том, что вы разделяете поле, которое вы собираетесь запрашивать. В противном случае вам придется просматривать все разделы. Вы уверены, что вам нужно запросить таблицу тегов только тегом tag_id? Я считаю, что нет, вам также понадобится запрос по заголовку тега. Это не так очевидно для таблицы Item, но, вероятно, вы также хотели бы запросить что-то вроде URL-адреса, чтобы найти item_id для него, когда другой пользователь назначит для него теги.

Но учтите, что таблицы тегов и элементов имеют неизменяемый заголовок и URL-адрес. Это означает, что вы можете использовать следующую технику:

  1. Выберите раздел из заголовка (для тега) или URL (для элемента).
  2. Выберите последовательность для этого раздела для генерации идентификатора.

Вы либо используете пар partition-localID как глобальный идентификатор, либо используете неперекрывающиеся наборы чисел.В любом случае, теперь вы можете вычислить раздел из полей id и title/URL. Не знаете заранее заранее количество разделов или беспокоиться, что это может измениться в будущем? Создайте их и присоединитесь к группам, чтобы их можно было перегруппировать в будущем.

Конечно, вы не можете сделать то же самое для таблицы TagMapping, поэтому вам придется дублировать. Вам нужно запросить его map_id, tag_id, item_id, правильно? Поэтому даже без разбиения на разделы вам необходимо дублировать данные, создав 3 индекса. Поэтому разница в том, что для каждого индекса используется разное разбиение (по разному полю). Я не вижу причин беспокоиться.

1

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

Речь идет о распределении БД, обычно это проблема синхронизации. Чтение, которое составляет около 90% работы, обычно может быть выполнено в реплицированной базе данных. Проблема заключается в том, как до обновление одной БД и оставаться последовательной будет все остальные и без убийства выступлений. Это зависит от деталей вашего сценария.

Другая возможность заключается в разделении, как вы просили, всех данных без перекрытия. Вероятно, вы разделили бы идентификатор пользователя или идентификатор темы. Если вы разделяете идентификатор по теме, одна база данных может ссылаться на все темы и просто указывать, какая выделенная БД хранит данные. Затем вы можете запросить правильный. Поскольку вы разделяете по ID, вся информация, связанная с этой темой, может быть в этой специализированной базе данных. Вы также можете перечислить также язык или страна для международного веб-сайта.

И последнее, но не менее важное: вы, вероятно, закончите смешивание двух: некоторые неперекрывающиеся данные и некоторые перекрывающиеся (реплицированные) данные. Сначала найдите обычные операции, затем найдите, как сделать их на одной БД наименее возможными запросами.

PS: Не забывайте о кешировании, это спасет вас больше, чем распределенная-DB.

Смежные вопросы