mirror of
https://github.com/moodle/moodle.git
synced 2025-04-16 14:02:32 +02:00
MDL-57791 analytics: Replace sql queries for API calls
This commit is contained in:
parent
acb14d08f6
commit
584ffa4ffc
@ -162,10 +162,8 @@ class course_dropout extends \core_analytics\local\target\binary {
|
||||
* @return void
|
||||
*/
|
||||
protected function calculate_sample($sampleid, \core_analytics\analysable $course, $starttime = false, $endtime = false) {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT ue.* FROM {user_enrolments} ue JOIN {user} u ON u.id = ue.userid WHERE ue.id = :ueid";
|
||||
$userenrol = $DB->get_record_sql($sql, array('ueid' => $sampleid));
|
||||
$userenrol = $this->retrieve('user_enrolments', $sampleid);
|
||||
|
||||
// We use completion as a success metric only when it is enabled.
|
||||
$completion = new \completion_info($course->get_course_data());
|
||||
|
@ -37,22 +37,22 @@ require_once($CFG->libdir . '/tablelib.php');
|
||||
class model_logs extends \table_sql {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @var \core_analytics\model
|
||||
*/
|
||||
protected $modelid = null;
|
||||
protected $model = null;
|
||||
|
||||
/**
|
||||
* Sets up the table_log parameters.
|
||||
*
|
||||
* @param string $uniqueid unique id of form.
|
||||
* @param int $modelid model id
|
||||
* @param \core_analytics\model $model
|
||||
*/
|
||||
public function __construct($uniqueid, $modelid) {
|
||||
public function __construct($uniqueid, $model) {
|
||||
global $PAGE;
|
||||
|
||||
parent::__construct($uniqueid);
|
||||
|
||||
$this->modelid = $modelid;
|
||||
$this->model = $model;
|
||||
|
||||
$this->set_attribute('class', 'modellog generaltable generalbox');
|
||||
$this->set_attribute('aria-live', 'polite');
|
||||
@ -182,11 +182,9 @@ class model_logs extends \table_sql {
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
global $DB;
|
||||
|
||||
$total = $DB->count_records('analytics_models_log', array('modelid' => $this->modelid));
|
||||
$total = count($this->model->get_logs());
|
||||
$this->pagesize($pagesize, $total);
|
||||
|
||||
$this->rawdata = $DB->get_records('analytics_models_log', array('modelid' => $this->modelid), 'timecreated DESC', '*',
|
||||
$this->get_page_start(), $this->get_page_size());
|
||||
$this->rawdata = $this->model->get_logs($this->get_page_start(), $this->get_page_size());
|
||||
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
|
@ -41,15 +41,13 @@ class predict_models extends \core\task\scheduled_task {
|
||||
public function execute() {
|
||||
global $DB, $OUTPUT, $PAGE;
|
||||
|
||||
$models = $DB->get_records_select('analytics_models', 'enabled = 1 AND trained = 1 AND timesplitting IS NOT NULL');
|
||||
$models = \core_analytics\manager::get_all_models(true, true);
|
||||
if (!$models) {
|
||||
mtrace(get_string('errornoenabledandtrainedmodels', 'tool_models'));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($models as $modelobj) {
|
||||
$model = new \core_analytics\model($modelobj);
|
||||
|
||||
foreach ($models as $model) {
|
||||
$result = $model->predict();
|
||||
if ($result) {
|
||||
echo $OUTPUT->heading(get_string('modelresults', 'tool_models', $model->get_target()->get_name()));
|
||||
|
@ -41,19 +41,24 @@ class train_models extends \core\task\scheduled_task {
|
||||
public function execute() {
|
||||
global $DB, $OUTPUT, $PAGE;
|
||||
|
||||
$models = $DB->get_records_select('analytics_models', 'enabled = 1 AND timesplitting IS NOT NULL');
|
||||
$models = \core_analytics\manager::get_all_models(true);
|
||||
if (!$models) {
|
||||
mtrace(get_string('errornoenabledmodels', 'tool_models'));
|
||||
return;
|
||||
}
|
||||
foreach ($models as $modelobj) {
|
||||
$model = new \core_analytics\model($modelobj);
|
||||
|
||||
foreach ($models as $model) {
|
||||
|
||||
if ($model->is_static()) {
|
||||
// Skip models based on assumptions.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$model->get_time_splitting()) {
|
||||
// Can not train if there is no time splitting method selected.
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $model->train();
|
||||
if ($result) {
|
||||
echo $OUTPUT->heading(get_string('modelresults', 'tool_models', $model->get_target()->get_name()));
|
||||
|
@ -144,7 +144,7 @@ switch ($action) {
|
||||
}
|
||||
|
||||
$renderer = $PAGE->get_renderer('tool_models');
|
||||
$modellogstable = new \tool_models\output\model_logs('model-' . $model->get_id(), $model->get_id());
|
||||
$modellogstable = new \tool_models\output\model_logs('model-' . $model->get_id(), $model);
|
||||
echo $renderer->render_table($modellogstable);
|
||||
break;
|
||||
}
|
||||
|
@ -34,18 +34,19 @@ defined('MOODLE_INTERNAL') || die();
|
||||
abstract class by_course extends base {
|
||||
|
||||
public function get_courses() {
|
||||
global $DB;
|
||||
|
||||
// Default to all system courses.
|
||||
if (!empty($this->options['filter'])) {
|
||||
$it = $this->options['filter'];
|
||||
$courses = $this->options['filter'];
|
||||
} else {
|
||||
// Iterate through all potentially valid courses.
|
||||
$it = $DB->get_recordset_select('course', 'id != :frontpage', array('frontpage' => SITEID), 'sortorder ASC');
|
||||
$courses = get_courses();
|
||||
}
|
||||
unset($courses[SITEID]);
|
||||
|
||||
$analysables = array();
|
||||
foreach ($it as $course) {
|
||||
foreach ($courses as $course) {
|
||||
// Skip the frontpage course.
|
||||
$analysable = \core_analytics\course::instance($course);
|
||||
$analysables[$analysable->get_id()] = $analysable;
|
||||
}
|
||||
@ -64,7 +65,7 @@ abstract class by_course extends base {
|
||||
$filesbytimesplitting = array();
|
||||
|
||||
// This class and all children will iterate through a list of courses (\core_analytics\course).
|
||||
$analysables = $this->get_courses();
|
||||
$analysables = $this->get_courses('all', 'c.sortorder ASC');
|
||||
foreach ($analysables as $analysableid => $analysable) {
|
||||
|
||||
$files = $this->process_analysable($analysable, $includetarget);
|
||||
|
@ -63,7 +63,8 @@ class site_courses extends sitewide {
|
||||
// Getting courses from DB instead of from the site as these samples
|
||||
// will be stored in memory and we just want the id.
|
||||
$select = 'id != 1';
|
||||
$courses = $DB->get_records_select('course', $select, null, '', '*');
|
||||
$courses = get_courses('all', 'c.sortorder ASC');
|
||||
unset($courses[SITEID]);
|
||||
|
||||
$courseids = array_keys($courses);
|
||||
$sampleids = array_combine($courseids, $courseids);
|
||||
|
@ -50,6 +50,14 @@ class manager {
|
||||
*/
|
||||
protected static $alltimesplittings = null;
|
||||
|
||||
/**
|
||||
* Returns all system models that match the provided filters.
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @param bool $trained
|
||||
* @param \context $predictioncontext
|
||||
* @return \core_analytics\model[]
|
||||
*/
|
||||
public static function get_all_models($enabled = false, $trained = false, $predictioncontext = false) {
|
||||
global $DB;
|
||||
|
||||
|
@ -1018,6 +1018,19 @@ class model {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model logs data.
|
||||
*
|
||||
* @param int $limitfrom
|
||||
* @param int $limitnum
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function get_logs($limitfrom = 0, $limitnum = 0) {
|
||||
global $DB;
|
||||
return $DB->get_records('analytics_models_log', array('modelid' => $this->get_id()), 'timecreated DESC', '*',
|
||||
$limitfrom, $limitnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* flag_file_as_used
|
||||
*
|
||||
|
59
analytics/tests/fixtures/test_static_target_shortname.php
vendored
Normal file
59
analytics/tests/fixtures/test_static_target_shortname.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
class test_static_target_shortname extends \core_analytics\local\target\binary {
|
||||
|
||||
protected $predictions = array();
|
||||
|
||||
public function get_analyser_class() {
|
||||
return '\core_analytics\local\analyser\site_courses';
|
||||
}
|
||||
|
||||
public static function classes_description() {
|
||||
return array(
|
||||
'Course fullname first char is A',
|
||||
'Course fullname first char is not A'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't want to discard results.
|
||||
* @return float
|
||||
*/
|
||||
protected function min_prediction_score() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't want to discard results.
|
||||
* @return array
|
||||
*/
|
||||
protected function ignored_predicted_classes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true) {
|
||||
// This is testing, let's make things easy.
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false) {
|
||||
global $DB;
|
||||
|
||||
$sample = $DB->get_record('course', array('id' => $sampleid));
|
||||
|
||||
if ($sample->visible == 0) {
|
||||
// We skip not-visible courses as a way to emulate the training data / prediction data difference.
|
||||
// In normal circumstances targets will return null when they receive a sample that can not be
|
||||
// processed, that same sample may be used for prediction.
|
||||
// We can not do this in is_valid_analysable because the analysable there is the site not the course.
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstchar = substr($sample->shortname, 0, 1);
|
||||
if ($firstchar === 'a') {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -48,12 +48,12 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
public function test_ml_training_and_prediction($timesplittingid, $npredictedranges, $predictionsprocessorclass) {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminuser();
|
||||
set_config('enabled_stores', 'logstore_standard', 'tool_log');
|
||||
|
||||
$ncourses = 10;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Generate training data.
|
||||
$params = array(
|
||||
'startdate' => mktime(0, 0, 0, 10, 24, 2015),
|
||||
@ -156,7 +156,7 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_ml_evaluation($modelquality, $ncourses, $expected, $predictionsprocessorclass) {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$this->setAdminuser();
|
||||
set_config('enabled_stores', 'logstore_standard', 'tool_log');
|
||||
|
||||
$sometimesplittings = '\core_analytics\local\time_splitting\weekly,' .
|
||||
|
Loading…
x
Reference in New Issue
Block a user