Kuasar

Рейтинг
185
Регистрация
16.12.2009
LikeAVirgin:
У меня имиджевые рекламные кампании постоянно идут, например, реклама крупных брендов

Поделитесь секретом, где вы их находите и как договариваетесь?

Мне бы парочку таких рекламодателей найти, чтобы заполнить порожний баннерный трафик.

Если цену привязывать к CTR, то не проще ли сделать просто фиксированную стоимость клика?

А какому типу рекламодателей сейчас могут быть интересны баннерные сети? Трафика там маловато. Интернет-магазины все в контексте сидят. FMCG все на телике.

Онлайн-игры по CPA рекламировать остается, но там eCPM стремится к нулю.

Весь вопрос в том, как этот баланс найти. Есть какие-то примеры?

Тупо снижать цену на показы/клики, пока не начнут раскупать? Так сеть может вебмастеров растерять из-за низких выплат.

Если цену не снижать, то продаж вообще может не быть. Опять же вебмастера разбегутся.

Реализация

Итак, если Вы еще не заснули от теоретического описания ситуации, перейдем к практической реализации. Запросы SQL я буду давать в диалекте MySQL, а алгоритмическую часть — в синтаксисе PHP, потому что на данный момент пара PHP/MySQL является наиболее распространенным и приемлемым вариантом для построения подобных вещей.

Опишем таблицу для хранения сообщений. В данном случае я дам только поля, необходимые для функционирования алгоритма, и абстрактное поле Data, в котором хранятся данные, относящиеся к письму. В реальных условиях это поле заменяется на поля TEXT Body, VARCHAR(255) Subject, VARCHAR(255) FromUser и так далее — все, что Вам надо для конкретной реализации.

CREATE TABLE Messages

(INT UNSIGNED ID NOT NULL PRIMARY KEY
,INT UNSIGNED ForumID NOT NULL,INDEX(ForumID)
,INT UNSIGNED ThreadID NOT NULL,INDEX(ThreadID)
,INT UNSIGNED ParentID NOT NULL DEFAULT 0,INDEX(ParentID)
,INT UNSIGNED X NOT NULL DEFAULT 0,INDEX(X)
,INT UNSIGNED Level NOT NULL DEFAULT 0,INDEX(Level)
,TEXT Data
);

Описание полей

ID

Идентификатор письма

ForumID

Идентификатор форума

ThreadID

Идентификатор треда

ParentID

Идентификатор исходного письма для данного ответа. Ноль, если письмо начинает новый тред.

X

Последовательность вывода писем в треде

Level

Отступ при выводе письма

Data

Данные письма

Алгоритмы

Итак, что нам нужно уметь делать с этим хозяйством: а) вставлять письмо, начинающее новую тему; б) вставлять ответ на уже существующее письмо; в) выводить все это красивыми ступеньками, причем на каждом уровне письма отсортированы по времени в обратном порядке, то есть самый последний ответ сверху, ближе всего к оригиналькому письму (на которое отвечали), остальные уезжают вниз. Рассмотрим каждое из этих действий.

Вставка нового письма

Исходные данные: $ForumID, $data. Мы должны сформировать номер для нового треда и вставить письмо. Делается это двумя запросами:

// Нашли новый ThreadID

mysql_query("SELECT @NewThreadID:=MAX(ThreadID)+1 FROM Messages");
// Вставили письмо
mysql_query("INSERT INTO Messages SET ForumID=$ForumID,ThreadID=@NewThreadID,Data=$data");

Поля X и Level мы не устанавливаем, и они принимают значение по умолчанию, то есть ParentID=0 (это не ответ), X=0 (первое письмо в треде) и Level=0 (нулевой уровень, нет отступа). Обратите внимание на два момента. Во-первых, я использовал для хранения номера нового треда переменную MySQL, потому что снаружи MySQL это число мне просто не нужно. Этого делать не обязательно, Вы можете передавать это число из одного запроса в другой через переменную языка программирования. Второй момент связан с тем, что номер ThreadID является глобальным для всех форумов в данной базе. Тут есть некоторое искушение добавить в первый запрос WHERE ForumID=$ForumID и тем самым «сэкономить» идентификаторы тредов, но не надо ему поддаваться. Потому что есть такая дополнительная операция, как перенесение треда в другой форум, и нам лучше будет не искать новый ThreadID при этом.

Добавление ответа на письмо

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

ForumID

Такой же, как у $parent (ForumID=$parent->ForumID). Если только Вы не предусмотрите возможности отвечать из одного форума в другой.

ThreadID

Такой же, как у $parent (ThreadID=$parent->ThreadID).

ParentID

Идентификатор $parent (ParentID=$parent->ID).

Level

На единицу больше, чем у $parent (Level=$parent->Level).

X

Тут-то кабан и порылся. Мы должны вставить новое письмо между $parent и следующим письмом треда, либо после $parent, если $parent — последнее письмо треда. Для этого берем диапазон, снизу ограниченный $parent->X, а сверху — либо X следующего письма треда, либо максимальным возможным значением MAXINT. И ставим X прямо в центр этого диапазона, вычисляя его по нехитрой формуле X=(MinX+MaxX)/2. При этом может возникнуть ситуация, когда вследствие накопления мусора у нас уже не осталось зазора между $parent и следующим письмом треда. Это может случиться, к примеру, если будет много ответов на одно письмо (с каждым новым ответом диапазон уменьшается в два раза). Выявив эту ситуацию, мы должны запустить единственный длительный процесс в этом алгоритме: сборку мусора. Она будет выражаться в том, что мы заново перенумеруем весь тред по полю X, выровняв все интервалы между сообщениями. Предварительно можно проверить, а влезет ли в этот тред что-либо еще вообще. Простейший способ это сделать — посчитать количество писем в треде и сравнить его с MAXINT/2. Конечно, при этом мы получим тред в два раза менее емкий, чем теоретический предел, но не будем заморачиваться на этом. Лично я надеюсь в этой жизни не увидеть ТАКИХ дискуссий. После сборки мусора у нас гарантированно есть интервал между $parent и следующим письмом, так что после этого мы смело идем на процедуру вставки ответа в момент вычисления диапазона для X.

Теперь все вместе

function getRecord($sql)

{
$rs=mysql_query($sql);
$record=mysql_fetch_object();
mysql_free_result($rs);
return $record;
}

function getNextX($parent)
{
$rs=mysql_query("SELECT X FROM Messages WHERE ThreadID=$parent->ThreadID AND X>$parent->X
ORDER BY X LIMIT 1");
$record=mysql_fetch_object($rs);
mysql_free_result($rs);
if($record) return $record->X;
return MAXINT;
}

$maxX=getNextX($parent);

// Если у нас некуда вставлять запись...
if($maxX-$parent->X < 2)
{
// Сколько писем-то?
$cnt=getRecord("SELECT COUNT(*) as Messages FROM Messages WHERE ThreadID=$parent->ThreadID");
$step=(int)(MAXINT / $cnt->Messages);
if($step<2)
die("Can't insert message!");

// Перенумеруем!
$cursor=0;
$rs=mysql_query("SELECT * FROM Messages WHERE ThreadID=$parent->ThreadID ORDER BY X");
while($message=mysql_fetch_object($rs))
{
mysql_query("UPDATE Messages SET X=$cursor WHERE ID=$message->ID");
if($message->ID == $parent->ID)
$maxX=($parent->X=$cursor)+$step;
$cursor+=$step;
}
mysql_free_result($rs);
}

// Вычисляем новый X
$newX=(int)(($parent->X + $maxX)/2);

// Все готово, вставляем сообщение
mysql_query("INSERT INTO Messages SET ForumID=$parent->ForumID, ThreadID=$parent->ThreadID,"
."ParentID=$parent->ID, Level=1+$parent->Level, X=$newX, Data=$data");

Примерно так. Естественно, этот фрагмент кода можно рассматривать только как чисто условный, так как с целью упрощения тут делаются вещи, которые обычно делаться не должны: «обработка» ошибки при помощи die(), использование низкоуровневых функций php для обращения к mysql безо всякого враппера, и так далее.

Вывод форума

Итак, теперь у нас есть сортировка внутри тредов, так что мы можем смело вывести весь форум одним запросом. Исходные данные — $ForumID.

function printMessage($message)

{
$offset=offsetStart+$message->Level*offsetStep;
echo "<DIV STYLE=\"margin-left: $offset\">";
// Печатать заголовок сообщения...
echo ...
echo "</DIV>";
}

$rs=mysql_query("SELECT * FROM Messages WHERE ForumID=$ForumID ORDER BY ThreadID DESC, X");
while($message=mysql_fetch_object($rs))
printMessage($message);
mysql_free_result($rs);

Правда, реальность несколько отличается от данной теории. Проблема в том, что форум надо выводить не весь, а постранично, и хорошо бы бить на страницы по границам тредов. Для этого нам придется сделать дополнительный запрос, чтобы выбрать все треды, нужные для данной страницы. Исходные данные: $ForumID, $PageSize — количество тредов на страницу, $CurrentPage — текущая страница.

$startRecord=$PageSize*$CurrentPage;

$threads=array();

$rs=mysql_query("SELECT ThreadID FROM Messages THERE ForumID=$ForumID GROUP BY ThreadID "
"ORDER BY ThreadID DESC LIMIT $startRecord,$PageSize");
while($thread=mysql_fetch_object()) $threads[]=$thread->ThreadID;
mysql_free_result($rs);

$rs=mysql_query("SELECT * FROM Messages WHERE ThreadID IN (".join(',',$threads).")
ORDER BY ThreadID DESC, X");
while($message=mysql_fetch_object($rs))
printMessage($message);
mysql_free_result($rs);

В данном случае сортировка осуществляется по номеру треда, но можно также сортировать по «свежести» сообщений, если хранение этой информации предусмотрено (ORDER BY MAX(CreatedAt_field)), или еще как-нибудь.

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

Комментарии — на akul@otamedia.com

Copyright © 2002 by Alexey Kulentsov

---------- Добавлено 05.11.2013 в 00:18 ----------

Нашел источник: http://db-maker.narod.ru/forum.htm

Рекурсия при "бесконечной" вложенности - это зло.

Сортировка массива в памяти при большом количестве комментов - это зло.

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

У меня на компе уже больше 10 лет хранится такая вот статья. Не помню уже даже откуда слил.

Статья подробная и длинная. Поэтому постить буду в несколько этапов.

---------- Добавлено 04.11.2013 в 23:50 ----------

Алгоритм построения древовидного форума без использования рекурсии

Копия от 21 декабря 2002 года. Оригинал статьи

Постановка задачи

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

Если рассмотреть задачу подробно, оказывается, что проблему представляет только сортировка писем внутри треда. Применим стандартный прием для таких ситуаций: предварительную сортировку, осуществляемую еще на этапе вставки письма в тред. Для этого в таблице писем создадим дополнительное поле X типа INT для этой цели. При этом проблема быстродействия перемещается в момент вставки письма, но тут мы ее легко решаем при помощи алгоритма со сборкой мусора, где мусором является неравномерность распределения значений поля X по допустимому диапазону (от 0 до MAXINT).

А на новом сайте редиректов никаких не настроено? Что там в .htaccess?

Если в браузере ввести

http://www.site.ru/new-prodazha-oborudovaniya/shirokoformatnye-printery

откроется оно или

http://www.site.ru/new-prodazha-oborudovaniya/shirokoformat_printers

?

ValdisRu:
после того как новый домен перенесете на свой хостинг, укоз через пару дней проверит что домен на него не ссылается и открепит домен самостоятельно

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

IMHO, если затраты на возврат старого домена не критично высоки, надо брать и восстановить редирект.

Только что проверил, что в заголовках Юкоз отдает при обращении к домену http://***.ucoz.ru/, к которому в настройках прикреплен домен http://***.ru/

HTTP/1.1 301 Moved Permanently

Server: uServ/3.2.2

Date: Sat, 19 Oct 2013 22:07:25 GMT

Content-Type: application/octet-stream

Transfer-Encoding: chunked

Connection: keep-alive

Keep-Alive: timeout=15

Location: http://***.ru/

Cache-Control: private

Что это, если не 301 редирект?

Всего: 907