Advertisement
Guest User

Untitled

a guest
Jan 24th, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.33 KB | None | 0 0
  1. <?php
  2.  
  3. namespace App\Cursometr\Facts\CourseStructure;
  4.  
  5. use App\Cursometr\Facts\UsingQuery;
  6. use App\Helpers\Structure;
  7. use Tinderbox\ClickhouseBuilder\Integrations\Laravel\Builder;
  8. use Tinderbox\ClickhouseBuilder\Query\Identifier;
  9.  
  10. class CourseStructureFastAnswersFact extends AbstractCourseStructureFact implements UsingQuery
  11. {
  12.     protected $format = 'integer';
  13.     protected $defaultValue = 0;
  14.    
  15.     public static function getName(): string
  16.     {
  17.         return 'fast-answers';
  18.     }
  19.  
  20.     public function getQuery(\Closure $queryCallback = null): Builder
  21.     {
  22.         /*
  23.          * Получим список листьев из раздела practice
  24.          */
  25.         $entities = Structure::getPracticeEntities($this->getCourseId());
  26.  
  27.         /*
  28.          * Считаем среднее и отклонение для каждой сущности, что бы потом приджоинить это к основному запросу при
  29.          * подсчете z-score.
  30.          */
  31.         $durationsQuery = $this->getCleanQuery()
  32.                                ->table('learners')
  33.                                ->select('entitiesAttempts.entityIri as entityIri', 'entitiesAttempts.durationTotal as duration')
  34.                                ->final()
  35.                                ->arrayJoin('entitiesAttempts')
  36.                                ->whereIn('entityIri', $entities->getIris())
  37.                                ->preWhere('courseId', '=', $this->getCourseId())
  38.                                ->where('duration', '>', 0)
  39.                                ->where('entitiesAttempts.passed', '=', 1);
  40.  
  41.         $durationsQuery = $this->getCleanQuery()
  42.                                ->table($durationsQuery)
  43.                                ->select('entityIri', raw('groupArray(duration) as durations'))
  44.                                ->groupBy('entityIri');
  45.  
  46.         /*
  47.          * arrayReduce('avg', values) AS median,
  48.          * arrayMap(x -> (pow(x - median, 2)), values) AS squared_deltas,
  49.          * sqrt(arraySum(squared_deltas) / (length(values) - 1)) AS deviation
  50.          */
  51.  
  52.         $medianAndDeviationQuery = $this->getCleanQuery()
  53.                                         ->table($durationsQuery)
  54.                                         ->select(
  55.                                             'entityIri',
  56.                                             raw('arrayReduce(\'median\', durations) as median'),
  57.                                             raw('sqrt(arraySum(arrayMap(x -> (pow(x - median, 2)), durations)) / (length(durations) - 1)) as deviation')
  58.                                         );
  59.  
  60.         /*
  61.          * Выбираем все попытки
  62.          */
  63.         $query = $this->getCleanQuery()
  64.                       ->table('learners')
  65.                       ->arrayJoin('entitiesAttempts')
  66.                       ->select('learnerId', 'entitiesAttempts.entityIri as entityIri', 'entitiesAttempts.durationTotal as duration')
  67.                       ->where('entitiesAttempts.passed', '=', 1)
  68.                       ->where('entitiesAttempts.durationTotal', '>', 0)
  69.                       ->applyWherePeriod('entitiesAttempts.startedAt', $this->getPeriod())
  70.                       ->final();
  71.  
  72.         /*
  73.          * Тут применяется фильтр по лернерам и сущностям
  74.          */
  75.         if (!is_null($queryCallback)) {
  76.             $query = $queryCallback($query, $this);
  77.         }
  78.  
  79.         $attemptsQuery = $this->getCleanQuery()
  80.                               ->table($query)
  81.                               ->select('entityIri', 'learnerId', raw('(duration - median) / deviation as z'))
  82.                               ->anyLeftJoin($medianAndDeviationQuery, ['entityIri'])
  83.                               ->where('z', '<=', -2);
  84.  
  85.         /*
  86.          * Тут мы оборачиваем запрос и подменяем entityIri на childEntityIri
  87.          */
  88.         $query = $this->getCleanQuery()
  89.                       ->from($attemptsQuery)
  90.                       ->select('learnerId', 'entityIri as childEntityIri');
  91.  
  92.         /*
  93.          * Берем из временной таблицы информацию о сущности и разворачиваем все строки с дочками
  94.          */
  95.         $longTableQuery = $this->getCleanQuery()
  96.                                ->table(new Identifier($this->getTempTableName()))
  97.                                ->select('entityIri', 'childEntityIri')
  98.                                ->arrayJoin('childs as childEntityIri');
  99.  
  100.         /*
  101.          * Далее на каждую развернутую строчку джоиним попытки по сущностям по дочернему iri
  102.          */
  103.         $finalQuery = $this->getCleanQuery()
  104.                            ->table($longTableQuery)
  105.                            ->select('entityIri', 'learnerId')
  106.                            ->allLeftJoin($query, ['childEntityIri'])
  107.                            ->where('learnerId', '>', 0);
  108.        
  109.         return $this->getCleanQuery()
  110.             ->table($finalQuery)
  111.             ->select(raw('uniq(learnerId) as '.static::getIdentifier()), 'entityIri')
  112.             ->groupBy('entityIri');
  113.     }
  114.  
  115.     public function getJoinColumns(): array
  116.     {
  117.         return ['entityIri'];
  118.     }
  119. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement