Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > Web > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Ответ
 
Опции темы
Старый 13.08.2018, 09:54   #1
mychatik
 
Аватар для mychatik
 
Регистрация: 06.05.2016
Сообщений: 6
Репутация: 10
По умолчанию Рандомный выбор из БД

Сразу скажу, я не программист, а учусь для себя, типа хобби...

Имеется вот такой код для рандомного выбора вопроса из БД:

Код:

<?php
/**
 * VOC / VOC++ Quiz engine
 *
 * questions randomizer
 * @author ChatMaster <chat@dream.lv>
 * @copyright ChatMaster <chat@dream.lv>
 * @since 08.03.2007
 * @version 2.0.4
 *
 */

set_time_limit(0);
error_reporting(E_ALL);
$path = preg_replace('|([^/]+)$|i', '', __FILE__);
chdir($path);

/************************************************/
/* Configuration */
require_once('config.php');
define('MYSQL_SERVER',       $quiz_config['db_server']); /* define port or socket here if needed (localhost:3306 or localhost:/tmp/mysqld/mysql.sock*/
define('MYSQL_USER',         $quiz_config['db_user']); /* MySQL user */
define('MYSQL_PASSWORD',     $quiz_config['db_pass']); /* MySQL Password */
define('MYSQL_DB',           $quiz_config['db_name']); /* database name */
define('MYSQL_TABLE_PREFIX', $quiz_config['db_prefix']); /* common table prefix */

/************************************************/
/* Initializing */
/* MySQL Connect */
echo("Connecting database... \n");
if (!mysql_connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD)) {
    echo("Cannot connect to the database. ".mysql_error()."\n");
    exit();
}
if (!mysql_select_db(MYSQL_DB)) {
    echo("Cannot select database. ".mysql_error()."\n");
    exit();
}
if ($quiz_config['mysql_encoding']) mysql_query('SET NAMES '.$quiz_config['mysql_encoding']);

$res = mysql_query('SELECT count(*) AS cnt FROM '.MYSQL_TABLE_PREFIX.'quiz LIMIT 1');
list ($count) = mysql_fetch_array($res);
mysql_free_result($res);

$ind = $count*10;

$res = mysql_query('SELECT id, last_use FROM '.MYSQL_TABLE_PREFIX.'quiz');

while ($row = mysql_fetch_array($res)) {
    $new_date = date("Y-m-d H:i:s", time()-rand(100, $ind));
    echo $row['id']."\t".$row['last_use']."\t".$new_date."\n";
    $sql = 'UPDATE '.MYSQL_TABLE_PREFIX.'quiz SET last_use="'.$new_date.'" WHERE id='.$row['id'];
    mysql_query($sql);
}

?>

Всё работает. Но есть вопросы.

Переменная $new_date. Почему рандом делается именно так? Почему именно дата, а не просто какое-либо число?
С текущей датой база вопросов никак не связана. Время загрузки - тоже не причём. Вопросы могут быть загружены, как 10 лет назад, так и минуту...
Нигде не могу найти ответ на этот вопрос.

И далее - сам рандом. Уж очень он предсказуемый. "Ходит" по группе одних и тех же вопросов, не охватывая всю базу.
Это очень заметно, если отвечать на викторину несколько часов подряд. Хоть вопросов в базе около 30000, но выборка идёт не из всего массива и вопросы начинают повторяться через несколько часов работы.

Для устранения бага - сделан фикс в виде кнопки "перемешивания". Но это не решает проблему. Просто рандом перескакивает на новый цикл, и снова "бегает по кругу" по одним и тем же вопросам.

И ещё, опять тот же рандом.
Если загрузить блок новых вопросов - они будут выводиться подряд в том же порядке, как и были загружены.
Постепенно, через несколько циклов, новый пакет постепенно "рассасывается" и новые вопросы начинают перемежаться со старыми.

Теперь, что я сделал.

Протестировав переменную $new_date, я заметил, что дата в ней изменяется очень незначительно.
Поэтому попытался сделать рандом более "рандомным" и в большем диапазоне дат:
Код:

$new_date = date("Y-m-d H:i:s", crc32(uniqid(mt_rand(), true).microtime(true)));

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

Я не прошу решить задачу за меня.
Просто объясните, пожалуйста, по принципу работы рандома через дату в этом файле (или дайте ссылку на инфу).
Если есть возможность, подскажите как правильно делать выборку из всего массива, без зацикливания.
Если же подскажете готовый вариант решения проблемы - буду очень благодарен.

Последний раз редактировалось mychatik; 13.08.2018 в 10:19.
mychatik вне форума   Ответить с цитированием
Старый 13.08.2018, 10:43   #2
Скарам
Дружите с Linq ;)
Участник клуба
 
Аватар для Скарам
 
Регистрация: 15.10.2008
Адрес: Москва
Сообщений: 796
Репутация: 359
По умолчанию

А какая задача? Викторина, содержит определенное количество вопросов и надо выбрать N вопросов на раунд? После этого идет следующий раунд вопросов из N вопросов?
Обычно время используют, как seed (источник случайный чисел) для псевдослучайных чисел. Затрудняюсь сказать что хотел сделать программист, но есть подозрение, что он хотел сделать последовательность вопрос не повторяющимися между раундами. На мой взгляд подход так себе. Я бы сделал прямой запрос случайных записей в нужном количестве и все (как-то так).
__________________
Не давай организму поблажки, каждый день тренируй его в шашки..
Скарам вне форума   Ответить с цитированием
Старый 13.08.2018, 10:50   #3
Serge_Bliznykov
МегаМодератор
СуперМодератор
 
Регистрация: 09.01.2008
Сообщений: 24,384
Репутация: 5308
По умолчанию

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

во-вторых, рекомендую воспользоваться решением отсюда - https://habr.com/post/54176/
// или по ссылке Скарам

в-третьих, расширение mysql() в PHP устарело, нужно переходить на PDO() или на mysqli()

Последний раз редактировалось Serge_Bliznykov; 13.08.2018 в 10:52.
Serge_Bliznykov вне форума   Ответить с цитированием
Старый 13.08.2018, 10:51   #4
Alex11223
Модератор
Заслуженный модератор
 
Регистрация: 12.01.2011
Сообщений: 17,010
Репутация: 3316

icq: 512-765
skype: alexp.frl
По умолчанию

С чего вы взяли, что это рандомный выбор?
Я не вижу тут никакого рандома при выборе, только выполнение обычного SELECT (без ORDER BY и т.п.) порядок которого вроде бы не гарантирован в MySQL, но вряд ли сильно рандомный.
Alex11223 вне форума   Ответить с цитированием
Старый 13.08.2018, 10:58   #5
Serge_Bliznykov
МегаМодератор
СуперМодератор
 
Регистрация: 09.01.2008
Сообщений: 24,384
Репутация: 5308
По умолчанию

Alex11223, мой пост выше отвечает на ваш вопрос...
очень вероятно, что скрипт, где выбираются "случайные" записи, использует сортировку по полю last_use
Serge_Bliznykov вне форума   Ответить с цитированием
Старый 13.08.2018, 13:13   #6
mychatik
 
Аватар для mychatik
 
Регистрация: 06.05.2016
Сообщений: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Скарам Посмотреть сообщение
А какая задача? Викторина, содержит определенное количество вопросов и надо выбрать N вопросов на раунд? После этого идет следующий раунд вопросов из N вопросов?
Задача в следующем - викторина идёт без перерыва. Из базы постоянно выбирается один вопрос, потом даются подсказки и, если не ответили - правильный ответ.
Если ответили - даётся награда, в зависимости от того, сколько подсказок использовано.

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
С чего вы взяли, что это рандомный выбор?
Я не вижу тут никакого рандома при выборе, только выполнение обычного SELECT (без ORDER BY и т.п.)
Вот поэтому и пишу, чтобы разобраться...
То, что это рандом я взял из описания questions randomizer и названия файла randomizer.php
Плюс в файле есть рандомное изменение переменной $new_date.

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
порядок которого вроде бы не гарантирован в MySQL, но вряд ли сильно рандомный.
Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
На мой взгляд - крайне неэффективное и плохо работающее решение
Вот-вот. И я об этом. "Рандомность" выборки - просто никакая...

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
во-первых, если я правильно понял, то это не код, который выбирает вопросы рандомно (это у Вас другой скрипт делает), это код, который заполняет поле last_use случайной датой, чтобы потом, когда выбирать случайные вопросы, можно было отсортировать по этому полю.
Я правильно понял, что чем больше различаются эти даты - тем вероятность повторения вопроса меньше?
Т.е. мой вариант изменения всё-же будет эффективным?

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
во-вторых, рекомендую воспользоваться решением отсюда - https://habr.com/post/54176/
// или по ссылке Скарам
Спасибо, поизучаю!

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
в-третьих, расширение mysql() в PHP устарело, нужно переходить на PDO() или на mysqli()
Не всё сразу...
Задача-минимум пока выполнена. Сделан перевод с php5.3 на php5.6; php7.0 - это на будущее.
Я так думаю, что сервера ещё долго будут поддерживать php5.6.
Изображения
Тип файла: jpg 3K83Y.jpg (46.8 Кб, 1 просмотров)
mychatik вне форума   Ответить с цитированием
Старый 13.08.2018, 13:20   #7
Alex11223
Модератор
Заслуженный модератор
 
Регистрация: 12.01.2011
Сообщений: 17,010
Репутация: 3316

icq: 512-765
skype: alexp.frl
По умолчанию

Зачем отвечать не дочитав?
Написали ж
Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
это не код, который выбирает вопросы рандомно
Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
очень вероятно, что скрипт, где выбираются "случайные" записи, использует сортировку по полю last_use



Цитата:
Сообщение от mychatik Посмотреть сообщение
чем больше различаются эти даты - тем вероятность повторения вопроса меньше?
Зависит от алгоритма выбора. Скорее всего там просто сортировка по дате, так что не важно, хоть числа по-порядку.

Последний раз редактировалось Alex11223; 13.08.2018 в 13:27.
Alex11223 вне форума   Ответить с цитированием
Старый 13.08.2018, 13:41   #8
mychatik
 
Аватар для mychatik
 
Регистрация: 06.05.2016
Сообщений: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
очень вероятно, что скрипт, где выбираются "случайные" записи, использует сортировку по полю last_use
Вот это оно?
Код:

/*************************************************/
/* Functions */
function get_question() {
    if (!defined('Q_COMMON')) exit('Installation error');
    global $answer, $words_count, $answer_length, $file_path;

    if (!file_exists($file_path.'quiz.php')) exit('Some system files was not found. Please reinstall quiz!');

    $str = file_get_contents($file_path.'quiz.php');
    //if (!preg_match('/Build 20070928092230<br>/iU', $str)) exit('I think, You have too low IQ to install quiz correctly.');

    /* Select question */
    $sql = 'SELECT * FROM '.MYSQL_TABLE_PREFIX.'quiz ORDER BY last_use ASC LIMIT 1';
    $res = mysql_query($sql) or die ('SQL ERROR! '.mysql_error());

    list ($id, $question, $answer_text, $last_use) = mysql_fetch_array($res, MYSQL_NUM);
    mysql_free_result($res);

    $answer_text = trim($answer_text);
    $answer_length = strlen($answer_text);
    $words_count = count(explode(' ', $answer_text));

    /* Update last use time */
    $sql = 'UPDATE '.MYSQL_TABLE_PREFIX.'quiz SET last_use="'.date('Y-m-d H:i:s').'" WHERE id='.intval($id);
    mysql_query($sql);

    /* Write Answer */
    $f = fopen($answer, "w");
    flock($f, LOCK_EX);
    fwrite($f, $answer_text."\t".time());
    flock($f, LOCK_UN);
    fclose($f);

    return $question;
}


Последний раз редактировалось mychatik; 13.08.2018 в 13:44.
mychatik вне форума   Ответить с цитированием
Старый 13.08.2018, 14:47   #9
Serge_Bliznykov
МегаМодератор
СуперМодератор
 
Регистрация: 09.01.2008
Сообщений: 24,384
Репутация: 5308
По умолчанию

Цитата:
Сообщение от mychatik Посмотреть сообщение
Вот это оно?
ОНО (отсортировать по случайному полю и взять одну (первую) запись.):
Цитата:
Сообщение от mychatik Посмотреть сообщение
Код:

$sql = 'SELECT * FROM '.MYSQL_TABLE_PREFIX.'quiz ORDER BY last_use ASC LIMIT 1';


я бы рекомендовал:
1) код, который в randomizer.php вообще не нужен.
2) код, который в get_question замените на простой код для получения случайной записи из таблице (ссылки на примеры кода уже дали). и всё.
больше ничего не надо.


p.s. похоже этот механизм задуман был для другого - чтобы выпавшие вопросы долго не выпадали.
Цитата:
Сообщение от mychatik Посмотреть сообщение
Код:

/* Update last use time */
    $sql = 'UPDATE '.MYSQL_TABLE_PREFIX.'quiz SET last_use="'.date('Y-m-d H:i:s').'" WHERE id='.intval($id);

но, имхо, толком это не получилось реализовать.

Последний раз редактировалось Serge_Bliznykov; 13.08.2018 в 14:52.
Serge_Bliznykov вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Рандомный вывод GRFed PHP 5 19.07.2017 10:15
Рандомный выбор. Stranger_465 Общие вопросы C/C++ 6 04.05.2015 18:50
Рандомный текст Jkeeee HTML и CSS 0 15.05.2011 15:59
Не рандомный рандом ))))) Junk1E Общие вопросы C/C++ 6 09.12.2009 19:51
Рандомный вывод Forrest Gamp Общие вопросы C/C++ 6 10.02.2008 16:03


02:59.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru