Если вы следили за моими предыдущими статьями об API Github , вы знаете, что разработчики Github делают все возможное для облегчения взаимодействия с данными Github. В этой статье мы рассмотрим API публичных событий Github и по пути создадим небольшую демонстрацию.
Что такое публичные мероприятия Github?
События Github — это взаимодействия пользователей, такие как добавление, объединение, создание репозиториев и т. Д. Это похоже на сохранение истории Github. Тем не менее, мы ограничены последними 300 событиями, и это проблема, если вы хотите искать данные всей истории.
Илья Григорик хотел отслеживать свой проект с открытым исходным кодом, но из-за ограничения API публичных событий Github он решил создать веб-сайт GithubArchive, где он запрашивает API Github и сохраняет результаты. Вы можете запросить архив со ссылками, такими как http://data.githubarchive.org/2015-01-01-15.json.gz
и вы получите архив, содержащий полезную нагрузку JSON. Это решение не очень эффективно и не помогает запрашивать историю данных, поэтому, когда Google BigQuery был выпущен, Григорик переместил все свои данные в новое хранилище и сделал его общедоступным.
Почему BigQuery?
Google BigQuery был создан для решения проблемы задержки запросов. Когда вы имеете дело с большими данными, вам необходимо иметь правильное оборудование и инфраструктуру для правильной обработки нагрузки. Теперь у вас есть возможность перенести свою базу данных только для добавления в инфраструктуру Google и увидеть миллионы строк данных, обработанных за считанные секунды.
Если вы не знакомы с API Google, обязательно ознакомьтесь с этим руководством о начале нового проекта Google API . После этого обязательно включите API BigQuery на консоли разработчиков Google.
Настройка среды
Я буду использовать Laravel в качестве своего предпочтительного фреймворка и Homestead Improved для моей виртуальной машины. Мы получим наши учетные данные Google из файла config/google.php
, и в соответствии с правилами безопасности Laravel я .env
эти учетные данные в файле .env
.
// config/google.php return [ 'app_name' => env('app_name'), 'client_id' => env('client_id'), 'client_secret' => env('client_secret'), 'api_key' => env('api_key') ];
// .env APP_DEBUG=true app_name='Optional app name' client_id='CHANGE IT' client_secret='CHANGE IT' api_key='CHANGE IT'
Я также создам нового поставщика услуг для хранения привязок наших служб Google.
// app/Providers/BigQueryServiceProvider.php class BigQueryServiceProvider extends ServiceProvider { public function register() { $this->app->bind('GoogleClient', function () { $googleClient = new \Google_Client(); $googleClient->setAccessToken(\Session::get("token")); return $googleClient; }); $this->app->bind('bigquery', function () { $googleClient = \App::make('GoogleClient'); $bigquery = new \Google_Service_Bigquery($googleClient); return $bigquery; }); } }
// config/app.php // ... 'providers' => [ // ... 'App\Providers\BigQueryServiceProvider', ]
Поскольку нашему приложению для запроса API потребуется авторизация пользователя, я попытался упростить этот процесс, создав промежуточное программное обеспечение для защиты наших маршрутов.
// app/Http/Middleware/GoogleLogin.php class GoogleLogin { public function handle($request, Closure $next) { $ga = \App::make('\App\Services\GoogleLogin'); if (!$ga->isLoggedIn()) { return redirect('login'); } return $next($request); } }
// app/Kernel.php protected $routeMiddleware = [ // ... 'google_login' => '\App\Http\Middleware\GoogleLogin' ];
Google BigQuery Query Console
Прежде чем мы начнем работать с BigQuery с использованием библиотеки PHP, давайте начнем исследовать консоль BigQuery Query . На консоли есть кнопка Compose Query
, чтобы вы могли писать свои запросы. Ниже у нас есть ссылка Query History
которая показывает историю наших запросов. Поскольку на наши запросы потребуется некоторое время, мы можем выполнить запрос как задание и через некоторое время запросить его статистику — ссылка «Журнал Job History
содержит список текущих заданий.
Если вы хотите взглянуть на схему таблицы и изучить доступные поля, вы можете перейти к левой панели и выбрать таблицу временной шкалы Github.
Google BigQuery API и Github
В качестве примера, давайте попробуем получить десятку популярных проектов на Github. Я буду определять популярность как количество вилок. Класс Google_Service_Bigquery
отвечает за все типы взаимодействий с Google BigQuery API. Ранее я ввел термин « jobs
, что означает, что мы можем выполнить запрос в фоновом режиме и со временем получить его статус, чтобы увидеть, завершен он или нет.
// app/Http/routes.php Route::any('/topTen', ['middleware' => 'google_login', 'as' => 'topTen', 'uses' => 'BigQueryAPIController@topTen']); // app/Http/Controllers/BigQueryAPIController.php class BigQueryAPIController extends Controller { public function __construct() { $this->bigqueryService = \App::make("bigquery"); } public function topTen() { $projectID = 'modular-robot-22'; $query_str = "SELECT repository_url, MAX(repository_forks) as max_forks" . " FROM githubarchive:github.timeline" . " GROUP EACH BY repository_url" . " ORDER BY max_forks DESC" . " LIMIT 10"; $query = new \Google_Service_Bigquery_QueryRequest(); $query->setQuery($query_str); $result = $this->bigqueryService->jobs->query($projectID, $query); $fields = $result->getSchema()->getFields(); $rows = $result->getRows(); dump($fields); foreach ($rows as $row) { dump($row->getF()); } } }
Идентификатор проекта можно найти в консоли разработчиков Google . Строка запроса respository_url
и MAX(repository_forks)
. Метод getSchema
возвращает экземпляр Google_Service_Bigquery_TableSchema
который содержит имена выбранных столбцов из ответа, а метод getRows
возвращает итеративный список Google_Service_Bigquery_TableRow
. Вывод выглядит следующим образом.
githubarchive:github.timeline
данных githubarchive:github.timeline
устарел и больше не будет обновляться. Новый способ работы с данными — через определенный временной диапазон (набор данных года, набор данных месяца, набор данных дня); Вы можете посетить githubarchive, чтобы узнать больше об этом. Теперь мы должны обновить наш запрос выше, чтобы работать с прошлогодними данными.
// app/Http/Controllers/BigQueryAPIController.php public function topTen() { $projectID = 'modular-robot-22'; $query_str = "SELECT repository_url, MAX(repository_forks) as max_forks" . " FROM githubarchive:year.2014" . " GROUP EACH BY repository_url" . " ORDER BY max_forks DESC" . " LIMIT 10"; //... }
Десять лучших репозиториев по языкам
Мы адаптируем предыдущий запрос для извлечения репозиториев определенного языка. Наша разметка представления будет содержать форму и набор языковых опций.
// resources/views/home.blade.php <form action="/" method="POST" class="form-inline"> <label for="language">Language: </label> <select name="language" id="language" class="form-control"> <option value="PHP">PHP</option> <option value="JavaScript">JavaScript</option> <option value="CSS">CSS</option> <option value="Python">Python</option> </select> <input type="submit" class="form-control" value="Submit"/> </form>
Когда пользователь отправляет форму, мы получаем выбранный язык и заполняем условие в нашем запросе SQL. Поскольку мы напечатаем наш результат запроса в виде таблицы, мы отделим часть заголовка таблицы от тела таблицы.
// app/Http/Controllers/BigQueryAPIController.php public function topTen() { if (!\Input::has('language')) { return \View::make('home', ['repos' => null]); } $language = \Input::get('language', 'PHP'); $projectID = 'modular-robot-647'; $query_str = "SELECT repository_url, MAX(repository_forks) as max_forks" . " FROM githubarchive:year.2014" . " WHERE repository_language='$language'" . " GROUP EACH BY repository_url" . " ORDER BY max_forks DESC" . " LIMIT 10"; $query = new \Google_Service_Bigquery_QueryRequest(); $query->setQuery($query_str); $result = $this->bigqueryService->jobs->query($projectID, $query); // getting the table header $fields = $result->getSchema()->getFields(); // query response rows $repos = $result->getRows(); return \View::make('home', ['repos' => $repos, 'tableHeader' => $fields]); }
Единственное, что изменилось по сравнению с предыдущим запросом, это условие where
, которое фильтрует языки по пользовательскому вводу. При распечатке таблицы результатов я старался сделать вещи общими для большинства запросов.
// resources/views/home.blade.php @if($repos) <table class="table table-hover"> <tr> @foreach($tableHeader as $item) <th>{{$item->getName()}}</th> @endforeach </tr> @foreach($repos as $repo) <tr> @foreach($repo->getF() as $item) <td>{{$item->getV()}}</td> @endforeach </tr> @endforeach </table> @else <h2>Nothing to show</h2> @endif
Метод getF()
возвращает содержимое строки, а метод getV()
возвращает содержимое ячейки. Вы можете проверить значения результатов, сбросив имена классов и пройдя через свойства.
Похоже, что CodeIgniter был на вершине, когда я тестировал это, но на момент написания статьи это не так — Laravel является самой популярной средой PHP на Github. Обязательно зайдите на страницу трендовых репозиториев Github, чтобы увидеть данные почти в реальном времени.
Если вы решили работать с данными, добавленными после 01/01/2015
, схема также будет содержать вложенные записи плюс поле полезной нагрузки в кодировке JSON. Это относится и к работе с дневными наборами данных — вы можете использовать консоль Google BigQuery для проверки схемы набора данных. BigQuery имеет несколько полезных функций JSON для работы с данными в кодировке JSON, обязательно ознакомьтесь с ними.
Вывод
В этой статье мы рассказали о публичных мероприятиях Github и о том, как их можно использовать через BigQuery. Заключительная демонстрация включает в себя пример базового использования, но вы можете поэкспериментировать с API и подготовиться к ежегодной проблеме данных Github с некоторыми интересными фактами о данных Github. Что вы думаете об API Github Events? У вас есть какие-нибудь интересные идеи для решения проблемы с данными? Дайте нам знать!