Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

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

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

Купить рекламу на форуме - 42 тыс руб за месяц

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

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

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

Код:
<?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 в 09:19.
mychatik вне форума Ответить с цитированием
Старый 13.08.2018, 09:43   #2
Скарам
Дружите с Linq ;)
Форумчанин
 
Аватар для Скарам
 
Регистрация: 15.10.2008
Сообщений: 822
По умолчанию

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

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

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

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

Последний раз редактировалось Serge_Bliznykov; 13.08.2018 в 09:52.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 13.08.2018, 09:51   #4
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

С чего вы взяли, что это рандомный выбор?
Я не вижу тут никакого рандома при выборе, только выполнение обычного SELECT (без ORDER BY и т.п.) порядок которого вроде бы не гарантирован в MySQL, но вряд ли сильно рандомный.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 13.08.2018, 09:58   #5
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

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

Цитата:
Сообщение от Скарам Посмотреть сообщение
А какая задача? Викторина, содержит определенное количество вопросов и надо выбрать 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 Кб, 121 просмотров)
mychatik вне форума Ответить с цитированием
Старый 13.08.2018, 12:20   #7
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

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



Цитата:
Сообщение от mychatik Посмотреть сообщение
чем больше различаются эти даты - тем вероятность повторения вопроса меньше?
Зависит от алгоритма выбора. Скорее всего там просто сортировка по дате, так что не важно, хоть числа по-порядку.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

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

Цитата:
Сообщение от 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 в 12:44.
mychatik вне форума Ответить с цитированием
Старый 13.08.2018, 13:47   #9
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

Цитата:
Сообщение от 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 в 13:52.
Serge_Bliznykov вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


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