BigQueryとPythonによるGithubへのダイビング
18143 ワード
私が働いている職場の大部分は、Googleを含めて、通常、毎年、または、毎年、パフォーマンス評価システムのいくつかの種類を持っている.そして、必ず、これらのシステムの全ては、数字が好きです.私の仕事の多くがオープンで行われるので、私は評価時間が来るとき、私が何をするかについての洞察を得るために、私のgithub用法に飛び込むようになりました.コミットまたはコミットのコードの数は、仕事の影響に直接翻訳されませんが、彼らはしばしば私の時間を費やした私の記憶をリフレッシュするのに役立ちます、私がしてきた仕事と私は、値を提供するために焦点を合わせる仕事の種類.
Githubは、直接使用することができますAPIを持っている間、あなたがダウンロードできるデータセットがありますGH Archive , データもavailable on Google BigQuery 一緒にother public datasets . GATHUBのような大部分のライブAPIは、レート制限やクォータを持ち、問い合わせの際によくインデックス付けされていないかもしれません.
私は、使用するのが好きですBigQuery Python libraries bigqueryにアクセスする.あなたは同様にオンラインコンソールを使うことができます、しかし、私は結果についてスクリプトをすることができることが役に立つとわかります.
!pip install google-cloud-bigquery
ライブラリがBigQueryと対話してインストールされたら、リクエストを作るのはほとんどのPythonistasに精通しています.この仕事のために、私は通常、使用しますcolab , またはローカルJupyter ノートブック.私は、私はクエリを簡単にダイビング、ローカルのデータをフィルタリングし、データの詳細を発見見つけることができます.閉じるこの動画はお気に入りから削除されていますJupyter Notebook I used to create this post .
Google QueryプロジェクトがBigQueryに接続するために必要なことは注目に値する.それは助けがあるquickstarts オンボードを加速するためにご利用いただけます.また、bigqueryに含まれますGoogle Cloud free-tier , しかし、多くのクエリはサイズが大きく、手当を排出できます.これをオーサリングするのと同様に、月あたりの1 TBの質問は無料です.Githubデータセットからのデータの1ヶ月あたりのクエリは、- 225 GBです.
# Follow these instructions to create a service account key:
# https://cloud.google.com/bigquery/docs/quickstarts/quickstart-client-libraries
# Then, replace the string below with the path to your service account key
export GOOGLE_APPLICATION_CREDENTIALS='/path/to/your/service-account-key.json'
いくつかの変数の設定とBigQueryのインポート
最初にすることは、スクリプトの残りの部分にいくつかの変数を設定することです.bigquery APIは私の知っている必要があります
GOOGLE_CLOUD_PROJECT_ID
また、Githubデータセットクエリでは、ターゲットユーザーと日付の範囲を知る必要があります.GOOGLE_CLOUD_PROJECT_ID = "google-cloud-project-id"
GITHUB_USERNAME = 'crwilcox'
START_DATE = "2020-08-01"
END_DATE = "2020-09-01"
START_DATE_SUFFIX = START_DATE[2:].replace('-', '')
END_DATE_SUFFIX = END_DATE[2:].replace('-', '')
from google.cloud import bigquery
client = bigquery.client.Client(project=GOOGLE_CLOUD_PROJECT_ID)
データセットへの掘削
出発点として、特定のユーザーのすべてのデータを見てみましょう.まずはタイプ別イベントを見てみましょう.
# Gather all events taken by a particular GitHub user
query = f"""SELECT type, event AS status, COUNT(*) AS count
FROM (
SELECT type, repo.name as repository, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, payload, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND
created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
)
GROUP BY type, status ORDER BY type, status;
"""
コストとクエリサイズの推定
クエリの1 TBがフリー層に含まれている間、bigqueryの多くのデータセットが大きく、それを排出するのは簡単です.ライブラリの最初のテストを実行する方法のクエリのサイズを推定する方法です.実行のコストと同様に効率を考慮するためにRun Run Queryを使うのは賢明です.例えば、私がこの2.5年にわたってこの質問を実行しようとするならば、クエリーサイズは3 TBを超えます、一方、最後の月はおよそ223 GBです.
# Estimating the bytes processed by the previous query.
job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)
query_job = client.query(
query,
job_config=job_config,
)
gb_processed = query_job.total_bytes_processed / (1024*1024*1024)
print("This query will process {} GB.".format(gb_processed))
This query will process 222.74764717370272 GB.
クエリの実行とデータの取得
今、このクエリのサイズが評価されている、それを実行することができますPandas dataframe 結果を探索するために使用することができます.
query_job = client.query(query)
result = query_job.result()
result.to_dataframe()
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
種類ステータス
カウント
0
イベント
なし
605
1
削除イベント
なし
255
2
フォーベント
なし
34
3
ゴルルミベント
なし
2
4
株式会社
"作成済み"
678年
5
発行イベント
"閉じた"
95
6
発行イベント
"オープン"
174
7
発行イベント
再開
2
8
メンバーイベント
"追加"
15
9
パブリックイベント
なし
1
10
プルラステンベント
"閉じた"
678年
11
プルラステンベント
"オープン"
443年
12
プルラステンベント
再開
7
13
PullRequestReview
"作成済み"
582年
14
プッシュイベント
なし
2243
15
releaseイベント
『発表』
90
16
ウォッチイベント
"開始"
61
がある20+ event types それはさらに調査できる.これらのイベントのいくつかは、与えられたユースケースにより興味深いかもしれません.パフォーマンスのレンズを使用していくつかのイベント
WatchEvent
or GollumEvent
, 面白くないかもしれません.しかし、他のイベントは、以下のような関連性の高い質問に答えるために使用できます.リポジトリによる統計情報の収集
私はGitHubとどのように相互作用するかについて考えるとき、私は組織とリポジトリに関して考えます.
リポジトリによってグループ化するクエリにいくつかの小さな変更を行うことで、いくつかの新しい統計を得ることができます.
query = f"""
SELECT repository, type, event AS status, COUNT(*) AS count
FROM (
SELECT type, repo.name as repository, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, payload, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND
created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
)
GROUP BY repository, type, status ORDER BY repository, type, status;
"""
query_job = client.query(query)
results = [i for i in query_job.result()]
上記のクエリをより正確にすることができますが、Pythonで一度データを分離するほうが簡単です.また、パンダがここで使用されないことに注意してください、しかし、代わりに結果は列挙されて、Pythonオブジェクトとして使われます.ここから、より高いレベルの情報を収集することができます.たとえば、ユーザーによってリリースされているか、またはどのように多くのプル要求が作成されているリリース.
# Releases made
count = [int(row.count) for row in results
if row.type == 'ReleaseEvent']
print(f"{sum(count)} Releases across {len(count)} repos")
# PRs Made
count = [int(row.count) for row in results
if row.type == 'PullRequestEvent' and
row.status == "\"opened\""]
print(f"{sum(count)} PRs opened across {len(count)} repos")
# PR Comments Left
count = [int(row.count) for row in results
if row.type == 'PullRequestReviewCommentEvent']
print(f"{sum(count)} PR comments across {len(count)} repos")
# Issues Created
count = [int(row.count) for row in results
if row.type == 'IssuesEvent' and
row.status == "\"opened\""]
print(f"{sum(count)} issues opened across {len(count)} repos")
# Issues Closed
count = [int(row.count) for row in results
if row.type == 'IssuesEvent' and
row.status == "\"closed\""]
print(f"{sum(count)} issues closed across {len(count)} repos")
# Issue Comments
count = [int(row.count) for row in results
if row.type == 'IssueCommentEvent']
print(f"{sum(count)} issue comments across {len(count)} repos")
# Push Events
count = [int(row.count) for row in results
if row.type == 'PushEvent']
print(f"{sum(count)} pushes across {len(count)} repos")
0 Releases across 0 repos
3 PRs opened across 3 repos
61 PR comments across 8 repos
6 issues opened across 3 repos
2 issues closed across 1 repos
17 issue comments across 9 repos
78 pushes across 13 repos
だから別のイベントの種類は、各ペイロードをさらに見ている.何か別の.
もちろん、いくつかの生産性の少ない、より面白いものを見つけることができます.たとえば、何回、私は結着修正を犯しましたか?
# How often do I forget to run the tests before committing?
query = f"""
SELECT type, repo.name as repository, JSON_EXTRACT(payload, '$.commits') as commits,
actor.login, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND type = "PushEvent"
AND created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
"""
query_job = client.query(query)
result = query_job.result()
df = result.to_dataframe()
df
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
種類倉庫
コミットする
ログイン
創造する
0
プッシュイベント
Pythonのストア
[ sha ] :"91 d 6580 e 2903 b 8796 d 8 c 6364 b 7 ;
クスノキ
2020 - 08 - 13 16 : 53 : 15 + 00 : 00
1
プッシュイベント
Pythonのストア
[ sha ] :"f 3 bedc 1 efae 4430 c 6853581 1 faff 06 i 513548
クスノキ
2020 - 08 - 13 16 : 53 : 18 + 00 : 00
2
プッシュイベント
パイソン・ファイヤーストア
{ sha ":
クスノキ
2020 - 08 - 06 02 : 58 : 25 + 00 : 00
3
プッシュイベント
パイソン・ファイヤーストア
[ sha ] :"afff 842 a 3356 cts 5 b 0342 b 573121 c 12 b 2 d 601 .
クスノキ
2020 - 08 - 06 05 : 55 : 58 + 00 : 00
4
プッシュイベント
パイソン・ファイヤーストア
[ sha ] :"C 93 a 077 d 6 d 6 bc 6 e 3 c 5070 a 3 a 5070 a 3 b 0439
クスノキ
2020 - 08 - 06 05 : 57 : 55 00 : 00
...
...
...
...
...
...
73
プッシュイベント
パイソン・ファイヤーストア
[ sha ] :"B 902 CA 30 ad 17 bc 0 d 51 d 1 b 03494 e 089 ca 08 ...
クスノキ
2020 - 08 - 04 17 : 34 : 22 + 00 : 00
74
プッシュイベント
グーグル・ライブラリ
[ sha ] :"e 963 b 33 ce 8 c 93994 c 640154 d 5 b 965 c 4 e 3 c 8 3 c 8 .
クスノキ
2020 - 08 - 07 21 : 10 : 53 + 00 : 00
75
プッシュイベント
Pythonドキュメントサンプル
[ sha ] :"86 dbbb 504 f 1423 f 7 d 33796 b 53096 c 5 e 285 e
クスノキ
2020 - 08 - 12 17 : 28 : 08 + 00 : 00
76
プッシュイベント
Pythonのストア
[ sha ] :"7122 f 24 d 0049 ecad 4 e 71 cbacb 4 bb b 26 26 b 4 dd 4 ...
クスノキ
2020 - 08 - 20 19 : 36 : 16 + 00 : 00
77
プッシュイベント
CRWilcox/ExporsureNotification - Verification - S .
[ sha ] :"f 087 f 323 d 0558436
クスノキ
2020 - 05 - 05 19 : 21 : 51 + 00 : 00
78行×5列
最初の結果を見ると、JSONデータの形状をよりよく理解できる.照会することができるメッセージフィールドがあります.
df["commits"][0]
'[{"sha":"ce97f5e939bcdca1c9c46f472f41ead04ac6b2fe","author":{"name":"Chris Wilcox","email":"[email protected]"},"message":"fix: lint","distinct":true,"url":"https://api.github.com/repos/crwilcox/python-firestore/commits/ce97f5e939bcdca1c9c46f472f41ead04ac6b2fe"}]'
len(df[df['commits'].str.contains("lint")])
それで、先月私のコミットの14 %(11/78)のようです.誰かがテストスイートを最初に実行するには少し良いかもしれない😅もう少し生産的に戻る
私が取り組んでいるプロジェクトの一部Conventional Commits 構文が使用されます.これは私がやっている仕事のタイプのアイデアを提供することができます.今のところ、私は非従来のコミットを無視して、それらをまとめます.
import json
from collections import Counter
commit_types = Counter()
types = [
"fix", "feat", "chore", "docs", "style",
"refactor", "perf", "test", "revert"
]
for i in range(len(df)):
commits = df.loc[i, "commits"]
json_commits = json.loads(commits)
for commit in json_commits:
# If the first line contains a : assume the left side is the type.
found_type = False
for t in types:
if commit['message'].startswith(t):
commit_types[t] += 1
found_type = True
break
else:
commit_types["non-conventional"] += 1
commit_types
Counter({'chore': 21,
'docs': 3,
'feat': 14,
'fix': 26,
'non-conventional': 107,
'refactor': 8,
'test': 2})
それは私のコミットのほとんどが修正され、適切な数は雑用であり、次は機能の実装です.残念なことに、期間の間のかなりの数のコミットは従来のコミットでありません、しかし、傾向がそれらのコミットのために類似していると仮定するのはたぶん安全です.どのような使用は、このデータを発見することができますか?
私は、私がGitTubに私の時間を費やす場所と異なる倉庫での私の時間がどのように壊れるかについて見るために啓発することを見つけるけれども、私があなたがこのデータを使うことができたものの表面を削ることを望むことができると思いません.あなたがこのデータセットを使うかもしれない方法に関するいくつかのより多くの考えは、ここにあります.
リポジトリのすべてのGithubの問題を取得します。
GITHUB_ORGANIZATION = 'googleapis' #@param {type:"string"}
GITHUB_REPOSITORY = 'python-%' #@param {type:"string"}
# Get all GitHub issues in a repository. In the example, a wildcard is used
# to get all issues
query = f"""
SELECT type, repo.name as repository, JSON_EXTRACT(payload, '$.pull_request.title') as title, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, JSON_EXTRACT(payload, '$.pull_request.html_url') as url, created_at
FROM `githubarchive.day.20*`
WHERE repo.name LIKE '{GITHUB_ORGANIZATION}/{GITHUB_REPOSITORY}' AND type = "PullRequestEvent"
AND created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
"""
query_job = client.query(query)
result = query_job.result()
result.to_dataframe()
あなたによって作成されたすべてのGithubの問題を取得します。
# Get all GitHub issues by this login
query = f"""
SELECT type, repo.name as repository, JSON_EXTRACT(payload, '$.issue.title') as title, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, JSON_EXTRACT(payload, '$.issue.html_url') as url, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND type = "IssuesEvent"
AND created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
"""
query_job = client.query(query)
result = query_job.result()
result.to_dataframe()
すべての問題コメントを取得します。
# Get all issue comments
query = f"""
SELECT type, repo.name as repository, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, JSON_EXTRACT(payload, '$.issue.html_url') as url, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND type = "IssueCommentEvent"
AND created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
"""
query_job = client.query(query)
result = query_job.result()
result.to_dataframe()
すべてのPRコメントを得てください。
# Get all PR comments created by this login
query = f"""
SELECT type, repo.name as repository, actor.login,
JSON_EXTRACT(payload, '$.action') AS event, JSON_EXTRACT(payload, '$.comment.html_url') as url, created_at
FROM `githubarchive.day.20*`
WHERE actor.login = '{GITHUB_USERNAME}' AND type = "PullRequestReviewCommentEvent"
AND created_at BETWEEN TIMESTAMP('{START_DATE}') AND
TIMESTAMP('{END_DATE}') AND
_TABLE_SUFFIX BETWEEN '{START_DATE_SUFFIX}' AND
'{END_DATE_SUFFIX}'
"""
query_job = client.query(query)
result = query_job.result()
result.to_dataframe()
当初公開https://chriswilcox.dev 2020年9月02日Reference
この問題について(BigQueryとPythonによるGithubへのダイビング), 我々は、より多くの情報をここで見つけました https://dev.to/googlecloud/diving-into-github-with-bigquery-and-python-3gfnテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol