построение базы данных кнопки «Мне нравится» (например, «Нравится» в Facebook или Google +1)

Я хочу знать структуру базы данных кнопки «Мне нравится», такой как Facebook или Google +1 и так далее.

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

Система должна определить, что пользователю понравилось или не понравилось это сообщение раньше, чтобы показать пользователю кнопку «Не нравится» или «Нравится».

Но как работает эта функция и как устроена база данных?

Я понял этот метод:

Каждое сообщение/публикация имеет столбец like для сохранения сериализованных пользовательских данных.

Post table
id           content                                like(serialized user_id)
1           hi world                 a:4:{i:0;i:234;i:1;i:32;i:2;i:423;i:3;i:4215;}
2      this is a good day            a:2:{i:0;i:2324;i:1;i:342;}

и десериализовать и определить user_id перед выводом сообщения

while($row=mysql_fetch_row($sqlresult))
{
  $like_data_array = unserialize($row['like']);
  if( in_array( $user_id , $like_data_array ) )
  {
     echo 'you liked this post';
     echo '<button>unlike</button>';
  }
  else
  {
     echo '<button>like</button>';
  }
}

Но я думаю, что этот метод слишком медленный для большого количества лайков. Особенно пост имеет более 100 000+ лайков.

Есть ли более эффективная конструкция?


person Angolao    schedule 27.08.2011    source источник
comment
@atif089 atif089 да, я нашел эффективный способ решить эту проблему.   -  person Angolao    schedule 17.11.2011
comment
@Angolao Я не думаю, что atif089 задал этот вопрос только для того, чтобы узнать о вас больше. Думаете ли вы о том, чтобы поделиться своим эффективным решением, точно так же, как вы требуете, чтобы другие люди поделились своим эффективным решением?   -  person Xfce4    schedule 02.01.2021


Ответы (3)


В нормализованных базах это делается с помощью трех таблиц:
users — со столбцами: id, name и т.д.
posts — со столбцами: id, content и т.д.
likes — со столбцами: user_id, post_id (user_id — это внешний ключ от пользователей, post_id — это внешний ключ от сообщений)
Итак, если вы хотите узнать, понравился ли пользователю определенный пост, выполните что-то вроде следующей команды:

SELECT * FROM likes WHERE post_id = 123456 AND user_id = 1000
person Andrei Bozantan    schedule 27.08.2011
comment
Этот метод будет создавать все больше и больше запросов MySQL для вывода контента. Это кажется более неэффективным. - person Angolao; 27.08.2011
comment
Что вы хотите сделать, так это создать отношения «многие ко многим» между сообщениями и пользователями. То, что я описал выше, является стандартным способом создания такого рода отношений в SQL (реляционной) базе данных. Конечно, каждый раз, когда вы хотите проверить, например, какие пользователи лайкнули определенный пост, вы должны динамически создавать запрос на основе post_id, но это не проблема. Также вы можете проверить ответ, данный @Qualcuno, который содержит некоторые причины, по которым ваш подход не будет работать правильно в долгосрочной перспективе с MySQL. - person Andrei Bozantan; 27.08.2011
comment
Да, но попробуйте представить ситуацию, когда на сайте социального сообщества очень часто отображается более 20-30 сообщений на домашней странице пользователя. Чтобы отобразить эту страницу, вы имеете в виду, что вам нужно создать 20-30 запросов MySQL, чтобы прочитать количество лайков для сообщения и проверить, понравилось ли или не понравилось пользователю сообщение, и один запрос MySQL, чтобы прочитать те 20-30 сообщений от друзей, которые пользователь следил? Кроме того, домашняя страница пользователя автоматически обновляет новое сообщение или обновляет их страницу, поэтому я буду создавать все больше и больше запросов для обработки этих данных. Но по-моему, я только что создал только один запрос MySQL. - person Angolao; 31.08.2011
comment
Вы создаете один запрос для всей страницы. Смотрите мой комментарий выше! - person ItalyPaleAle; 01.09.2011

Если бы я хотел сделать это с MySQL (или любой другой реляционной базой данных), я бы, конечно, сделал так, как предложил Андрей. Это "правильный" путь! Собственно, для этого у нас и есть реляционные базы данных. При правильном проектировании с кешированием (memcached et similia, а также кеширование запросов MySQL) это не совсем неэффективно.

anlai, ваше предложение добавить столбец с сериализованными данными "неверно" по разным причинам:

  1. Это не очень хорошо в средах с большим числом одновременных подключений, таких как Facebook. Поскольку вы всегда обновляете строку, ваш поток выглядит следующим образом: считывание значения из MySQL, изменение его в приложении, обновление значения в MySQL. Чтобы предотвратить проблемы параллелизма, вам придется сделать это в одной транзакции, тем самым заблокировав строку на (относительно) долгое время. Это очень плохо, если у вас есть тысячи одновременных запросов, желающих сделать одно и то же.
  2. «текстовые» столбцы имеют максимальную длину. Таким образом, вы можете добавить максимальное количество лайков. Кроме того, постоянно увеличивая поле, вы вносите большую фрагментацию в файл базы данных. Это действительно неэффективно!
  3. И последнее, но не менее важное: это неправильный способ использования RDMS (системы управления реляционными базами данных), как MySQL, говоря «философски».

В любом случае, все здесь ответили, думая, что СУБД... Но что, если бы Facebook не использовал СУБД? (И, вероятно, это не так!) Мы в 2011 году, у нас тоже есть базы данных «NoSQL» :)

Возьмем, к примеру, MongoDB. С его страницами без схемы вы можете создать коллекцию «сообщений», например:

posts.url = url of the like
posts.likes = array of users who liked (for example posts.like = [{name: "john Doe", uid: 12}, {name: "Mario", uid: 43}] ).

Делая это таким образом, вам не нужно запрашивать другие таблицы. Обновления (вставка нового элемента в массив posts.like) являются атомарными операциями, поэтому вам не нужно беспокоиться о проблемах параллелизма. И именно для этого предназначена MongoDB (или другая нереляционная СУБД).

person ItalyPaleAle    schedule 27.08.2011
comment
Хорошо, но в обычной ситуации нажатие кнопки «Нравится» не является обязательным событием. Впечатляет, что у одного поста более 1000 лайков, поэтому просто выполните SELECT -> unserialize -> array_push -> serialize -> UPDATE более 1000 раз. Но домашняя страница пользователя будет загружать более 10 000 просмотров страниц (это не слишком много, верно?) в обычной ситуации. Таким образом, вам нужно создать более 150 000 запросов, чтобы вывести сообщение и загрузить количество лайков и проверить, понравился ли или не понравился пользователю этот пост. Лучше ли это для высококонкурентных сред? - person Angolao; 31.08.2011
comment
Если бы я был вами, я бы ДЕЙСТВИТЕЛЬНО рассмотрел способ NoSQL для этого. В любом случае, если вам нужен MySQL... Например, вы должны сначала выбрать все сообщения (SELECT * FROM user_wall WHERE user_id = ?), а затем выбрать все лайки (SELECT count(like_id) FROM post_likes WHERE post_id IN ([list of post_ids ]) GROUP BY post_id), а затем получить идентификаторы пользователей (SELECT * FROM users WHERE user_id IN(...) ). Всего 3 запроса! (Я предлагаю вам не запрашивать каждое сообщение, а запрашивать все сообщения одновременно). Сериализация плоха ещё и тем, что у вас есть ограничение на количество лайков! - person ItalyPaleAle; 01.09.2011

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

Я действительно не думаю, что Facebook делает специальную оптимизацию для кнопок «Нравится», отличную от распределения кешей для областей пользователей (например, наличие предварительно запрошенного набора данных для пользователей, которые вошли в систему). И у Facebook действительно огромная база пользователей.

person Pedro Montoto García    schedule 27.08.2011
comment
Если Facebook использует Memcached для кэширования подобных данных, я думаю, что это все еще большой проект по поиску понравившегося user_id, поиску большого массива, включающего 100 000 user_id? - person Angolao; 27.08.2011
comment
memcached хранит все в памяти, а все ключи вставляются в хеш-таблицу (бинарное дерево). Таким образом, это BLAZING быстро. Поиск элемента в списке из 100 000 идентификаторов пользователей занимает очень короткое время (сложность — O(log2(n)), поэтому для поиска 1 из 100 00 вам нужно выполнить около 16 итераций!) - person ItalyPaleAle; 27.08.2011