[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Как реализовать скрипт "Популярное за неделю"
romeno
Здравствуйте уважаемые форумчане.

Недавно начал осваивать PHP и MySQL, создал сайт, для которого решил сделать в сайдбаре вывод популярных постов за неделю.

Создал таблицу в базе 4 колонки: id|id_post|date_v|count_v

При просмотре любого поста, в таблицу отправляется запрос проверки, на существование в таблице строки с сегодняшней датой и id_post данного поста. Если запись существует, то строка обновляется с прибавлением +1 к count_v. Если не существует, то создается такая строка с count_v=1.

Далее достаю из базы все записи за последнюю неделю, а далее ПРОБЛЕМА.

Не могу придумать как обработать все эти данные и получить 10 значений id_post у которых наибольшие суммы их count_v за неделю.

Нужно как-то суммировать все записи count_v для каждого уникального id_post, потом сортировать и выбрать первую десятку. Но как?



Спустя 7 минут, 50 секунд (7.01.2012 - 21:54) nugle написал(а):
а ты группирую по count_v, если я правильно понял задачу, то получается так
$query = mysql_query('select * from `posts` order by `count_v`');

Спустя 1 час, 19 минут, 51 секунда (7.01.2012 - 23:14) romeno написал(а):
Цитата (nugle @ 7.01.2012 - 18:54)
а ты группирую по count_v, если я правильно понял задачу, то получается так
$query = mysql_query('select * from `posts` order by `count_v`');

Так не получится. Мне нужно получить не 10 строк с наибольшим значением count_v, а 10 уникальных id_post с наибольшим количеством просмотров (в сумме).

Например в таблице будут такие записи:

id | id_post | date_v | count_v
1 |1 |11-01-01 |5
2 |2 |11-01-01 |7
3 |3 |11-01-01 |9
4 |4 |11-01-01 |4
5 |1 |11-01-02 |4
6 |4 |11-01-02 |11
7 |1 |11-01-03 |4
8 |2 |11-01-03 |5
9 |2 |11-01-04 |1
10|4 |11-01-05 |4
11|2 |11-01-05 |7
12|3 |11-01-07 |4
13|1 |11-01-09 |88
14|2 |11-01-09 |4
15|4 |11-01-09 |4
16|6 |11-01-09 |12
17|1 |11-01-11 |4
18|2 |11-01-11 |56
19|3 |11-01-12 |4
20|1 |11-01-12 |12

Ну и допустим сегодня 12.01.11 и нам нужно вытянуть самые популярные за неделю id_post. То есть вытягиваем все строки за неделю с 12-й строки по 20-ю. (Это я сделал). Далее нужно найти в этих строках одинаковые id_post например строки (12и19) (13и17и20) (14и18)(15) (16). Теперь если строк с одинаковым id_post больше одного, то все их значения count_v нужно суммировать например, для строк (12и19) это (4+4) для (13и17и20) это (88+4+12) и т.д. И теперь получив суммы нужно определить, ну допустим 3 суммы самые большие. id_post этих сум и будут идентификаторами трех самых популярных постов за неделю. (В данной таблице только данные просмотров постов, их id и дата просмотра а не сами посты)

Спустя 1 час, 41 минута, 19 секунд (8.01.2012 - 00:55) Renden написал(а):
romeno
Ну поидее в данном случае вам подойдут фунции SUM() для суммирования райтинга и ORDER BY `count_v` DESC LIMIT 3 для нахождения 3-х максимальных..

Спустя 6 часов, 6 минут, 25 секунд (8.01.2012 - 07:02) Эли4ка написал(а):
romeno
а Вы в таблице к каждой новой теме создавайте строчку имя и кол-во просмотров..и при новом просмотре увеличивайте на 1..а потом запросом и выводите ..

Спустя 4 часа, 19 минут, 14 секунд (8.01.2012 - 11:21) romeno написал(а):
Цитата (Эли4ка @ 8.01.2012 - 04:02)
romeno
а Вы в таблице к каждой новой теме создавайте строчку имя и кол-во просмотров..и при новом просмотре увеличивайте на 1..а потом запросом и выводите ..

Такой вариант подходит для вывода самых популярных постов за все время (то есть выводим десять постов и сортируем по полю [просмотры]), а мне нужно за неделю. Популярных за неделю не значит популярных, которые опубликованы за неделю, а посты которые размещены за все время но наиболее просматриваемые за неделю. То есть пост, который размещен три месяца назад просмотрели вчера 100 раз и сегодня 1раз, а пост опубликованный сегодня просмотрели только 5 раз. таким образом более популярным будет тот, который размещен три месяца назад, потому что его в сумме просмотрено за неделю 101 раз.

Но все равно спасибо за попытку помочь.

Спустя 30 минут, 31 секунда (8.01.2012 - 11:51) romeno написал(а):
Цитата (Renden @ 7.01.2012 - 21:55)
romeno
Ну поидее в данном случае вам подойдут фунции SUM() для суммирования райтинга и ORDER BY `count_v` DESC LIMIT 3 для нахождения 3-х максимальных..

Это уже ближе, но как я понимаю функция SUM() возвращает сумму всех данных столбца где (какое-то условие).

Тогда алгоритм будет такой:

1. Достать все строки за неделю
2. Получить все уникальные id_post (за неделю строк с одинаковым id_post может быть до 7)
3. Теперь функцией SUM() для каждого уникального id_post запросить сумму просмотров (я так понимаю в цикле). Функция SUM() вернет нам десять сумм наибольших (с помощью ORDER BY). А как теперь получить этих десяти сумм id_post?

1. Первый пункт - понятно.
2. Второй - не могу ничего придумать как получить только уникальные id_post.
3. По третьему - если за неделю просмотрено 5000 постов не слишком ли долго база будет высчитывать суммы просмотров? Да и как потом получить их id_post?


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

Спустя 12 минут, 41 секунда (8.01.2012 - 12:04) nugle написал(а):
дай дамп таблицы

Спустя 10 минут, 48 секунд (8.01.2012 - 12:15) uWeb написал(а):
Храните дату в unix timestamp.
WHERE `ts` > UNIX_TIMESTAMP(curdate() - interval 7 day)

Спустя 44 минуты, 45 секунд (8.01.2012 - 12:59) romeno написал(а):
Цитата (nugle @ 8.01.2012 - 09:04)
дай дамп таблицы

-- phpMyAdmin SQL Dump
-- version 3.2.3
-- http://www.phpmyadmin.net
--
-- Хост: localhost
-- Время создания: Янв 08 2012 г., 11:58
-- Версия сервера: 5.1.40
-- Версия PHP: 5.3.3

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- База данных: `post`
--

-- --------------------------------------------------------

--
-- Структура таблицы `popular_post`
--

CREATE TABLE IF NOT EXISTS `popular_post` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`id_post` int(10) NOT NULL,
`date` date NOT NULL,
`views` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=13 ;

--
-- Дамп данных таблицы `popular_post`
--

INSERT INTO `popular_post` (`id`, `id_post`, `date`, `views`) VALUES
(1, 1, '2011-12-28', 11),
(8, 1, '2011-12-29', 3),
(3, 9, '2012-01-07', 1),
(4, 8, '2012-01-07', 3),
(5, 5, '2012-01-07', 3),
(6, 2, '2012-01-07', 15),
(7, 6, '2012-01-07', 13),
(9, 1, '2012-01-07', 5),
(10, 10, '2012-01-08', 6),
(11, 6, '2012-01-08', 5),
(12, 5, '2012-01-08', 5);

Спустя 3 минуты, 35 секунд (8.01.2012 - 13:03) romeno написал(а):
Цитата (uWeb @ 8.01.2012 - 09:15)
Храните дату в unix timestamp.
WHERE `ts` > UNIX_TIMESTAMP(curdate() - interval 7 day)

И как это решит проблему?

С выборкой по дате проблем нет
WHERE date >= ( NOW() - INTERVAL 7 DAY )

Спустя 1 час, 52 минуты, 35 секунд (8.01.2012 - 14:56) nugle написал(а):
<?php 
$query = mysql_query('select * from post WHERE date_v >= ( NOW() - INTERVAL 7 DAY )');
$new = array();
while($row = mysql_fetch_assoc($query))
{
$new[$row['id_post']] = $new[$row['id_post']] + $row['count_v'];
}
var_dump($new);
?>

Спустя 1 час, 9 минут, 49 секунд (8.01.2012 - 16:05) romeno написал(а):
nugle - спасибо большое. Работает.

Суммы просмотров получено. А теперь как получить 3 id_post, у которых наибольшая сумма просмотров и вытащить из другой таблицы SELECT * FROM post_data WHERE id=id_post(массив из трех значений (сум количества просмотров) и от самого большего к самому меньшему).

Спустя 26 минут, 28 секунд (8.01.2012 - 16:32) nugle написал(а):
$query = mysql_query('select * from popular_post WHERE date >= ( NOW() - INTERVAL 7 DAY )');
$new = array();
$max = array();
while($row = mysql_fetch_assoc($query))
{
$new[$row['id_post']] = $new[$row['id_post']] + $row['views'];
}
$max[0] = reset($new);
$max[1] = reset($new);
$max[2] = reset($new);

var_dump($new);

foreach($new as $key=>$val)
if($val > $max[0])
$max[0] = $val;

$max[1] = for_each($max[1], $max[0], $new);
$max[2] = for_each($max[2], $max[1], $new);

function for_each($var1, $var2, $arr){
foreach($arr as $key=>$val)
if($val > $var1 && $val < $var2)
$var1 = $val;
return $var1;
}

var_dump($max);

Спустя 1 час, 8 минут, 47 секунд (8.01.2012 - 17:41) romeno написал(а):
nugle - благодарю Вас за то, что тратите свое время.

В результате я получил 3 наибольшие значения массива $new, а мне нужны их ключи.

Я порылся в различных мануалах и у меня получилось так:


$query = mysql_query('select * from post WHERE date_v >= ( NOW() - INTERVAL 7 DAY )');
$new = array();
while($row = mysql_fetch_assoc($query))
{
$new[$row['id_post']] = $new[$row['id_post']] + $row['views'];
}

arsort($new); //сортировка
$array_keys_new = array_keys($new); //выборка ключей
$array_slice_new = array_slice($array_keys_new,0,3); //выборка первых трех результатов




Можно ли так делать и как теперь обратиться к другой таблице с постами на выборку строк у которых id= $array_slice_new[0], id= $array_slice_new[1], id= $array_slice_new[2]

Спустя 17 минут, 11 секунд (8.01.2012 - 17:58) nugle написал(а):
А что мешает создать двумерный массив? Усложним не много
$query = mysql_query('select * from popular_post WHERE date >= ( NOW() - INTERVAL 7 DAY )');
$new = array();
$max = array();
while($row = mysql_fetch_assoc($query))
{
$new[$row['id_post']] = $new[$row['id_post']] + $row['views'];
}

$first = reset($new);
$first_key = array_shift(array_keys($new));

$max[0]['key'] = $first_key;
$max[0]['val'] = $first;
$max[1]['key'] = $first_key;
$max[1]['val'] = $first;
$max[2]['key'] = $first_key;
$max[2]['val'] = $first;


var_dump($new);

foreach($new as $key=>$val)
if($val > $max[0]['val'])
{
$max[0]['val'] = $val;
$max[0]['key'] = $key;
}

$max[1] = for_each($max[1], $max[0], $new);
$max[2] = for_each($max[2], $max[1], $new);

function for_each($var1, $var2, $arr){
foreach($arr as $key=>$val)
if($val > $var1['val'] && $val < $var2['val'])
{
$var1['val'] = $val;
$var1['key'] = $key;
}
return $var1;
}

var_dump($max);

Спустя 45 минут, 14 секунд (8.01.2012 - 18:43) romeno написал(а):
nugle А так как описал я неправильно? Просто, смотрите: если нам нужно вытянуть только три ключа, то хорошо можно сделать, так как Вы указали. А если завтра нам понадобится вытянуть не 3 а 10, то нужно будет добавлять кучу кода, в моем же случае достаточно будет изменить один параметр в array_slice из 3 на 10. Но я не уверен правильно ли построена программа.


$query = mysql_query('select * from post WHERE date_v >= ( NOW() - INTERVAL 7 DAY )');
$new = array();
while($row = mysql_fetch_assoc($query))
{
$new[$row['id_post']] = $new[$row['id_post']] + $row['views'];
}

arsort($new); //сортировка
$array_keys_new = array_keys($new); //выборка ключей
$array_slice_new = array_slice($array_keys_new,0,3); //выборка первых трех результатов


Но в любом случае спасибо большое за помощь.

Спустя 7 минут, 44 секунды (8.01.2012 - 18:51) nugle написал(а):
у вас все правильно.

Спустя 1 час, 56 секунд (8.01.2012 - 19:52) romeno написал(а):
Цитата (nugle @ 8.01.2012 - 15:51)
у вас все правильно.

Тогда последний вопрос: Как извлечь данные постов из другой таблицы где id=id_post[3 значения] или теперь уже id=масиву $array_slice_new и сортировать вывод как в массиве $array_slice_new. То есть сначала должно идти строка где id=$array_slice_new[0] потом id=$array_slice_new[1] и т.д.


mysql_query ('SELECT * FROM post_data WHERE id=все значения масива $array_slice_new ',$db)

Спустя 8 часов, 8 минут, 27 секунд (9.01.2012 - 04:00) FatCat написал(а):
Делал для этого форума рейтинг тем на главной странице.
У нас сделано не за последнюю неделю, а за всё время существования ресурса.
В БД пишется только число просмотров: при каждой генерации страничку поле просмотров увеличивается на единичку.

Запрос:
SELECT ... , 
(
6*(".time()."-t.start_date)/(".time()."-".$INFO['board_start'].")+1)*t.views/(".time()."-t.start_date) AS keyder
...
ORDER BY keyder DESC

Здесь:
start_date - юниксштамп создания топика;
$INFO['board_start'] - юниксштамп запуска форума;
views - число просмотров темы.

Дальше в цикле по результатам запроса формируется список рейтинга:
$list_top10 = "<ol style='margin-top:0px;margin-bottom:0px;margin-left:28px'>";
while ( $top10 = $DB->fetch_row() ){
$list_top10 .= "<li><a style=color:#306284 href='index.php?showtopic=".$top10['tid']."'>".$top10['title']."</a>";
if($top10['description'] != "")$list_top10 .= "<br>".$top10['description'];
$list_top10 .= "<br>(Рейтинг просмотров: ".round(12343*$top10['keyder'])).")";
}
$list_top10 .= "</ol>";


Результат можно посмотреть у нас на главной странице.

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

Спустя 6 часов, 12 минут, 33 секунды (9.01.2012 - 10:13) romeno написал(а):
Это на сколько я понял популярность относительно создания. То есть если я создал тему и в течени часа у нее 100 просмотров то она будет выше чем тема у которой 100 просмотров но созданная она вчера.

А мне нужно так: за неделю опубликовано 3 поста. На сайте уже есть к примеру 100 постов. За неделю просмотрено 70 постов включая 3 опубликованные за неделю (или нет - не важно). Мне нужно посчитать какой пост сколько просмотрено за неделю и вывести список допустим 10 у которых наибольшее число просмотров (именно за неделю).

Пост может быть создан год назад но на этой неделе он популярен.

Спустя 3 часа, 4 минуты, 51 секунда (9.01.2012 - 13:18) nugle написал(а):
$array_slice_new - это у тебя массив собираешь его в строку
$array_slice_new = implode(',', $array_slice_new);
обрезаешь
$array_slice_new = trim($array_slice_new, ',');
делаешь выборку
$query= mysql_query('select * from table where id in('.$array_slice_new.')');

Спустя 58 минут, 41 секунда (9.01.2012 - 14:16) romeno написал(а):
Цитата (nugle @ 9.01.2012 - 10:18)
$array_slice_new - это у тебя массив собираешь его в строку
$array_slice_new = implode(',', $array_slice_new);
обрезаешь
$array_slice_new = trim($array_slice_new, ',');
делаешь выборку
$query= mysql_query('select * from table where id in('.$array_slice_new.')');

Работает, но сортирует по id, а нужно в том порядке, в каком идут в $array_slice_new

Спустя 7 минут, 56 секунд (9.01.2012 - 14:24) nugle написал(а):
Собираешь вывод в массив(ключом делаешь id), потом проходишься циклом по $array_slice_new и меняешь местами

Спустя 41 минута, 40 секунд (9.01.2012 - 15:06) romeno написал(а):
Цитата (nugle @ 9.01.2012 - 11:24)
Собираешь вывод в массив(ключом делаешь id), потом проходишься циклом по $array_slice_new и меняешь местами

Знаю, что достал с вопросами но моего уровня не достаточно что бы осуществить то, что Вы написали. С выводом из базы в массив понятно, а дальше?

Спустя 3 часа, 50 минут, 16 секунд (9.01.2012 - 18:56) nugle написал(а):
Как то так
$query= mysql_query('select * from table where id in('.$array_slice_new.')');
while($row = mysql_fetch_assoc($query))
{
$array[$row['id']] = $row['value'];
}

foreach($array_slice_new as $key=>$val)
{
echo $array[$val];
}
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.