|
|
|
| Добрый день. Хочу хранить в одном столбце набор опций (1-присутствует, 0-отсуствует), одна опция - один бит. Соотвественно в условие выборки выглядит как
SELECT ... WHERE options & $options
например, $options = 0xС0 или 11000000 (двоичная), т.е. первые две опции включены. Понятно, что выбираются записи, в которых опции хотя бы в одном бите совпадают с маской $options.
Однако в BIGINT можно хранить 64 бит для логических операций. А какие варианты можно предложить для хранения большего числа, 80 например? | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 16:19)
| | на мой взгляд не очень хорошая идея, (тем более что лично у меня не работает, ну может просто ума не хватает)
я бы лучше сделал 80 полей
выборку (а иногда и группировку) легко организовать, что по одному полю, что по всем 80
правда надо на счет нагрузки потестить | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 17:25)
| | Идея просто отличная в том плане, что скорость работы зашкаливающая (пробовала с 24 битами). Плюс удобство - что ищем переводим в биты (это делается) как
$rtvs = $raidcall*8+$teamspeak*4+$ventrilo*2+$skype;
|
(можно и со сдвигом)
а на выходе в скрипте по AND маске получаем "все по отдельности".
Да, только сейчас возник вопрос - может и php не поддерживает более 64 битные переменные, сейчас гляну.
UPD. Поддерживает | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 17:36)
| | не могли бы вы кусок кода подкинуть, для потестить
или сюда прикрепить или на почту кинуть
хоту разобраться в этом вопросе
и если в одно поле не лезет, сделайте 2х64 :) | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 17:42)
| |
function time_track($shour, $ehour) // Преобразует время от $shour до $ehour в последовательность бит
{
$time_track = 0xFFFFFF; // FF FF FF
if ($shour == $ehour) return $time_track;
if ($shour <= $ehour) {$s=$shour; $e=$ehour;} else {$s=$ehour; $e=$shour;}
$time_track = $time_track >> (24-$e);
$time_track = $time_track << (24-$e); // отрезали с конца часы
$time_track = $time_track << $s;
$time_track = $time_track & 0xFFFFFF;
$time_track = $time_track >> $s; // отрезали с начала
if ($shour > $ehour) $time_track = $time_track ^ 0xFFFFFF; // для случая перехода через 00:00
return $time_track;
}
|
Функция переводит время игры от shour до ehour в 24 бита, 1 - играет, 0 - не играет.
Если делаем запрос SELECT ... WHERE `time_track` & $time_track
то выводит если есть совпадение хоть по одному биту (подробности тут, но там в коде у меня была ошибка).
Сейчас хочу использовать подобное решение для хранения опций, и их уже более 64. | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 17:53)
| | спасибо, еще бы кусок дампа таблицы было-бы совсем хорошо | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 18:03)
| |
function dbconnect(&$db) // соединяемся с БД
{
$user = 'root';
$password = '';
$table = 'tmp';
$db = new mysqli('localhost', $user, $password, $table);
$db->query('SET NAMES \'utf8\'');
}
dbconnect($db);
for ($i = 0; $i<10000; $i++)
{
$shour = rand(0,23);
$ehour = rand(0,23);
$time_track = time_track($shour, $ehour);
$query = "INSERT INTO `mytime` (`time_track`) VALUES ('$time_track')";
$db->query($query);
}
|
| |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 18:07)
| | время только часы, а то я уже с UNIXTIME экспериментировать начал
запрос по маске должен вернуть тех кто был в игре за промежуток времени, пришедших и сваливших включительно? | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 18:13)
| | Время это int. Просто цифра :) Которую мы используем для &, и не более.
Иллюстрация: http://demiart.ru/forum/uploads8/post-714290-1320768544.gif
Да не нужно привязываться к маске и логике. Это рабочая функция, все отлично работает на готовом проекте. Я пытаюсь подобную технику использовать для хранения списка опций уже в другом скрипте.
Просто чтобы 1 & 1 = 1 и все. И чтобы можно было более 64 бит. Если нужны подробности о time_track, то тут она, там вся проблематика.
UPD. Почему лучше не использовать 2x64?
Потому что это нарушит архитектуру. Есть запрос, который извлекает из одной таблицы все опции: их название, а также порядковый номер бита. Потом делаем запрос ко 2 таблице с маской. А если 72 опции, то уже придется кодировать не только номер бита, но и где он хранится.
Ладно, сейчас попробую 2x64 | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 18:44)
| | Да не нужно привязываться к маске и логике.
как это не надо, очень даже надо, я же должен ведать что творю
ходил по ссылке, принцип понятен, но вот применение в самой игре не понятно
____
хорошо что вы пришли на этот форум, тут такие как вы позарез нужны :) | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 19:44)
| | Спасибо за похвалу. О форуме узнала из книги самоучитель MySQL.
Описание скрипта и его работа тут
Простым языком говоря, есть игрок 1, который размещает анкету и указывает время игры, например от 10.00 до 20.00.
Приходит второй игрок, ищет анкеты людей, причем он сам играет с 12.00 до 15.00. Находит анкету первого игрока. То есть время игры должно перекрываться. А бинарное логическое И дает возможность сравнить время, если каждый бит - это время игры. Хоть один бит совпадает - значит время игры совпадает хоть по одному часу. А потом уже в скрипте можно сделать бинарное И, получить результат, и, посчитав количество бит в нем, определить совпадение времени в часах. Можно и в MySQL это сделать, функция bit count (не помню как пишется).
И мне понравилось работать с битами. А массовое хранение опций "есть", "нет" напрашивается именно на такой способ хранения. У мне 72 опции. Наверное, придется реализовывать 2x64 (или даже 4x32), так как php отказывается работать (не правильно работает) с такими числами.
UPD. А если хранить список опций таким способом, то искать стоит так: (`options` XOR $mask) AND $mask.
UPD2. То есть у меня задача такая: есть, скажем, автомастерская 1.
Она указывает
1. чиним двигатель(0 - не чиним)
2. чиним двери (1 - да, чиним)
3. пылесосим салон (1 - да, пылесосим).
В бинарном виде это 011
2 автомастерская: чинят все (111)
Мужик ищет мастерскую, где бы ему починили двери, то есть 010.
Делаем поиск (`options` XOR $mask) AND $mask, если не нуль, получаем что мастерская подходит. Для 010 подходят обе. Для 110 - только вторая "чиним все" | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 20:25)
| | теперь гораздо яснее, но есть одно но, в запросе по демо ссылке нет сортировки
без сортировки игра не стоит свеч
по этому полю сортировка нормально проходит?
___
WoW - это круто, у меня жена на офе играет :) | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 22:25)
| | Сортировка есть, она сделана на основе релевантности (уже в скрипте). Можно конечно и в запросе такое реализовать, но не хотелось все это закладывать в запрос, слишком замороченный он тогда получится.
У меня там считается пересечение времени, то есть число часов, которые играют оба игрока. По этому полю скрипт рассчивает релевантность, прямо влиящую на сортировку. А также рассчитывается "антивремя", то есть если часы, когда играет один из игроков, но не играет второй. Это также влияет на релевантность (смысл: вывести в первые ряды игроков с максимальным совпадением времени). И прочие параметры - совпадение средств связи учитывается. В описании это сказано.
Таки решена задаче через 4x32. Конечный запрос примерно такой
WHERE ((g.girl_services_0x32 ^ 32) & 32 OR (g.girl_services_0x32 ^ 0) & 0 OR (g.girl_services_0x32 ^ 0) & 0 OR (g.girl_services_0x32 ^ 0) & 0)= 0
32 - (просто совпало с 32, м.б. любым) это параметр "100000" в первом блоке по 32 | |
|
|
|
|
|
|
|
для: yadyra
(10.03.2012 в 22:50)
| | разруливать релевантность на РНР, тоже нагрузка большая должна быть и код должен быть не маленький
ну это действительно надо все тестировать засекать время выполнения скрипта, нагрузку и расход оперативки | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 23:38)
| | Там в запросе стоит последние обновленные, LIMIT 30, так что ничего страшного. код в несколько строк. идет банальный подсчет совпадающих бит, вводятся несколько коэфициентов.
for ($i = 0; $i<count($result); $i++)
{
// Рассчитываем релевантность
$bc_time = enum_convert::bit_count($time_track & $result[$i]['time_track']);
$bc_anti_time = enum_convert::bit_count($anti_time_track & $result[$i]['time_track']);
$bc_rtvs = enum_convert::bit_count($result[$i]['rtvs'] & $rtvs);
//$bc_now = bit_count($result[$i]['time_track'] & $now_track);
$result[$i]['relevancy'] = $bc_time*3 + $bc_rtvs - $bc_anti_time;
}
function compare($x, $y)
{
if ($x['relevancy'] == $y['relevancy']) return 0;
elseif ($x['relevancy'] > $y['relevancy']) return -1;
else return 1;
}
usort($result, 'compare');
return $result;
}
// вырезано из класса
static function bit_count($v) // Считает количество "1" в 32-разрядной переменной
{
$v = ($v & 0x49249249) + (($v >> 1) & 0x49249249) + (($v >> 2) & 0x49249249);
$v = (($v + ($v >> 3)) & 0x381c0e07) + (($v >> 6) & 0x381c0e07);
return ($v + ($v >> 9) + ($v >> 18) + ($v >> 27)) & 0x3f;
}
}
|
| |
|
|
|
|
|
|
|
для: yadyra
(11.03.2012 в 01:08)
| | Там в запросе стоит последние обновленные, LIMIT 30
т.е самые релевантные могут не попасть в выборку, это же не есть хорошо
это расчет только по времени, так что для "полного счастья" код увеличиться раз в пять
опять же при выборке по классам идет четкая зависимость если хотим война, значит воин, но танковать могут и ДК и паладин в зависимости от спека ну и тд.
идея у вас замечательная, я думаю её нужно хорошенько развивать
___
в любом случае спасибо за подробные объяснения | |
|
|
|
|
|
|
|
для: Valick
(11.03.2012 в 07:39)
| | >>т.е самые релевантные могут не попасть в выборку, это же не есть хорошо
Пока что так. Кроме того если прикинуть, кто попадет в выборку "самые последние, 30 штук", "сервер", "фракция" (это самый минимум при поиске, даже без времени и связи), то из этих 30 человек многим анкетам будет уже более месяца. Ну а зачем показывать более релевантные "старые анкеты", если их хозяева уже давно может забросили это дело. Так что время последнего обновления влияет на результаты, иначе в топе бы висели те, кто поставил все виды связи, все дни недели и указал самое популярное время игры (10-18 часов, например).
В общем я знаю о проблемах с релевантностью, и еще в этом направлении предстоит много сделать. Сейчас разработка приостановлена, есть вещи поинтересней.
>>идея у вас замечательная, я думаю её нужно хорошенько развивать
Идея не моя, а взята с сайта воврейдер, вроде, я лишь программирую для одного человека который захотел подобное для своего сайта.
>>больше 64 бит в одном поле хранить не выйдет
да тут пришлось с "over 64" перейти на 4 столбца по 32, сказываются ограничения php, уже все сделано и работает :)
Спасибо за дискуссию | |
|
|
|
|
|
|
|
для: yadyra
(11.03.2012 в 11:43)
| | Кроме того если прикинуть, кто попадет в выборку "самые последние, 30 штук"
это в расчете на небольшое количество людей, представьте если 500 человек обновили свои данные в течение последнего часа, из них в выборку попадут всего 30.
я конечно представляю что на пиратках народу не бывает лишнего, все время дефицит
но логика завязанная на количество сами понимаете :)
но это уже совсем другая история, главное что бы заказчик был доволен ;)
___
еще на демо сайте слайдером можно выбрать время от 0 до 24, а вот 4 часа игры с 23 часов до 03 указать нельзя ;)
еще кроме раидкала и вентрилы есть mumble, правда кроме офа я его ни на одной пиратке не встречал
вы меня извините, я не придираюсь, я "что вижу то пою" :) | |
|
|
|
|
|
|
|
для: Valick
(10.03.2012 в 23:38)
| | Извините, что вмешиваюсь )
Как раз кажется вы у кого-то спрашивали нафига нужен тип SET и куда его можно применить?
Это как раз тот случай. Т.е. тип SET это визуализация побитовых операций. Т.е. данные в этом типе хранятся как ЦЕЛОЕ просто при создании поля каждому биту присваивается как бы имя. И операции с этим полем такие же быстрае как с целым.
_____
P.S. больше 64 бит в одном поле хранить не выйдет. И ЦЕЛОГО больше БИГИНТа нету и СЕТ максимум 64 элемента может иметь. | |
|
|
|
|
|
|
|
для: Sfinks
(11.03.2012 в 02:21)
| | при таком раскладе один из нас не понимает назначение поля SET :)
будет время займусь этим вопросом | |
|
|
|