--- slug: /ja/getting-started/example-datasets/github sidebar_label: Githubリポジトリ sidebar_position: 1 description: ClickHouseのGitHubリポジトリまたはお好みのリポジトリを分析します --- # GitHubデータを使用したClickHouseでのクエリ記述 このデータセットには、ClickHouseリポジトリのすべてのコミットと変更が含まれています。これは、ClickHouseに付属しているネイティブの`git-import`ツールを使用して生成できます。 生成されたデータは、以下の各テーブルに対して`tsv`ファイルを提供します: - `commits` - 統計を伴うコミット。 - `file_changes` - 各コミットで変更されたファイルと、その変更に関する情報および統計。 - `line_changes` - 各コミットで変更されたファイル内の変更行、およびその行に関する完全な情報および前回の変更に関する情報。 2022年11月8日時点で、各TSVファイルのサイズと行数はおおよそ以下の通りです: - `commits` - 7.8M - 266,051行 - `file_changes` - 53M - 266,051行 - `line_changes` - 2.7G - 7,535,157行 # 目次 - [GitHubデータを使用したClickHouseでのクエリ記述](#githubデータを使用したclickhouseでのクエリ記述) - [目次](#目次) - [データの生成](#データの生成) - [データのダウンロードと挿入](#データのダウンロードと挿入) - [クエリ](#クエリ) - [単一ファイルの履歴](#単一ファイルの履歴) - [現在のアクティブファイルを見つける](#現在のアクティブファイルを見つける) - [最も多く変更されたファイルをリストする](#最も多く変更されたファイルをリストする) - [コミットは通常、週のどの日に発生するか?](#コミットは通常週のどの日に発生するか) - [サブディレクトリ/ファイルの履歴 - 行数、コミット数、寄稿者数の推移](#サブディレクトリファイルの履歴---行数コミット数寄稿者数の推移) - [最大著者数のファイルリスト](#最大著者数のファイルリスト) - [リポジトリ内の最古のコード行](#リポジトリ内の最古のコード行) - [最も古い履歴を持つファイル](#最も古い履歴を持つファイル) - [ドキュメントとコードに関する寄稿者の分布](#ドキュメントとコードに関する寄稿者の分布) - [最も多様な影響を持つ著者](#最も多様な影響を持つ著者) - [著者のお気に入りファイル](#著者のお気に入りファイル) - [著者数が最も少ない最大ファイル](#著者数が最も少ない最大ファイル) - [コミットとコード行の時間別分布; 曜日別、著者別; 特定のサブディレクトリ用](#コミットとコード行の時間別分布-曜日別著者別-特定のサブディレクトリ用) - [著者の行列:他の著者のコードを書き直す傾向を示す](#著者の行列他の著者のコードを書き直す傾向を示す) - [曜日ごとの最高貢献者は誰ですか?](#曜日ごとの最高貢献者は誰ですか) - [リポジトリ全体のコード年齢の分布](#リポジトリ全体のコード年齢の分布) - [各著者のコードの何パーセントが他の著者によって削除されたか?](#各著者のコードの何パーセントが他の著者によって削除されたか) - [最も多く書き直されたファイルのリスト?](#最も多く書き直されたファイルのリスト) - [コードがリポジトリに留まる可能性が最も高い曜日は?](#コードがリポジトリに留まる可能性が最も高い曜日は) - [平均コード年齢でソートされたファイル](#平均コード年齢でソートされたファイル) - [誰がより多くのテスト/CPPコード/コメントを書く傾向があるのか?](#誰がより多くのテストcppコードコメントを書く傾向があるのか) - [著者のコミットが時間経過とともにコード/コメントの割合に関してどのように変化するのか?](#著者のコミットが時間経過とともにコードコメントの割合に関してどのように変化するのか) - [コードが書き換えられるまでの平均時間と中央値(コードの decay の半減期)は?](#コードが書き換えられるまでの平均時間と中央値コードの-decay-の半減期は) - [どのような時がコードが書き換えられる可能性が最も高いのか?](#どのような時がコードが書き換えられる可能性が最も高いのか) - [どの著者のコードが最も安定しているか?](#どの著者のコードが最も安定しているか) - [ある著者による最も連続したコミットの日数](#ある著者による最も連続したコミットの日数) - [ファイルの行ごとのコミット履歴](#ファイルの行ごとのコミット履歴) - [未解決の質問](#未解決の質問) - [Git blame](#git-blame) - [関連コンテンツ](#関連コンテンツ) # データの生成 これは任意です。データは自由に配布しています - [データのダウンロードと挿入](#データのダウンロードと挿入)を参照してください。 ```bash git clone git@github.com:ClickHouse/ClickHouse.git cd ClickHouse clickhouse git-import --skip-paths 'generated\.cpp|^(contrib|docs?|website|libs/(libcityhash|liblz4|libdivide|libvectorclass|libdouble-conversion|libcpuid|libzstd|libfarmhash|libmetrohash|libpoco|libwidechar_width))/' --skip-commits-with-messages '^Merge branch ' ``` この操作は、ClickHouseリポジトリに対して約3分(2022年11月8日時点のMacBook Pro 2021で)かかります。 利用可能なオプションの完全なリストは、ツールのネイティブヘルプから取得できます。 ```bash clickhouse git-import -h ``` このヘルプでは、上記の各テーブルのDDLも提供されます。例えば: ``` CREATE TABLE git.commits ( hash String, author LowCardinality(String), time DateTime, message String, files_added UInt32, files_deleted UInt32, files_renamed UInt32, files_modified UInt32, lines_added UInt32, lines_deleted UInt32, hunks_added UInt32, hunks_removed UInt32, hunks_changed UInt32 ) ENGINE = MergeTree ORDER BY time; ``` **これらのクエリは、どのリポジトリでも機能するはずです。自由に探索して、結果を報告してください** 実行時間に関するいくつかのガイドライン(2022年11月時点): - Linux - `~/clickhouse git-import` - 160分 # データのダウンロードと挿入 以下のデータを使用して、作業環境を再現できます。あるいは、このデータセットはplay.clickhouse.comで入手可能です - 詳細は[クエリ](#クエリ)を参照してください。 以下のリポジトリのために生成されたファイルが見つかります: - ClickHouse(2022年11月8日) - https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/commits.tsv.xz - 2.5 MB - https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/file_changes.tsv.xz - 4.5MB - https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/line_changes.tsv.xz - 127.4 MB - Linux(2022年11月8日) - https://datasets-documentation.s3.amazonaws.com/github/commits/linux/commits.tsv.xz - 44 MB - https://datasets-documentation.s3.amazonaws.com/github/commits/linux/file_changes.tsv.xz - 467MB - https://datasets-documentation.s3.amazonaws.com/github/commits/linux/line_changes.tsv.xz - 1.1G このデータを挿入するには、以下のクエリを実行してデータベースを準備します: ```sql DROP DATABASE IF EXISTS git; CREATE DATABASE git; CREATE TABLE git.commits ( hash String, author LowCardinality(String), time DateTime, message String, files_added UInt32, files_deleted UInt32, files_renamed UInt32, files_modified UInt32, lines_added UInt32, lines_deleted UInt32, hunks_added UInt32, hunks_removed UInt32, hunks_changed UInt32 ) ENGINE = MergeTree ORDER BY time; CREATE TABLE git.file_changes ( change_type Enum('Add' = 1, 'Delete' = 2, 'Modify' = 3, 'Rename' = 4, 'Copy' = 5, 'Type' = 6), path LowCardinality(String), old_path LowCardinality(String), file_extension LowCardinality(String), lines_added UInt32, lines_deleted UInt32, hunks_added UInt32, hunks_removed UInt32, hunks_changed UInt32, commit_hash String, author LowCardinality(String), time DateTime, commit_message String, commit_files_added UInt32, commit_files_deleted UInt32, commit_files_renamed UInt32, commit_files_modified UInt32, commit_lines_added UInt32, commit_lines_deleted UInt32, commit_hunks_added UInt32, commit_hunks_removed UInt32, commit_hunks_changed UInt32 ) ENGINE = MergeTree ORDER BY time; CREATE TABLE git.line_changes ( sign Int8, line_number_old UInt32, line_number_new UInt32, hunk_num UInt32, hunk_start_line_number_old UInt32, hunk_start_line_number_new UInt32, hunk_lines_added UInt32, hunk_lines_deleted UInt32, hunk_context LowCardinality(String), line LowCardinality(String), indent UInt8, line_type Enum('Empty' = 0, 'Comment' = 1, 'Punct' = 2, 'Code' = 3), prev_commit_hash String, prev_author LowCardinality(String), prev_time DateTime, file_change_type Enum('Add' = 1, 'Delete' = 2, 'Modify' = 3, 'Rename' = 4, 'Copy' = 5, 'Type' = 6), path LowCardinality(String), old_path LowCardinality(String), file_extension LowCardinality(String), file_lines_added UInt32, file_lines_deleted UInt32, file_hunks_added UInt32, file_hunks_removed UInt32, file_hunks_changed UInt32, commit_hash String, author LowCardinality(String), time DateTime, commit_message String, commit_files_added UInt32, commit_files_deleted UInt32, commit_files_renamed UInt32, commit_files_modified UInt32, commit_lines_added UInt32, commit_lines_deleted UInt32, commit_hunks_added UInt32, commit_hunks_removed UInt32, commit_hunks_changed UInt32 ) ENGINE = MergeTree ORDER BY time; ``` データを挿入するには、`INSERT INTO SELECT`と[s3機能](https://clickhouse.com/docs/ja/integrations/s3/s3-table-functions/)を使用します。例えば、以下のようにClickHouseファイルをそれぞれのテーブルに挿入します: *commits* ```sql INSERT INTO git.commits SELECT * FROM s3('https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/commits.tsv.xz', 'TSV', 'hash String,author LowCardinality(String), time DateTime, message String, files_added UInt32, files_deleted UInt32, files_renamed UInt32, files_modified UInt32, lines_added UInt32, lines_deleted UInt32, hunks_added UInt32, hunks_removed UInt32, hunks_changed UInt32') 0 rows in set. Elapsed: 1.826 sec. Processed 62.78 thousand rows, 8.50 MB (34.39 thousand rows/s., 4.66 MB/s.) ``` *file_changes* ```sql INSERT INTO git.file_changes SELECT * FROM s3('https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/file_changes.tsv.xz', 'TSV', 'change_type Enum(\'Add\' = 1, \'Delete\' = 2, \'Modify\' = 3, \'Rename\' = 4, \'Copy\' = 5, \'Type\' = 6), path LowCardinality(String), old_path LowCardinality(String), file_extension LowCardinality(String), lines_added UInt32, lines_deleted UInt32, hunks_added UInt32, hunks_removed UInt32, hunks_changed UInt32, commit_hash String, author LowCardinality(String), time DateTime, commit_message String, commit_files_added UInt32, commit_files_deleted UInt32, commit_files_renamed UInt32, commit_files_modified UInt32, commit_lines_added UInt32, commit_lines_deleted UInt32, commit_hunks_added UInt32, commit_hunks_removed UInt32, commit_hunks_changed UInt32') 0 rows in set. Elapsed: 2.688 sec. Processed 266.05 thousand rows, 48.30 MB (98.97 thousand rows/s., 17.97 MB/s.) ``` *line_changes* ```sql INSERT INTO git.line_changes SELECT * FROM s3('https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/line_changes.tsv.xz', 'TSV', ' sign Int8, line_number_old UInt32, line_number_new UInt32, hunk_num UInt32, hunk_start_line_number_old UInt32, hunk_start_line_number_new UInt32, hunk_lines_added UInt32,\n hunk_lines_deleted UInt32, hunk_context LowCardinality(String), line LowCardinality(String), indent UInt8, line_type Enum(\'Empty\' = 0, \'Comment\' = 1, \'Punct\' = 2, \'Code\' = 3), prev_commit_hash String, prev_author LowCardinality(String), prev_time DateTime, file_change_type Enum(\'Add\' = 1, \'Delete\' = 2, \'Modify\' = 3, \'Rename\' = 4, \'Copy\' = 5, \'Type\' = 6),\n path LowCardinality(String), old_path LowCardinality(String), file_extension LowCardinality(String), file_lines_added UInt32, file_lines_deleted UInt32, file_hunks_added UInt32, file_hunks_removed UInt32, file_hunks_changed UInt32, commit_hash String,\n author LowCardinality(String), time DateTime, commit_message String, commit_files_added UInt32, commit_files_deleted UInt32, commit_files_renamed UInt32, commit_files_modified UInt32, commit_lines_added UInt32, commit_lines_deleted UInt32, commit_hunks_added UInt32, commit_hunks_removed UInt32, commit_hunks_changed UInt32') 0 rows in set. Elapsed: 50.535 sec. Processed 7.54 million rows, 2.09 GB (149.11 thousand rows/s., 41.40 MB/s.) ``` # クエリ ツールはヘルプ出力に基づいて、いくつかのクエリを提案しています。私たちは、これらに加えて、興味深い追加のクエリにも回答しています。これらのクエリは、ツールの任意の順序に対しておおよそ増加する複雑さを持っています。 このデータセットは、`git_clickhouse`データベースで[play.clickhouse.com](https://sql.clickhouse.com?query_id=DCQPNPAIMAQXRLHYURLKVJ)で入手可能です。すべてのクエリのために、この環境へのリンクを提供しますが、データベース名は必要に応じて調整します。データ収集の時期によって、playの結果はここに表示されているものと異なる場合があります。 ## 単一ファイルの履歴 最もシンプルなクエリです。ここでは、`StorageReplicatedMergeTree.cpp`のすべてのコミットメッセージを表示します。これらはより興味深いものが多いので、最新のメッセージを最初に表示するようにソートします。 [play](https://sql.clickhouse.com?query_id=COAZRFX2YFULDBXRQTCQ1S) ```sql SELECT time, substring(commit_hash, 1, 11) AS commit, change_type, author, path, old_path, lines_added, lines_deleted, commit_message FROM git.file_changes WHERE path = 'src/Storages/StorageReplicatedMergeTree.cpp' ORDER BY time DESC LIMIT 10 ┌────────────────time─┬─commit──────┬─change_type─┬─author─────────────┬─path────────────────────────────────────────┬─old_path─┬─lines_added─┬─lines_deleted─┬─commit_message───────────────────────────────────┐ │ 2022-10-30 16:30:51 │ c68ab231f91 │ Modify │ Alexander Tokmakov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 13 │ 10 │ partを削除状態でアクセスする修正 │ │ 2022-10-23 16:24:20 │ b40d9200d20 │ Modify │ Anton Popov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 28 │ 30 │ DataPartStorageの定数性のセマンティクス向上 │ │ 2022-10-23 01:23:15 │ 56e5daba0c9 │ Modify │ Anton Popov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 28 │ 44 │ DataPartStorageBuilderを削除 │ │ 2022-10-21 13:35:37 │ 851f556d65a │ Modify │ Igor Nikonov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 3 │ 2 │ 使用されていないパラメータを削除 │ │ 2022-10-21 13:02:52 │ 13d31eefbc3 │ Modify │ Igor Nikonov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 4 │ 4 │ Replicated merge treeの改良 │ │ 2022-10-21 12:25:19 │ 4e76629aafc │ Modify │ Azat Khuzhin │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 3 │ 2 │ -Wshorten-64-to-32への修正 │ │ 2022-10-19 13:59:28 │ 05e6b94b541 │ Modify │ Antonio Andelic │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 4 │ 0 │ 改良 │ │ 2022-10-19 13:34:20 │ e5408aac991 │ Modify │ Antonio Andelic │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 3 │ 53 │ 論理を簡素化 │ │ 2022-10-18 15:36:11 │ 7befe2825c9 │ Modify │ Alexey Milovidov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 2 │ 2 │ StorageReplicatedMergeTree.cppの更新 │ │ 2022-10-18 15:35:44 │ 0623ad4e374 │ Modify │ Alexey Milovidov │ src/Storages/StorageReplicatedMergeTree.cpp │ │ 1 │ 1 │ StorageReplicatedMergeTree.cppの更新 │ └─────────────────────┴─────────────┴─────────────┴────────────────────┴─────────────────────────────────────────────┴──────────┴─────────────┴───────────────┴──────────────────────────────────────────────────┘ 10 rows in set. Elapsed: 0.006 sec. Processed 12.10 thousand rows, 1.60 MB (1.93 million rows/s., 255.40 MB/s.) ``` リネームイベントの前に存在していた変更は表示しないため、リネームを除外し、行変更を確認することもできます: [play](https://sql.clickhouse.com?query_id=AKS9SYLARFMZCHGAAQNEBN) ```sql SELECT time, substring(commit_hash, 1, 11) AS commit, sign, line_number_old, line_number_new, author, line FROM git.line_changes WHERE path = 'src/Storages/StorageReplicatedMergeTree.cpp' ORDER BY line_number_new ASC LIMIT 10 ┌────────────────time─┬─commit──────┬─sign─┬─line_number_old─┬─line_number_new─┬─author───────────┬─line──────────────────────────────────────────────────┐ │ 2020-04-16 02:06:10 │ cdeda4ab915 │ -1 │ 1 │ 1 │ Alexey Milovidov │ #include │ │ 2020-04-16 02:06:10 │ cdeda4ab915 │ 1 │ 2 │ 1 │ Alexey Milovidov │ #include │ │ 2020-04-16 02:06:10 │ cdeda4ab915 │ 1 │ 2 │ 2 │ Alexey Milovidov │ │ │ 2021-05-03 23:46:51 │ 02ce9cc7254 │ -1 │ 3 │ 2 │ Alexey Milovidov │ #include │ │ 2021-05-27 22:21:02 │ e2f29b9df02 │ -1 │ 3 │ 2 │ s-kat │ #include │ │ 2022-10-03 22:30:50 │ 210882b9c4d │ 1 │ 2 │ 3 │ alesapin │ #include │ │ 2022-10-23 16:24:20 │ b40d9200d20 │ 1 │ 2 │ 3 │ Anton Popov │ #include │ │ 2021-06-20 09:24:43 │ 4c391f8e994 │ 1 │ 2 │ 3 │ Mike Kot │ #include "Common/hex.h" │ │ 2021-12-29 09:18:56 │ 8112a712336 │ -1 │ 6 │ 5 │ avogar │ #include │ │ 2022-04-21 20:19:13 │ 9133e398b8c │ 1 │ 11 │ 12 │ Nikolai Kochetov │ #include │ └─────────────────────┴─────────────┴──────┴─────────────────┴─────────────────┴──────────────────┴───────────────────────────────────────────────────────┘ 10 rows in set. Elapsed: 0.258 sec. Processed 7.54 million rows, 654.92 MB (29.24 million rows/s., 2.54 GB/s.) ``` リネームを考慮したファイルの[行ごとのコミット履歴](#行ごとのコミット履歴)を見つけるよりも複雑なクエリもあります。 ## 現在のアクティブファイルを見つける これは、リポジトリ内の現在のファイルのみを考慮したい後の分析にとって重要です。このセットは、リネームまたは削除(および再追加/リネーム)されていないファイルとして推定します。 **dbms、libs、tests/testflows/ディレクトリ内のファイルに関して壊れたコミット履歴があったようです。したがって、これらも除外します。** [play](https://sql.clickhouse.com?query_id=2HNFWPCFWEEY92WTAPMA7W) ```sql SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)') ORDER BY path LIMIT 10 ┌─path────────────────────────────────────────────────────────────┐ │ tests/queries/0_stateless/01054_random_printable_ascii_ubsan.sh │ │ tests/queries/0_stateless/02247_read_bools_as_numbers_json.sh │ │ tests/performance/file_table_function.xml │ │ tests/queries/0_stateless/01902_self_aliases_in_columns.sql │ │ tests/queries/0_stateless/01070_h3_get_base_cell.reference │ │ src/Functions/ztest.cpp │ │ src/Interpreters/InterpreterShowTablesQuery.h │ │ src/Parsers/Kusto/ParserKQLStatement.h │ │ tests/queries/0_stateless/00938_dataset_test.sql │ │ src/Dictionaries/Embedded/GeodataProviders/Types.h │ └─────────────────────────────────────────────────────────────────┘ 10 rows in set. Elapsed: 0.085 sec. Processed 532.10 thousand rows, 8.68 MB (6.30 million rows/s., 102.64 MB/s.) ``` これにより、ファイルがリネームされた後に元の名前に再リネームされることが可能になります。まず、リネームの結果として削除されたファイルの`old_path`のリストを集約します。これを最後の操作と統合します。最後に、最終イベントが`Delete`ではないものにフィルタリングします。 [play](https://sql.clickhouse.com?query_id=1OXCKMOH2JVMSHD3NS2WW6) ```sql SELECT uniq(path) FROM ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)') ORDER BY path ) ┌─uniq(path)─┐ │ 18559 │ └────────────┘ 1 row in set. Elapsed: 0.089 sec. Processed 532.10 thousand rows, 8.68 MB (6.01 million rows/s., 97.99 MB/s.) ``` このパターンを`git list-files`に適用すると、18155件が報告されます。 ```bash git ls-files | grep -v -E 'generated\.cpp|^(contrib|docs?|website|libs/(libcityhash|liblz4|libdivide|libvectorclass|libdouble-conversion|libcpuid|libzstd|libfarmhash|libmetrohash|libpoco|libwidechar_width))/' | wc -l 18155 ``` **したがって、現行のソリューションは現在のファイルの推定値です** ここでの違いは、いくつかの要因に起因しています: - リネームはファイルの他の変更と同時に発生する可能性があります。これらは`file_changes`内で別のイベントとしてリストされますが、同じ時間で発生します。`argMax`関数はこれを区別する方法がなく、最初の値を選択します。挿入の自然な順序(正しい順序を知る唯一の手段)は、ユニオン全体で維持されないため、変更されたイベントが選択される可能性があります。例えば、`src/Functions/geometryFromColumn.h`ファイルは、`src/Functions/geometryConverters.h`にリネームされる前に複数の変更があります。現在のソリューションでは、最後の変更イベントが`Modify`として選ばれる可能性があるため、`src/Functions/geometryFromColumn.h`が保持されます。 [play](https://sql.clickhouse.com?query_id=SCXWMR9GBMJ9UNZYQXQBFA) ```sql SELECT change_type, path, old_path, time, commit_hash FROM git.file_changes WHERE (path = 'src/Functions/geometryFromColumn.h') OR (old_path = 'src/Functions/geometryFromColumn.h') ┌─change_type─┬─path───────────────────────────────┬─old_path───────────────────────────┬────────────────time─┬─commit_hash──────────────────────────────┐ │ Add │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 9376b676e9a9bb8911b872e1887da85a45f7479d │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 6d59be5ea4768034f6526f7f9813062e0c369f7b │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 33acc2aa5dc091a7cb948f78c558529789b2bad8 │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 78e0db268ceadc42f82bc63a77ee1a4da6002463 │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 14a891057d292a164c4179bfddaef45a74eaf83a │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ d0d6e6953c2a2af9fb2300921ff96b9362f22edb │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ fe8382521139a58c0ba277eb848e88894658db66 │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ 3be3d5cde8788165bc0558f1e2a22568311c3103 │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ afad9bf4d0a55ed52a3f55483bc0973456e10a56 │ │ Modify │ src/Functions/geometryFromColumn.h │ │ 2021-03-11 12:08:16 │ e3290ecc78ca3ea82b49ebcda22b5d3a4df154e6 │ │ Rename │ src/Functions/geometryConverters.h │ src/Functions/geometryFromColumn.h │ 2021-03-11 12:08:16 │ 125945769586baf6ffd15919b29565b1b2a63218 │ └─────────────┴────────────────────────────────────┴────────────────────────────────────┴─────────────────────┴──────────────────────────────────────────┘ 11 rows in set. Elapsed: 0.030 sec. Processed 266.05 thousand rows, 6.61 MB (8.89 million rows/s., 220.82 MB/s.) ``` - 壊れたコミット履歴 - 削除イベントの欠落。ソースと原因は未定です。 これらの違いは、私たちの分析に有意に影響を及ぼすべきではありません。**このクエリの改善版を歓迎します**。 ## 最も多く変更されたファイルをリストする 現在のファイルに制限し、変更数を削除と追加の合計として考えます。 [play](https://sql.clickhouse.com?query_id=MHXPSBNPTDMJYR3OYSXVR7) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, sum(lines_added) + sum(lines_deleted) AS modifications FROM git.file_changes WHERE (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path ORDER BY modifications DESC LIMIT 10 ┌─path───────────────────────────────────────────────────┬─modifications─┐ │ src/Storages/StorageReplicatedMergeTree.cpp │ 21871 │ │ src/Storages/MergeTree/MergeTreeData.cpp │ 17709 │ │ programs/client/Client.cpp │ 15882 │ │ src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp │ 14249 │ │ src/Interpreters/InterpreterSelectQuery.cpp │ 12636 │ │ src/Parsers/ExpressionListParsers.cpp │ 11794 │ │ src/Analyzer/QueryAnalysisPass.cpp │ 11760 │ │ src/Coordination/KeeperStorage.cpp │ 10225 │ │ src/Functions/FunctionsConversion.h │ 9247 │ │ src/Parsers/ExpressionElementParsers.cpp │ 8197 │ └────────────────────────────────────────────────────────┴───────────────┘ 10 rows in set. Elapsed: 0.134 sec. Processed 798.15 thousand rows, 16.46 MB (5.95 million rows/s., 122.62 MB/s.) ``` ## コミットは通常、週のどの日に発生するか? [play](https://sql.clickhouse.com?query_id=GED2STFSYJDRAA59H8RLIV) ```sql SELECT day_of_week, count() AS c FROM git.commits GROUP BY dayOfWeek(time) AS day_of_week ┌─day_of_week─┬─────c─┐ │ 1 │ 10575 │ │ 2 │ 10645 │ │ 3 │ 10748 │ │ 4 │ 10944 │ │ 5 │ 10090 │ │ 6 │ 4617 │ │ 7 │ 5166 │ └─────────────┴───────┘ 7 rows in set. Elapsed: 0.262 sec. Processed 62.78 thousand rows, 251.14 KB (239.73 thousand rows/s., 958.93 KB/s.) ``` 金曜日に生産性の低下が見られるのは理にかなっています。週末にコードをコミットしている人々を見るのは素晴らしいです!貢献者の皆さんに大感謝! ## サブディレクトリ/ファイルの履歴 - 行数、コミット数、寄稿者数の推移 フィルタリングされない場合、これは非常に大きなクエリ結果を生成します。したがって、以下の例ではファイルまたはサブディレクトリでフィルタリングできるようにします。ここでは、`toStartOfWeek`関数を使用して週ごとにグループ化します - 必要に応じて適応してください。 [play](https://sql.clickhouse.com?query_id=REZRXDVU7CAWT5WKNJSTNY) ```sql SELECT week, sum(lines_added) AS lines_added, sum(lines_deleted) AS lines_deleted, uniq(commit_hash) AS num_commits, uniq(author) AS authors FROM git.file_changes WHERE path LIKE 'src/Storages%' GROUP BY toStartOfWeek(time) AS week ORDER BY week ASC LIMIT 10 ┌───────week─┬─lines_added─┬─lines_deleted─┬─num_commits─┬─authors─┐ │ 2020-03-29 │ 49 │ 35 │ 4 │ 3 │ │ 2020-04-05 │ 940 │ 601 │ 55 │ 14 │ │ 2020-04-12 │ 1472 │ 607 │ 32 │ 11 │ │ 2020-04-19 │ 917 │ 841 │ 39 │ 12 │ │ 2020-04-26 │ 1067 │ 626 │ 36 │ 10 │ │ 2020-05-03 │ 514 │ 435 │ 27 │ 10 │ │ 2020-05-10 │ 2552 │ 537 │ 48 │ 12 │ │ 2020-05-17 │ 3585 │ 1913 │ 83 │ 9 │ │ 2020-05-24 │ 2851 │ 1812 │ 74 │ 18 │ │ 2020-05-31 │ 2771 │ 2077 │ 77 │ 16 │ └────────────┴─────────────┴───────────────┴─────────────┴─────────┘ 10 rows in set. Elapsed: 0.043 sec. Processed 266.05 thousand rows, 15.85 MB (6.12 million rows/s., 364.61 MB/s.) ``` このデータは視覚化に適しています。以下では Superset を使用します。 **追加された行と削除された行に関して:** ![](./images/superset-github-lines-added-deleted.png) **コミットと著者に関して:** ![](./images/superset-commits-authors.png) ## 最大著者数のファイルリスト 現在のファイルのみに制限します。 [play](https://sql.clickhouse.com?query_id=CYQFNQNK9TAMPU2OZ8KG5Y) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, uniq(author) AS num_authors FROM git.file_changes WHERE path IN (current_files) GROUP BY path ORDER BY num_authors DESC LIMIT 10 ┌─path────────────────────────────────────────┬─num_authors─┐ │ src/Core/Settings.h │ 127 │ │ CMakeLists.txt │ 96 │ │ .gitmodules │ 85 │ │ src/Storages/MergeTree/MergeTreeData.cpp │ 72 │ │ src/CMakeLists.txt │ 71 │ │ programs/server/Server.cpp │ 70 │ │ src/Interpreters/Context.cpp │ 64 │ │ src/Storages/StorageReplicatedMergeTree.cpp │ 63 │ │ src/Common/ErrorCodes.cpp │ 61 │ │ src/Interpreters/InterpreterSelectQuery.cpp │ 59 │ └─────────────────────────────────────────────┴─────────────┘ 10 rows in set. Elapsed: 0.239 sec. Processed 798.15 thousand rows, 14.13 MB (3.35 million rows/s., 59.22 MB/s.) ``` ## リポジトリ内の最古のコード行 現在のファイルのみに制限します。 [play](https://sql.clickhouse.com?query_id=VWPBPGRZVGTHOCQYWNQZNT) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT any(path) AS file_path, line, max(time) AS latest_change, any(file_change_type) FROM git.line_changes WHERE path IN (current_files) GROUP BY line ORDER BY latest_change ASC LIMIT 10 ┌─file_path───────────────────────────────────┬─line────────────────────────────────────────────────────────┬───────latest_change─┬─any(file_change_type)─┐ │ utils/compressor/test.sh │ ./compressor -d < compressor.snp > compressor2 │ 2011-06-17 22:19:39 │ Modify │ │ utils/compressor/test.sh │ ./compressor < compressor > compressor.snp │ 2011-06-17 22:19:39 │ Modify │ │ utils/compressor/test.sh │ ./compressor -d < compressor.qlz > compressor2 │ 2014-02-24 03:14:30 │ Add │ │ utils/compressor/test.sh │ ./compressor < compressor > compressor.qlz │ 2014-02-24 03:14:30 │ Add │ │ utils/config-processor/config-processor.cpp │ if (argc != 2) │ 2014-02-26 19:10:00 │ Add │ │ utils/config-processor/config-processor.cpp │ std::cerr << "std::exception: " << e.what() << std::endl; │ 2014-02-26 19:10:00 │ Add │ │ utils/config-processor/config-processor.cpp │ std::cerr << "Exception: " << e.displayText() << std::endl; │ 2014-02-26 19:10:00 │ Add │ │ utils/config-processor/config-processor.cpp │ Poco::XML::DOMWriter().writeNode(std::cout, document); │ 2014-02-26 19:10:00 │ Add │ │ utils/config-processor/config-processor.cpp │ std::cerr << "Some exception" << std::endl; │ 2014-02-26 19:10:00 │ Add │ │ utils/config-processor/config-processor.cpp │ std::cerr << "usage: " << argv[0] << " path" << std::endl; │ 2014-02-26 19:10:00 │ Add │ └─────────────────────────────────────────────┴─────────────────────────────────────────────────────────────┴─────────────────────┴───────────────────────┘ 10 rows in set. Elapsed: 1.101 sec. Processed 8.07 million rows, 905.86 MB (7.33 million rows/s., 823.13 MB/s.) ``` ## 最も古い履歴を持つファイル 現在のファイルのみに制限します。 [play](https://sql.clickhouse.com?query_id=VWPBPGRZVGTHOCQYWNQZNT) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT count() AS c, path, max(time) AS latest_change FROM git.file_changes WHERE path IN (current_files) GROUP BY path ORDER BY c DESC LIMIT 10 ┌───c─┬─path────────────────────────────────────────┬───────latest_change─┐ │ 790 │ src/Storages/StorageReplicatedMergeTree.cpp │ 2022-10-30 16:30:51 │ │ 788 │ src/Storages/MergeTree/MergeTreeData.cpp │ 2022-11-04 09:26:44 │ │ 752 │ src/Core/Settings.h │ 2022-10-25 11:35:25 │ │ 749 │ CMakeLists.txt │ 2022-10-05 21:00:49 │ │ 575 │ src/Interpreters/InterpreterSelectQuery.cpp │ 2022-11-01 10:20:10 │ │ 563 │ CHANGELOG.md │ 2022-10-27 08:19:50 │ │ 491 │ src/Interpreters/Context.cpp │ 2022-10-25 12:26:29 │ │ 437 │ programs/server/Server.cpp │ 2022-10-21 12:25:19 │ │ 375 │ programs/client/Client.cpp │ 2022-11-03 03:16:55 │ │ 350 │ src/CMakeLists.txt │ 2022-10-24 09:22:37 │ └─────┴─────────────────────────────────────────────┴─────────────────────┘ 10 rows in set. Elapsed: 0.124 sec. Processed 798.15 thousand rows, 14.71 MB (6.44 million rows/s., 118.61 MB/s.) ``` 私たちのコアデータ構造である Merge Tree は、当然のことながら常に進化しており、長い編集の歴史があります! ## ドキュメントとコードに関する寄稿者の分布 **データ収集中に、`docs/` フォルダ内の変更は非常に汚れたコミット履歴のためにフィルタリングされました。そのため、このクエリの結果は正確ではありません。** 特定の時期、例えばリリース日周辺に、私たちはより多くのドキュメントを記述していますか?`countIf` 関数を使用して単純な比率を計算し、`bar` 関数を使用して結果を視覚化できます。 [play](https://sql.clickhouse.com?query_id=BA4RZUXUHNQBH9YK7F2T9J) ```sql SELECT day, bar(docs_ratio * 1000, 0, 100, 100) AS bar FROM ( SELECT day, countIf(file_extension IN ('h', 'cpp', 'sql')) AS code, countIf(file_extension = 'md') AS docs, docs / (code + docs) AS docs_ratio FROM git.line_changes WHERE (sign = 1) AND (file_extension IN ('h', 'cpp', 'sql', 'md')) GROUP BY dayOfMonth(time) AS day ) ┌─day─┬─bar─────────────────────────────────────────────────────────────┐ │ 1 │ ███████████████████████████████████▍ │ │ 2 │ ███████████████████████▋ │ │ 3 │ ████████████████████████████████▋ │ │ 4 │ █████████████ │ │ 5 │ █████████████████████▎ │ │ 6 │ ████████ │ │ 7 │ ███▋ │ │ 8 │ ████████▌ │ │ 9 │ ██████████████▎ │ │ 10 │ █████████████████▏ │ │ 11 │ █████████████▎ │ │ 12 │ ███████████████████████████████████▋ │ │ 13 │ █████████████████████████████▎ │ │ 14 │ ██████▋ │ │ 15 │ █████████████████████████████████████████▊ │ │ 16 │ ██████████▎ │ │ 17 │ ██████████████████████████████████████▋ │ │ 18 │ █████████████████████████████████▌ │ │ 19 │ ███████████ │ │ 20 │ █████████████████████████████████▊ │ │ 21 │ █████ │ │ 22 │ ███████████████████████▋ │ │ 23 │ ███████████████████████████▌ │ │ 24 │ ███████▌ │ │ 25 │ ██████████████████████████████████▎ │ │ 26 │ ███████████▏ │ │ 27 │ ███████████████████████████████████████████████████████████████ │ │ 28 │ ████████████████████████████████████████████████████▏ │ │ 29 │ ███▌ │ │ 30 │ ████████████████████████████████████████▎ │ │ 31 │ █████████████████████████████████▏ │ └─────┴─────────────────────────────────────────────────────────────────┘ 31 rows in set. Elapsed: 0.043 sec. Processed 7.54 million rows, 40.53 MB (176.71 million rows/s., 950.40 MB/s.) ``` 月末近くに少し多いかもしれませんが、全体的には良好な均等分布を維持しています。再度、これはデータ挿入中のドキュメントフィルタリングによる信頼性が低いです。 ## 最も多様な影響を持つ著者 ここでの多様性は、著者が貢献したユニークなファイルの数とします。 [play](https://sql.clickhouse.com?query_id=MT8WBABUKYBYSBA78W5TML) ```sql SELECT author, uniq(path) AS num_files FROM git.file_changes WHERE (change_type IN ('Add', 'Modify')) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY author ORDER BY num_files DESC LIMIT 10 ┌─author─────────────┬─num_files─┐ │ Alexey Milovidov │ 8433 │ │ Nikolai Kochetov │ 3257 │ │ Vitaly Baranov │ 2316 │ │ Maksim Kita │ 2172 │ │ Azat Khuzhin │ 1988 │ │ alesapin │ 1818 │ │ Alexander Tokmakov │ 1751 │ │ Amos Bird │ 1641 │ │ Ivan │ 1629 │ │ alexey-milovidov │ 1581 │ └────────────────────┴───────────┘ 10 rows in set. Elapsed: 0.041 sec. Processed 266.05 thousand rows, 4.92 MB (6.56 million rows/s., 121.21 MB/s.) ``` 最近の作業において、最も多様なコミットを持つ人物を見てみましょう。日付で制限するのではなく、著者の最後の N 回のコミットに制限します(この場合、私たちは 3 を使用しましたが、自由に変更してください): [play](https://sql.clickhouse.com?query_id=4Q3D67FWRIVWTY8EIDDE5U) ```sql SELECT author, sum(num_files_commit) AS num_files FROM ( SELECT author, commit_hash, uniq(path) AS num_files_commit, max(time) AS commit_time FROM git.file_changes WHERE (change_type IN ('Add', 'Modify')) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY author, commit_hash ORDER BY author ASC, commit_time DESC LIMIT 3 BY author ) GROUP BY author ORDER BY num_files DESC LIMIT 10 ┌─author───────────────┬─num_files─┐ │ Mikhail │ 782 │ │ Li Yin │ 553 │ │ Roman Peshkurov │ 119 │ │ Vladimir Smirnov │ 88 │ │ f1yegor │ 65 │ │ maiha │ 54 │ │ Vitaliy Lyudvichenko │ 53 │ │ Pradeep Chhetri │ 40 │ │ Orivej Desh │ 38 │ │ liyang │ 36 │ └──────────────────────┴───────────┘ 10 rows in set. Elapsed: 0.106 sec. Processed 266.05 thousand rows, 21.04 MB (2.52 million rows/s., 198.93 MB/s.) ``` ## 著者のお気に入りファイル ここでは、創設者である [Alexey Milovidov](https://github.com/alexey-milovidov) を選択し、分析を現在のファイルに制限します。 [play](https://sql.clickhouse.com?query_id=OKGZBACRHVGCRAGCZAJKMF) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, count() AS c FROM git.file_changes WHERE (author = 'Alexey Milovidov') AND (path IN (current_files)) GROUP BY path ORDER BY c DESC LIMIT 10 ┌─path────────────────────────────────────────┬───c─┐ │ CMakeLists.txt │ 165 │ │ CHANGELOG.md │ 126 │ │ programs/server/Server.cpp │ 73 │ │ src/Storages/MergeTree/MergeTreeData.cpp │ 71 │ │ src/Storages/StorageReplicatedMergeTree.cpp │ 68 │ │ src/Core/Settings.h │ 65 │ │ programs/client/Client.cpp │ 57 │ │ programs/server/play.html │ 48 │ │ .gitmodules │ 47 │ │ programs/install/Install.cpp │ 37 │ └─────────────────────────────────────────────┴─────┘ 10 rows in set. Elapsed: 0.106 sec. Processed 798.15 thousand rows, 13.97 MB (7.51 million rows/s., 131.41 MB/s.) ``` これは理にかなっています。なぜなら、Alexey は変更ログの維持を担当しているからです。しかし、ファイルの基本名を使用してお気に入りのファイルを特定すると、リネームを考慮に入れ、コードの貢献に焦点を当てることができます。 [play](https://sql.clickhouse.com?query_id=P9PBDZGOSVTKXEXU73ZNAJ) ```sql SELECT base, count() AS c FROM git.file_changes WHERE (author = 'Alexey Milovidov') AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY basename(path) AS base ORDER BY c DESC LIMIT 10 ┌─base───────────────────────────┬───c─┐ │ StorageReplicatedMergeTree.cpp │ 393 │ │ InterpreterSelectQuery.cpp │ 299 │ │ Aggregator.cpp │ 297 │ │ Client.cpp │ 280 │ │ MergeTreeData.cpp │ 274 │ │ Server.cpp │ 264 │ │ ExpressionAnalyzer.cpp │ 259 │ │ StorageMergeTree.cpp │ 239 │ │ Settings.h │ 225 │ │ TCPHandler.cpp │ 205 │ └────────────────────────────────┴─────┘ 10 rows in set. Elapsed: 0.032 sec. Processed 266.05 thousand rows, 5.68 MB (8.22 million rows/s., 175.50 MB/s.) ``` これは彼の興味分野をより反映しているかもしれません。 ## 著者数が最も少ない最大ファイル これを行うには、まず最大ファイルを特定する必要があります。すべてのファイルを、履歴からのコミットによる完全なファイル再構成により推定することは非常に負担がかかります! 推定として、現在のファイルに制限し、行の追加を合計し、削除を差し引きます。次に、著者数に対する長さの比率を計算することができます。 [play](https://sql.clickhouse.com?query_id=PVSDOHZYUMRDDUZFEYJC7J) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, sum(lines_added) - sum(lines_deleted) AS num_lines, uniqExact(author) AS num_authors, num_lines / num_authors AS lines_author_ratio FROM git.file_changes WHERE path IN (current_files) GROUP BY path ORDER BY lines_author_ratio DESC LIMIT 10 ┌─path──────────────────────────────────────────────────────────────────┬─num_lines─┬─num_authors─┬─lines_author_ratio─┐ │ src/Common/ClassificationDictionaries/emotional_dictionary_rus.txt │ 148590 │ 1 │ 148590 │ │ src/Functions/ClassificationDictionaries/emotional_dictionary_rus.txt │ 55533 │ 1 │ 55533 │ │ src/Functions/ClassificationDictionaries/charset_freq.txt │ 35722 │ 1 │ 35722 │ │ src/Common/ClassificationDictionaries/charset_freq.txt │ 35722 │ 1 │ 35722 │ │ tests/integration/test_storage_meilisearch/movies.json │ 19549 │ 1 │ 19549 │ │ tests/queries/0_stateless/02364_multiSearch_function_family.reference │ 12874 │ 1 │ 12874 │ │ src/Functions/ClassificationDictionaries/programming_freq.txt │ 9434 │ 1 │ 9434 │ │ src/Common/ClassificationDictionaries/programming_freq.txt │ 9434 │ 1 │ 9434 │ │ tests/performance/explain_ast.xml │ 5911 │ 1 │ 5911 │ │ src/Analyzer/QueryAnalysisPass.cpp │ 5686 │ 1 │ 5686 │ └───────────────────────────────────────────────────────────────────────┴───────────┴─────────────┴────────────────────┘ 10 rows in set. Elapsed: 0.138 sec. Processed 798.15 thousand rows, 16.57 MB (5.79 million rows/s., 120.11 MB/s.) ``` テキスト辞書はあまり現実的ではないかもしれないので、ファイル拡張子フィルターを介してコードのみに制限しましょう! [play](https://sql.clickhouse.com?query_id=BZHGWUIZMPZZUHS5XRBK2M) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, sum(lines_added) - sum(lines_deleted) AS num_lines, uniqExact(author) AS num_authors, num_lines / num_authors AS lines_author_ratio FROM git.file_changes WHERE (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path ORDER BY lines_author_ratio DESC LIMIT 10 ┌─path──────────────────────────────────┬─num_lines─┬─num_authors─┬─lines_author_ratio─┐ │ src/Analyzer/QueryAnalysisPass.cpp │ 5686 │ 1 │ 5686 │ │ src/Analyzer/QueryTreeBuilder.cpp │ 880 │ 1 │ 880 │ │ src/Planner/Planner.cpp │ 873 │ 1 │ 873 │ │ src/Backups/RestorerFromBackup.cpp │ 869 │ 1 │ 869 │ │ utils/memcpy-bench/FastMemcpy.h │ 770 │ 1 │ 770 │ │ src/Planner/PlannerActionsVisitor.cpp │ 765 │ 1 │ 765 │ │ src/Functions/sphinxstemen.cpp │ 728 │ 1 │ 728 │ │ src/Planner/PlannerJoinTree.cpp │ 708 │ 1 │ 708 │ │ src/Planner/PlannerJoins.cpp │ 695 │ 1 │ 695 │ │ src/Analyzer/QueryNode.h │ 607 │ 1 │ 607 │ └───────────────────────────────────────┴───────────┴─────────────┴────────────────────┘ 10 rows in set. Elapsed: 0.140 sec. Processed 798.15 thousand rows, 16.84 MB (5.70 million rows/s., 120.32 MB/s.) ``` 若干の新しいバイアスがあるため、これは、最近のファイルにはコミットの機会が少ないです。1 年以上経過したファイルに制限したらどうなるのでしょうか? [play](https://sql.clickhouse.com?query_id=RMHHZEDHFUCBGRQVQA2732) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT min(time) AS min_date, path, sum(lines_added) - sum(lines_deleted) AS num_lines, uniqExact(author) AS num_authors, num_lines / num_authors AS lines_author_ratio FROM git.file_changes WHERE (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path HAVING min_date <= (now() - toIntervalYear(1)) ORDER BY lines_author_ratio DESC LIMIT 10 ┌────────────min_date─┬─path───────────────────────────────────────────────────────────┬─num_lines─┬─num_authors─┬─lines_author_ratio─┐ │ 2021-03-08 07:00:54 │ utils/memcpy-bench/FastMemcpy.h │ 770 │ 1 │ 770 │ │ 2021-05-04 13:47:34 │ src/Functions/sphinxstemen.cpp │ 728 │ 1 │ 728 │ │ 2021-03-14 16:52:51 │ utils/memcpy-bench/glibc/dwarf2.h │ 592 │ 1 │ 592 │ │ 2021-03-08 09:04:52 │ utils/memcpy-bench/FastMemcpy_Avx.h │ 496 │ 1 │ 496 │ │ 2020-10-19 01:10:50 │ tests/queries/0_stateless/01518_nullable_aggregate_states2.sql │ 411 │ 1 │ 411 │ │ 2020-11-24 14:53:34 │ programs/server/GRPCHandler.cpp │ 399 │ 1 │ 399 │ │ 2021-03-09 14:10:28 │ src/DataTypes/Serializations/SerializationSparse.cpp │ 363 │ 1 │ 363 │ │ 2021-08-20 15:06:57 │ src/Functions/vectorFunctions.cpp │ 1327 │ 4 │ 331.75 │ │ 2020-08-04 03:26:23 │ src/Interpreters/MySQL/CreateQueryConvertVisitor.cpp │ 311 │ 1 │ 311 │ │ 2020-11-06 15:45:13 │ src/Storages/Rocksdb/StorageEmbeddedRocksdb.cpp │ 611 │ 2 │ 305.5 │ └─────────────────────┴────────────────────────────────────────────────────────────────┴───────────┴─────────────┴────────────────────┘ 10 rows in set. Elapsed: 0.143 sec. Processed 798.15 thousand rows, 18.00 MB (5.58 million rows/s., 125.87 MB/s.) ``` ## コミットとコード行の時間別分布; 曜日別、著者別; 特定のサブディレクトリ用 これは、週の曜日ごとの追加された行と削除された行の数として解釈します。この場合、[Functions ディレクトリ](https://github.com/ClickHouse/ClickHouse/tree/master/src/Functions) に注目します。 [play](https://sql.clickhouse.com?query_id=PF3KEMYG5CVLJGCFYQEGB1) ```sql SELECT dayOfWeek, uniq(commit_hash) AS commits, sum(lines_added) AS lines_added, sum(lines_deleted) AS lines_deleted FROM git.file_changes WHERE path LIKE 'src/Functions%' GROUP BY toDayOfWeek(time) AS dayOfWeek ┌─dayOfWeek─┬─commits─┬─lines_added─┬─lines_deleted─┐ │ 1 │ 476 │ 24619 │ 15782 │ │ 2 │ 434 │ 18098 │ 9938 │ │ 3 │ 496 │ 26562 │ 20883 │ │ 4 │ 587 │ 65674 │ 18862 │ │ 5 │ 504 │ 85917 │ 14518 │ │ 6 │ 314 │ 13604 │ 10144 │ │ 7 │ 294 │ 11938 │ 6451 │ └───────────┴─────────┴─────────────┴───────────────┘ 7 rows in set. Elapsed: 0.034 sec. Processed 266.05 thousand rows, 14.66 MB (7.73 million rows/s., 425.56 MB/s.) ``` および、時間帯別に。 [play](https://sql.clickhouse.com?query_id=Q4VDVKEGHHRBCUJHNCVTF1) ```sql SELECT hourOfDay, uniq(commit_hash) AS commits, sum(lines_added) AS lines_added, sum(lines_deleted) AS lines_deleted FROM git.file_changes WHERE path LIKE 'src/Functions%' GROUP BY toHour(time) AS hourOfDay ┌─hourOfDay─┬─commits─┬─lines_added─┬─lines_deleted─┐ │ 0 │ 71 │ 4169 │ 3404 │ │ 1 │ 90 │ 2174 │ 1927 │ │ 2 │ 65 │ 2343 │ 1515 │ │ 3 │ 76 │ 2552 │ 493 │ │ 4 │ 62 │ 1480 │ 1304 │ │ 5 │ 38 │ 1644 │ 253 │ │ 6 │ 104 │ 4434 │ 2979 │ │ 7 │ 117 │ 4171 │ 1678 │ │ 8 │ 106 │ 4604 │ 4673 │ │ 9 │ 135 │ 60550 │ 2678 │ │ 10 │ 149 │ 6133 │ 3482 │ │ 11 │ 182 │ 8040 │ 3833 │ │ 12 │ 209 │ 29428 │ 15040 │ │ 13 │ 187 │ 10204 │ 5491 │ │ 14 │ 204 │ 9028 │ 6060 │ │ 15 │ 231 │ 15179 │ 10077 │ │ 16 │ 196 │ 9568 │ 5925 │ │ 17 │ 138 │ 4941 │ 3849 │ │ 18 │ 123 │ 4193 │ 3036 │ │ 19 │ 165 │ 8817 │ 6646 │ │ 20 │ 140 │ 3749 │ 2379 │ │ 21 │ 132 │ 41585 │ 4182 │ │ 22 │ 85 │ 4094 │ 3955 │ │ 23 │ 100 │ 3332 │ 1719 │ └───────────┴─────────┴─────────────┴───────────────┘ 24 rows in set. Elapsed: 0.039 sec. Processed 266.05 thousand rows, 14.66 MB (6.77 million rows/s., 372.89 MB/s.) ``` この分布は、私たちの開発チームの大部分がアムステルダムにいることを考慮すると理にかなっています。`bar` 関数は、これらの分布を視覚化するのに役立ちます。 [play](https://sql.clickhouse.com?query_id=9AZ8CENV8N91YGW7T6IB68) ```sql SELECT hourOfDay, bar(commits, 0, 400, 50) AS commits, bar(lines_added, 0, 30000, 50) AS lines_added, bar(lines_deleted, 0, 15000, 50) AS lines_deleted FROM ( SELECT hourOfDay, uniq(commit_hash) AS commits, sum(lines_added) AS lines_added, sum(lines_deleted) AS lines_deleted FROM git.file_changes WHERE path LIKE 'src/Functions%' GROUP BY toHour(time) AS hourOfDay ) ┌─hourOfDay─┬─commits───────────────────────┬─lines_added────────────────────────────────────────┬─lines_deleted──────────────────────────────────────┐ │ 0 │ ████████▊ │ ██████▊ │ ███████████▎ │ │ 1 │ ███████████▎ │ ███▌ │ ██████▍ │ │ 2 │ ████████ │ ███▊ │ █████ │ │ 3 │ █████████▌ │ ████▎ │ █▋ │ │ 4 │ ███████▋ │ ██▍ │ ████▎ │ │ 5 │ ████▋ │ ██▋ │ ▋ │ │ 6 │ █████████████ │ ███████▍ │ █████████▊ │ │ 7 │ ██████████████▋ │ ██████▊ │ █████▌ │ │ 8 │ █████████████▎ │ ███████▋ │ ███████████████▌ │ │ 9 │ ████████████████▊ │ ██████████████████████████████████████████████████ │ ████████▊ │ │ 10 │ ██████████████████▋ │ ██████████▏ │ ███████████▌ │ │ 11 │ ██████████████████████▋ │ █████████████▍ │ ████████████▋ │ │ 12 │ ██████████████████████████ │ █████████████████████████████████████████████████ │ ██████████████████████████████████████████████████ │ │ 13 │ ███████████████████████▍ │ █████████████████ │ ██████████████████▎ │ │ 14 │ █████████████████████████▌ │ ███████████████ │ ████████████████████▏ │ │ 15 │ ████████████████████████████▊ │ █████████████████████████▎ │ █████████████████████████████████▌ │ │ 16 │ ████████████████████████▌ │ ███████████████▊ │ ███████████████████▋ │ │ 17 │ █████████████████▎ │ ████████▏ │ ████████████▋ │ │ 18 │ ███████████████▍ │ ██████▊ │ ██████████ │ │ 19 │ ████████████████████▋ │ ██████████████▋ │ ██████████████████████▏ │ │ 20 │ █████████████████▌ │ ██████▏ │ ███████▊ │ │ 21 │ ████████████████▌ │ ██████████████████████████████████████████████████ │ █████████████▊ │ │ 22 │ ██████████▋ │ ██████▋ │ █████████████▏ │ │ 23 │ ████████████▌ │ █████▌ │ █████▋ │ └───────────┴───────────────────────────────┴────────────────────────────────────────────────────┴────────────────────────────────────────────────────┘ 24 rows in set. Elapsed: 0.038 sec. Processed 266.05 thousand rows, 14.66 MB (7.09 million rows/s., 390.69 MB/s.) ``` ## 著者の行列:他の著者のコードを書き直す傾向を示す `sign = -1` はコード削除を示しています。句読点や空行の挿入は除外します。 [プレイ](https://sql.clickhouse.com?query_id=448O8GWAHY3EM6ZZ7AGLAM) ```sql SELECT prev_author || '(a)' as add_author, author || '(d)' as delete_author, count() AS c FROM git.line_changes WHERE (sign = -1) AND (file_extension IN ('h', 'cpp')) AND (line_type NOT IN ('Punct', 'Empty')) AND (author != prev_author) AND (prev_author != '') GROUP BY prev_author, author ORDER BY c DESC LIMIT 1 BY prev_author LIMIT 100 ┌─prev_author──────────┬─author───────────┬─────c─┐ │ Ivan │ Alexey Milovidov │ 18554 │ │ Alexey Arno │ Alexey Milovidov │ 18475 │ │ Michael Kolupaev │ Alexey Milovidov │ 14135 │ │ Alexey Milovidov │ Nikolai Kochetov │ 13435 │ │ Andrey Mironov │ Alexey Milovidov │ 10418 │ │ proller │ Alexey Milovidov │ 7280 │ │ Nikolai Kochetov │ Alexey Milovidov │ 6806 │ │ alexey-milovidov │ Alexey Milovidov │ 5027 │ │ Vitaliy Lyudvichenko │ Alexey Milovidov │ 4390 │ │ Amos Bird │ Ivan Lezhankin │ 3125 │ │ f1yegor │ Alexey Milovidov │ 3119 │ │ Pavel Kartavyy │ Alexey Milovidov │ 3087 │ │ Alexey Zatelepin │ Alexey Milovidov │ 2978 │ │ alesapin │ Alexey Milovidov │ 2949 │ │ Sergey Fedorov │ Alexey Milovidov │ 2727 │ │ Ivan Lezhankin │ Alexey Milovidov │ 2618 │ │ Vasily Nemkov │ Alexey Milovidov │ 2547 │ │ Alexander Tokmakov │ Alexey Milovidov │ 2493 │ │ Nikita Vasilev │ Maksim Kita │ 2420 │ │ Anton Popov │ Amos Bird │ 2127 │ └──────────────────────┴──────────────────┴───────┘ 20 rows in set. Elapsed: 0.098 sec. Processed 7.54 million rows, 42.16 MB (76.67 million rows/s., 428.99 MB/s.) ``` Sankeyチャート(SuperSet)は、これをうまく視覚化できます。視覚的多様性を高めるために、各著者の上位3つのコード削除者を取得するために`LIMIT BY`を3に増やします。 ![](./images/superset-authors-matrix.png) Alexeyは明らかに他の人のコードを削除するのが好きです。よりバランスの取れたコード削除のビューを得るために、彼を除外しましょう。 ![](./images/superset-authors-matrix_v2.png) ## 曜日ごとの最高貢献者は誰ですか? コミット数を単純に考えると: [プレイ](https://sql.clickhouse.com?query_id=WXPKFJCAHOKYKEVTWNFVCY) ```sql SELECT day_of_week, author, count() AS c FROM git.commits GROUP BY dayOfWeek(time) AS day_of_week, author ORDER BY day_of_week ASC, c DESC LIMIT 1 BY day_of_week ┌─day_of_week─┬─author───────────┬────c─┐ │ 1 │ Alexey Milovidov │ 2204 │ │ 2 │ Alexey Milovidov │ 1588 │ │ 3 │ Alexey Milovidov │ 1725 │ │ 4 │ Alexey Milovidov │ 1915 │ │ 5 │ Alexey Milovidov │ 1940 │ │ 6 │ Alexey Milovidov │ 1851 │ │ 7 │ Alexey Milovidov │ 2400 │ └─────────────┴──────────────────┴──────┘ 7 rows in set. Elapsed: 0.012 sec. Processed 62.78 thousand rows, 395.47 KB (5.44 million rows/s., 34.27 MB/s.) ``` ここでは、最も長い貢献者である創業者のAlexeyにいくつかの利点があります。過去1年に分析を制限しましょう。 [プレイ](https://sql.clickhouse.com?query_id=8YRJGHFTNJAWJ96XCJKKEH) ```sql SELECT day_of_week, author, count() AS c FROM git.commits WHERE time > (now() - toIntervalYear(1)) GROUP BY dayOfWeek(time) AS day_of_week, author ORDER BY day_of_week ASC, c DESC LIMIT 1 BY day_of_week ┌─day_of_week─┬─author───────────┬───c─┐ │ 1 │ Alexey Milovidov │ 198 │ │ 2 │ alesapin │ 162 │ │ 3 │ alesapin │ 163 │ │ 4 │ Azat Khuzhin │ 166 │ │ 5 │ alesapin │ 191 │ │ 6 │ Alexey Milovidov │ 179 │ │ 7 │ Alexey Milovidov │ 243 │ └─────────────┴──────────────────┴─────┘ 7 rows in set. Elapsed: 0.004 sec. Processed 21.82 thousand rows, 140.02 KB (4.88 million rows/s., 31.29 MB/s.) ``` これはまだ少し単純で、人々の作業を反映していません。 より良い指標は、過去1年の総作業に対する各日の最高貢献者の割合かもしれません。削除と追加のコードを同等に扱います。 [プレイ](https://sql.clickhouse.com?query_id=VQF4KMRDSUEXGS1JFVDJHV) ```sql SELECT top_author.day_of_week, top_author.author, top_author.author_work / all_work.total_work AS top_author_percent FROM ( SELECT day_of_week, author, sum(lines_added) + sum(lines_deleted) AS author_work FROM git.file_changes WHERE time > (now() - toIntervalYear(1)) GROUP BY author, dayOfWeek(time) AS day_of_week ORDER BY day_of_week ASC, author_work DESC LIMIT 1 BY day_of_week ) AS top_author INNER JOIN ( SELECT day_of_week, sum(lines_added) + sum(lines_deleted) AS total_work FROM git.file_changes WHERE time > (now() - toIntervalYear(1)) GROUP BY dayOfWeek(time) AS day_of_week ) AS all_work USING (day_of_week) ┌─day_of_week─┬─author──────────────┬──top_author_percent─┐ │ 1 │ Alexey Milovidov │ 0.3168282877768332 │ │ 2 │ Mikhail f. Shiryaev │ 0.3523434231193969 │ │ 3 │ vdimir │ 0.11859742484577324 │ │ 4 │ Nikolay Degterinsky │ 0.34577318920318467 │ │ 5 │ Alexey Milovidov │ 0.13208704423684223 │ │ 6 │ Alexey Milovidov │ 0.18895257783624633 │ │ 7 │ Robert Schulze │ 0.3617405888930302 │ └─────────────┴─────────────────────┴─────────────────────┘ 7 rows in set. Elapsed: 0.014 sec. Processed 106.12 thousand rows, 1.38 MB (7.61 million rows/s., 98.65 MB/s.) ``` ## リポジトリ全体のコード年齢の分布 分析を現在のファイルに制限します。簡潔さのために、結果を深さ2のルートフォルダーごとに5ファイルに制限します。必要に応じて調整してください。 [プレイ](https://sql.clickhouse.com?query_id=6YWAUQYPZINZDJGBEZBNWG) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT concat(root, '/', sub_folder) AS folder, round(avg(days_present)) AS avg_age_of_files, min(days_present) AS min_age_files, max(days_present) AS max_age_files, count() AS c FROM ( SELECT path, dateDiff('day', min(time), toDate('2022-11-03')) AS days_present FROM git.file_changes WHERE (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path ) GROUP BY splitByChar('/', path)[1] AS root, splitByChar('/', path)[2] AS sub_folder ORDER BY root ASC, c DESC LIMIT 5 BY root ┌─folder───────────────────────────┬─avg_age_of_files─┬─min_age_files─┬─max_age_files─┬────c─┐ │ base/base │ 387 │ 201 │ 397 │ 84 │ │ base/glibc-compatibility │ 887 │ 59 │ 993 │ 19 │ │ base/consistent-hashing │ 993 │ 993 │ 993 │ 5 │ │ base/widechar_width │ 993 │ 993 │ 993 │ 2 │ │ base/consistent-hashing-sumbur │ 993 │ 993 │ 993 │ 2 │ │ docker/test │ 1043 │ 1043 │ 1043 │ 1 │ │ programs/odbc-bridge │ 835 │ 91 │ 945 │ 25 │ │ programs/copier │ 587 │ 14 │ 945 │ 22 │ │ programs/library-bridge │ 155 │ 47 │ 608 │ 21 │ │ programs/disks │ 144 │ 62 │ 150 │ 14 │ │ programs/server │ 874 │ 709 │ 945 │ 10 │ │ rust/BLAKE3 │ 52 │ 52 │ 52 │ 1 │ │ src/Functions │ 752 │ 0 │ 944 │ 809 │ │ src/Storages │ 700 │ 8 │ 944 │ 736 │ │ src/Interpreters │ 684 │ 3 │ 944 │ 490 │ │ src/Processors │ 703 │ 44 │ 944 │ 482 │ │ src/Common │ 673 │ 7 │ 944 │ 473 │ │ tests/queries │ 674 │ -5 │ 945 │ 3777 │ │ tests/integration │ 656 │ 132 │ 945 │ 4 │ │ utils/memcpy-bench │ 601 │ 599 │ 605 │ 10 │ │ utils/keeper-bench │ 570 │ 569 │ 570 │ 7 │ │ utils/durability-test │ 793 │ 793 │ 793 │ 4 │ │ utils/self-extracting-executable │ 143 │ 143 │ 143 │ 3 │ │ utils/self-extr-exec │ 224 │ 224 │ 224 │ 2 │ └──────────────────────────────────┴──────────────────┴───────────────┴───────────────┴──────┘ 24 rows in set. Elapsed: 0.129 sec. Processed 798.15 thousand rows, 15.11 MB (6.19 million rows/s., 117.08 MB/s.) ``` ## 各著者のコードの何パーセントが他の著者によって削除されたか? この質問を解決するには、著者によって書かれた行数を他の貢献者によって削除された総行数で割る必要があります。 [プレイ](https://sql.clickhouse.com?query_id=T4DTWTB36WFSEYAZLMGRNF) ```sql SELECT k, written_code.c, removed_code.c, removed_code.c / written_code.c AS remove_ratio FROM ( SELECT author AS k, count() AS c FROM git.line_changes WHERE (sign = 1) AND (file_extension IN ('h', 'cpp')) AND (line_type NOT IN ('Punct', 'Empty')) GROUP BY k ) AS written_code INNER JOIN ( SELECT prev_author AS k, count() AS c FROM git.line_changes WHERE (sign = -1) AND (file_extension IN ('h', 'cpp')) AND (line_type NOT IN ('Punct', 'Empty')) AND (author != prev_author) GROUP BY k ) AS removed_code USING (k) WHERE written_code.c > 1000 ORDER BY remove_ratio DESC LIMIT 10 ┌─k──────────────────┬─────c─┬─removed_code.c─┬───────remove_ratio─┐ │ Marek Vavruša │ 1458 │ 1318 │ 0.9039780521262003 │ │ Ivan │ 32715 │ 27500 │ 0.8405930001528351 │ │ artpaul │ 3450 │ 2840 │ 0.8231884057971014 │ │ Silviu Caragea │ 1542 │ 1209 │ 0.7840466926070039 │ │ Ruslan │ 1027 │ 802 │ 0.7809152872444012 │ │ Tsarkova Anastasia │ 1755 │ 1364 │ 0.7772079772079772 │ │ Vyacheslav Alipov │ 3526 │ 2727 │ 0.7733976176971072 │ │ Marek Vavruša │ 1467 │ 1124 │ 0.7661895023858214 │ │ f1yegor │ 7194 │ 5213 │ 0.7246316374756742 │ │ kreuzerkrieg │ 3406 │ 2468 │ 0.724603640634175 │ └────────────────────┴───────┴────────────────┴────────────────────┘ 10 rows in set. Elapsed: 0.126 sec. Processed 15.07 million rows, 73.51 MB (119.97 million rows/s., 585.16 MB/s.) ``` ## 最も多く書き直されたファイルのリスト? この質問に対する最も単純なアプローチは、パスごとの行修正数を単純にカウントすることかもしれません(現行ファイルに制限): ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ) SELECT path, count() AS c FROM git.line_changes WHERE (file_extension IN ('h', 'cpp', 'sql')) AND (path IN (current_files)) GROUP BY path ORDER BY c DESC LIMIT 10 ┌─path───────────────────────────────────────────────────┬─────c─┐ │ src/Storages/StorageReplicatedMergeTree.cpp │ 21871 │ │ src/Storages/MergeTree/MergeTreeData.cpp │ 17709 │ │ programs/client/Client.cpp │ 15882 │ │ src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp │ 14249 │ │ src/Interpreters/InterpreterSelectQuery.cpp │ 12636 │ │ src/Parsers/ExpressionListParsers.cpp │ 11794 │ │ src/Analyzer/QueryAnalysisPass.cpp │ 11760 │ │ src/Coordination/KeeperStorage.cpp │ 10225 │ │ src/Functions/FunctionsConversion.h │ 9247 │ │ src/Parsers/ExpressionElementParsers.cpp │ 8197 │ └────────────────────────────────────────────────────────┴───────┘ 10 rows in set. Elapsed: 0.160 sec. Processed 8.07 million rows, 98.99 MB (50.49 million rows/s., 619.49 MB/s.) ``` これは「書き直し」という概念を捉えていませんが、コミット内の大部分のファイルが変更された場合に求めます。これは、より複雑なクエリを必要とします。50%以上が削除され、50%以上が追加された場合を書き直しと見なすとしましょう。このクエリは現在のファイルのみに制限されています。我々は、`path`と`commit_hash`をグループ化することによってすべてのファイル変更をリストし、追加された行と削除された行の数を返します。ウィンドウ関数を使用して、ある瞬間のファイルの累積サイズを推定し、変更がファイルサイズに与える影響を`追加行 - 削除行`として推定します。この統計を使用して、各変更の追加されたまたは削除されたファイルの割合を計算できます。最後に、書き直しを構成するファイル変更の数をカウントします。すなわち、`(percent_add >= 0.5) AND (percent_delete >= 0.5) AND current_size > 50`。ファイルが90行未満の場合はそれを除外し、早期の寄稿が書き直しとしてカウントされるのを避けます。これにより非常に小さなファイルへのバイアスを避けることができます。 [プレイ](https://sql.clickhouse.com?query_id=5PL1QLNSH6QQTR8H9HINNP) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ), changes AS ( SELECT path, max(time) AS max_time, commit_hash, any(lines_added) AS num_added, any(lines_deleted) AS num_deleted, any(change_type) AS type FROM git.file_changes WHERE (change_type IN ('Add', 'Modify')) AND (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path, commit_hash ORDER BY path ASC, max_time ASC ), rewrites AS ( SELECT path, commit_hash, max_time, type, num_added, num_deleted, sum(num_added - num_deleted) OVER (PARTITION BY path ORDER BY max_time ASC) AS current_size, if(current_size > 0, num_added / current_size, 0) AS percent_add, if(current_size > 0, num_deleted / current_size, 0) AS percent_delete FROM changes ) SELECT path, count() AS num_rewrites FROM rewrites WHERE (type = 'Modify') AND (percent_add >= 0.5) AND (percent_delete >= 0.5) AND (current_size > 50) GROUP BY path ORDER BY num_rewrites DESC LIMIT 10 ┌─path──────────────────────────────────────────────────┬─num_rewrites─┐ │ src/Storages/WindowView/StorageWindowView.cpp │ 8 │ │ src/Functions/array/arrayIndex.h │ 7 │ │ src/Dictionaries/CacheDictionary.cpp │ 6 │ │ src/Dictionaries/RangeHashedDictionary.cpp │ 5 │ │ programs/client/Client.cpp │ 4 │ │ src/Functions/polygonPerimeter.cpp │ 4 │ │ src/Functions/polygonsEquals.cpp │ 4 │ │ src/Functions/polygonsWithin.cpp │ 4 │ │ src/Processors/Formats/Impl/ArrowColumnToCHColumn.cpp │ 4 │ │ src/Functions/polygonsSymDifference.cpp │ 4 │ └───────────────────────────────────────────────────────┴──────────────┘ 10 rows in set. Elapsed: 0.299 sec. Processed 798.15 thousand rows, 31.52 MB (2.67 million rows/s., 105.29 MB/s.) ``` ## コードがリポジトリに留まる可能性が最も高い曜日は? このためには、コードの行を一意に特定する必要があります。同じ行がファイル内に複数回表示される可能性があるため、パスと行の内容を使用して推定します。 追加された行に関するクエリを作成し、削除された行と結合し、後者が前者よりも最近発生したケースをフィルタリングします。これにより、削除された行を取得し、これらの二つのイベント間の時間を計算できます。 最後に、このデータセットを集約して、曜日ごとのリポジトリの平均保持日数を計算します。 [プレイ](https://sql.clickhouse.com?query_id=GVF23LEZTNZI22BT8LZBBE) ```sql SELECT day_of_week_added, count() AS num, avg(days_present) AS avg_days_present FROM ( SELECT added_code.line, added_code.time AS added_day, dateDiff('day', added_code.time, removed_code.time) AS days_present FROM ( SELECT path, line, max(time) AS time FROM git.line_changes WHERE (sign = 1) AND (line_type NOT IN ('Punct', 'Empty')) GROUP BY path, line ) AS added_code INNER JOIN ( SELECT path, line, max(time) AS time FROM git.line_changes WHERE (sign = -1) AND (line_type NOT IN ('Punct', 'Empty')) GROUP BY path, line ) AS removed_code USING (path, line) WHERE removed_code.time > added_code.time ) GROUP BY dayOfWeek(added_day) AS day_of_week_added ┌─day_of_week_added─┬────num─┬───avg_days_present─┐ │ 1 │ 171879 │ 193.81759260875384 │ │ 2 │ 141448 │ 153.0931013517335 │ │ 3 │ 161230 │ 137.61553681076722 │ │ 4 │ 255728 │ 121.14149799787273 │ │ 5 │ 203907 │ 141.60181847606998 │ │ 6 │ 62305 │ 202.43449161383518 │ │ 7 │ 70904 │ 220.0266134491707 │ └───────────────────┴────────┴────────────────────┘ 7 rows in set. Elapsed: 3.965 sec. Processed 15.07 million rows, 1.92 GB (3.80 million rows/s., 483.50 MB/s.) ``` ## 平均コード年齢でソートされたファイル このクエリは、[コードがリポジトリに留まる可能性が最も高い曜日は?](#コードがリポジトリに留まる可能性が最も高い曜日は) と同じ原則を使用します - パスと行の内容を使用して、行のコードを一意に特定します。これにより、ラインが追加されてから削除されるまでの時間を特定できます。ただし、現在のファイルとコードのみにフィルタリングし、各ファイルの行にわたって平均化します。 [プレイ](https://sql.clickhouse.com?query_id=3CYYT7HEHWRFHVCM9JCKSU) ```sql WITH current_files AS ( SELECT path FROM ( SELECT old_path AS path, max(time) AS last_time, 2 AS change_type FROM git.file_changes GROUP BY old_path UNION ALL SELECT path, max(time) AS last_time, argMax(change_type, time) AS change_type FROM git.file_changes GROUP BY path ) GROUP BY path HAVING (argMax(change_type, last_time) != 2) AND (NOT match(path, '(^dbms/)|(^libs/)|(^tests/testflows/)|(^programs/server/store/)')) ORDER BY path ASC ), lines_removed AS ( SELECT added_code.path AS path, added_code.line, added_code.time AS added_day, dateDiff('day', added_code.time, removed_code.time) AS days_present FROM ( SELECT path, line, max(time) AS time, any(file_extension) AS file_extension FROM git.line_changes WHERE (sign = 1) AND (line_type NOT IN ('Punct', 'Empty')) GROUP BY path, line ) AS added_code INNER JOIN ( SELECT path, line, max(time) AS time FROM git.line_changes WHERE (sign = -1) AND (line_type NOT IN ('Punct', 'Empty')) GROUP BY path, line ) AS removed_code USING (path, line) WHERE (removed_code.time > added_code.time) AND (path IN (current_files)) AND (file_extension IN ('h', 'cpp', 'sql')) ) SELECT path, avg(days_present) AS avg_code_age FROM lines_removed GROUP BY path ORDER BY avg_code_age DESC LIMIT 10 ┌─path────────────────────────────────────────────────────────────┬──────avg_code_age─┐ │ utils/corrector_utf8/corrector_utf8.cpp │ 1353.888888888889 │ │ tests/queries/0_stateless/01288_shard_max_network_bandwidth.sql │ 881 │ │ src/Functions/replaceRegexpOne.cpp │ 861 │ │ src/Functions/replaceRegexpAll.cpp │ 861 │ │ src/Functions/replaceOne.cpp │ 861 │ │ utils/zookeeper-remove-by-list/main.cpp │ 838.25 │ │ tests/queries/0_stateless/01356_state_resample.sql │ 819 │ │ tests/queries/0_stateless/01293_create_role.sql │ 819 │ │ src/Functions/ReplaceStringImpl.h │ 810 │ │ src/Interpreters/createBlockSelector.cpp │ 795 │ └─────────────────────────────────────────────────────────────────┴───────────────────┘ 10 rows in set. Elapsed: 3.134 sec. Processed 16.13 million rows, 1.83 GB (5.15 million rows/s., 582.99 MB/s.) ``` ## 誰がより多くのテスト/CPPコード/コメントを書く傾向があるのか? この質問にアプローチする方法はいくつかあります。テスト対コードの比率に焦点を当て、このクエリは比較的簡単です - `tests`を含むフォルダへの寄与をカウントし、総寄与に対する比率を計算します。 ただし、20回以上の変更を行ったユーザーに制限して、定期的なコミッターに焦点を当て、一回限りの寄与へのバイアスを避けます。 [プレイ](https://sql.clickhouse.com?query_id=JGKZSEQDPDTDKZXD3ZCGLE) ```sql SELECT author, countIf((file_extension IN ('h', 'cpp', 'sql', 'sh', 'py', 'expect')) AND (path LIKE '%tests%')) AS test, countIf((file_extension IN ('h', 'cpp', 'sql')) AND (NOT (path LIKE '%tests%'))) AS code, code / (code + test) AS ratio_code FROM git.file_changes GROUP BY author HAVING code > 20 ORDER BY code DESC LIMIT 20 ┌─author───────────────┬─test─┬──code─┬─────────ratio_code─┐ │ Alexey Milovidov │ 6617 │ 41799 │ 0.8633303040317251 │ │ Nikolai Kochetov │ 916 │ 13361 │ 0.9358408629263851 │ │ alesapin │ 2408 │ 8796 │ 0.785076758300607 │ │ kssenii │ 869 │ 6769 │ 0.8862267609321812 │ │ Maksim Kita │ 799 │ 5862 │ 0.8800480408347096 │ │ Alexander Tokmakov │ 1472 │ 5727 │ 0.7955271565495208 │ │ Vitaly Baranov │ 1764 │ 5521 │ 0.7578586135895676 │ │ Ivan Lezhankin │ 843 │ 4698 │ 0.8478613968597726 │ │ Anton Popov │ 599 │ 4346 │ 0.8788675429726996 │ │ Ivan │ 2630 │ 4269 │ 0.6187853312074214 │ │ Azat Khuzhin │ 1664 │ 3697 │ 0.689610147360567 │ │ Amos Bird │ 400 │ 2901 │ 0.8788245986064829 │ │ proller │ 1207 │ 2377 │ 0.6632254464285714 │ │ chertus │ 453 │ 2359 │ 0.8389046941678521 │ │ alexey-milovidov │ 303 │ 2321 │ 0.8845274390243902 │ │ Alexey Arno │ 169 │ 2310 │ 0.9318273497377975 │ │ Vitaliy Lyudvichenko │ 334 │ 2283 │ 0.8723729461215132 │ │ Robert Schulze │ 182 │ 2196 │ 0.9234650967199327 │ │ CurtizJ │ 460 │ 2158 │ 0.8242933537051184 │ │ Alexander Kuzmenkov │ 298 │ 2092 │ 0.8753138075313808 │ └──────────────────────┴──────┴───────┴────────────────────┘ 20 rows in set. Elapsed: 0.034 sec. Processed 266.05 thousand rows, 4.65 MB (7.93 million rows/s., 138.76 MB/s.) ``` この分布をヒストグラムとしてプロットできます。 [プレイ](https://sql.clickhouse.com?query_id=S5AJIIRGSUAY1JXEVHQDAK) ```sql WITH ( SELECT histogram(10)(ratio_code) AS hist FROM ( SELECT author, countIf((file_extension IN ('h', 'cpp', 'sql', 'sh', 'py', 'expect')) AND (path LIKE '%tests%')) AS test, countIf((file_extension IN ('h', 'cpp', 'sql')) AND (NOT (path LIKE '%tests%'))) AS code, code / (code + test) AS ratio_code FROM git.file_changes GROUP BY author HAVING code > 20 ORDER BY code DESC LIMIT 20 ) ) AS hist SELECT arrayJoin(hist).1 AS lower, arrayJoin(hist).2 AS upper, bar(arrayJoin(hist).3, 0, 100, 500) AS bar ┌──────────────lower─┬──────────────upper─┬─bar───────────────────────────┐ │ 0.6187853312074214 │ 0.6410053888179964 │ █████ │ │ 0.6410053888179964 │ 0.6764177968945693 │ █████ │ │ 0.6764177968945693 │ 0.7237343804750673 │ █████ │ │ 0.7237343804750673 │ 0.7740802855073157 │ █████▋ │ │ 0.7740802855073157 │ 0.807297655565091 │ ████████▋ │ │ 0.807297655565091 │ 0.8338381996094653 │ ██████▎ │ │ 0.8338381996094653 │ 0.8533566747727687 │ ████████▋ │ │ 0.8533566747727687 │ 0.871392376017531 │ █████████▍ │ │ 0.871392376017531 │ 0.904916108899021 │ ████████████████████████████▋ │ │ 0.904916108899021 │ 0.9358408629263851 │ █████████████████▌ │ └────────────────────┴────────────────────┴───────────────────────────────┘ 10 rows in set. Elapsed: 0.051 sec. Processed 266.05 thousand rows, 4.65 MB (5.24 million rows/s., 91.64 MB/s.) ``` ほとんどの寄稿者は、予想通り、テストよりもコードを多く書きます。 コードを寄稿する際に、誰が最も多くのコメントを追加するのでしょうか? [プレイ](https://sql.clickhouse.com?query_id=EXPHDIURBTOXXOK1TGNNYD) ```sql SELECT author, avg(ratio_comments) AS avg_ratio_comments, sum(code) AS code FROM ( SELECT author, commit_hash, countIf(line_type = 'Comment') AS comments, countIf(line_type = 'Code') AS code, if(comments > 0, comments / (comments + code), 0) AS ratio_comments FROM git.line_changes GROUP BY author, commit_hash ) GROUP BY author ORDER BY code DESC LIMIT 10 ┌─author─────────────┬──avg_ratio_comments─┬────code─┐ │ Alexey Milovidov │ 0.1034915408309902 │ 1147196 │ │ s-kat │ 0.1361718900215362 │ 614224 │ │ Nikolai Kochetov │ 0.08722993407690126 │ 218328 │ │ alesapin │ 0.1040477684726504 │ 198082 │ │ Vitaly Baranov │ 0.06446875712939285 │ 161801 │ │ Maksim Kita │ 0.06863376297549255 │ 156381 │ │ Alexey Arno │ 0.11252677608033655 │ 146642 │ │ Vitaliy Zakaznikov │ 0.06199215397180561 │ 138530 │ │ kssenii │ 0.07455322590796751 │ 131143 │ │ Artur │ 0.12383737231074826 │ 121484 │ └────────────────────┴─────────────────────┴─────────┘ 10 rows in set. Elapsed: 0.290 sec. Processed 7.54 million rows, 394.57 MB (26.00 million rows/s., 1.36 GB/s.) ``` コードの寄与によってソートしていることに注意してください。すべての大きな寄稿者に対して驚くほど高い%であり、これがコードを非常に読みやすくする一因です。 ## 著者のコミットが時間経過とともにコード/コメントの割合に関してどのように変化するのか? 著者ごとの計算は簡単です。 [プレイ](#U0VMRUNUCiAgICBhdXRob3IsCiAgICBjb3VudElmKGxpbmVfdHlwZSA9ICdDb2RlJykgQVMgY29kZV9saW5lcywKICAgIGNvdW50SWYoKGxpbmVfdHlwZSA9ICdDb21tZW50JykgT1IgKGxpbmVfdHlwZSA9ICdQdW5jdCcpKSBBUyBjb21tZW50cywKICAgIGNvZGVfbGluZXMgLyAoY29tbWVudHMgKyBjb2RlX2xpbmVzKSBBUyByYXRpb19jb2RlLAogICAgdG9TdGFydE9mV2Vlayh0aW1lKSBBUyB3ZWVrCkZST00gZ2l0X2NsaWNraG91c2UubGluZV9jaGFuZ2VzCkdST1VQIEJZCiAgICB0aW1lLAogICAgYXV0aG9yCk9SREVSIEJZCiAgICBhdXRob3IgQVNDLAogICAgdGltZSBBU0MKTElNSVQgMTA=) ```sql SELECT author, countIf(line_type = 'Code') AS code_lines, countIf((line_type = 'Comment') OR (line_type = 'Punct')) AS comments, code_lines / (comments + code_lines) AS ratio_code, toStartOfWeek(time) AS week FROM git.line_changes GROUP BY time, author ORDER BY author ASC, time ASC LIMIT 10 ┌─author──────────────────────┬─code_lines─┬─comments─┬─────────ratio_code─┬───────week─┐ │ 1lann │ 8 │ 0 │ 1 │ 2022-03-06 │ │ 20018712 │ 2 │ 0 │ 1 │ 2020-09-13 │ │ 243f6a8885a308d313198a2e037 │ 0 │ 2 │ 0 │ 2020-12-06 │ │ 243f6a8885a308d313198a2e037 │ 0 │ 112 │ 0 │ 2020-12-06 │ │ 243f6a8885a308d313198a2e037 │ 0 │ 14 │ 0 │ 2020-12-06 │ │ 3ldar-nasyrov │ 2 │ 0 │ 1 │ 2021-03-14 │ │ 821008736@qq.com │ 27 │ 2 │ 0.9310344827586207 │ 2019-04-21 │ │ ANDREI STAROVEROV │ 182 │ 60 │ 0.7520661157024794 │ 2021-05-09 │ │ ANDREI STAROVEROV │ 7 │ 0 │ 1 │ 2021-05-09 │ │ ANDREI STAROVEROV │ 32 │ 12 │ 0.7272727272727273 │ 2021-05-09 │ └─────────────────────────────┴────────────┴──────────┴────────────────────┴────────────┘ 10 rows in set. Elapsed: 0.145 sec. Processed 7.54 million rows, 51.09 MB (51.83 million rows/s., 351.44 MB/s.) ``` 理想的には、すべての著者の最初のコミットからの集約でこの変化を見たいと思います。著者は徐々に書くコメントの数を減らしているのでしょうか? これを計算するために、まず各著者の時間に伴うコメント比率を計算します - [誰がより多くのテスト/ CPP コード/ コメントを書きがちか?](#who-tends-to-write-more-tests--cpp-code--comments)と同様です。これは各著者の開始日と結合され、コメント比率を週オフセットで計算できます。 すべての著者の平均を計算した後、毎10週目を選択してこれらの結果をサンプリングします。 [プレイ](https://sql.clickhouse.com?query_id=SBHEWR8XC4PRHY13HPPKCN) ```sql WITH author_ratios_by_offset AS ( SELECT author, dateDiff('week', start_dates.start_date, contributions.week) AS week_offset, ratio_code FROM ( SELECT author, toStartOfWeek(min(time)) AS start_date FROM git.line_changes WHERE file_extension IN ('h', 'cpp', 'sql') GROUP BY author AS start_dates ) AS start_dates INNER JOIN ( SELECT author, countIf(line_type = 'Code') AS code, countIf((line_type = 'Comment') OR (line_type = 'Punct')) AS comments, comments / (comments + code) AS ratio_code, toStartOfWeek(time) AS week FROM git.line_changes WHERE (file_extension IN ('h', 'cpp', 'sql')) AND (sign = 1) GROUP BY time, author HAVING code > 20 ORDER BY author ASC, time ASC ) AS contributions USING (author) ) SELECT week_offset, avg(ratio_code) AS avg_code_ratio FROM author_ratios_by_offset GROUP BY week_offset HAVING (week_offset % 10) = 0 ORDER BY week_offset ASC LIMIT 20 ┌─week_offset─┬──────avg_code_ratio─┐ │ 0 │ 0.21626798253005078 │ │ 10 │ 0.18299433892099454 │ │ 20 │ 0.22847255749045017 │ │ 30 │ 0.2037816688365288 │ │ 40 │ 0.1987063517030308 │ │ 50 │ 0.17341406302829748 │ │ 60 │ 0.1808884776496144 │ │ 70 │ 0.18711773536450496 │ │ 80 │ 0.18905573684766458 │ │ 90 │ 0.2505147771581594 │ │ 100 │ 0.2427673990917429 │ │ 110 │ 0.19088569009169926 │ │ 120 │ 0.14218574654598348 │ │ 130 │ 0.20894252550489317 │ │ 140 │ 0.22316626978848397 │ │ 150 │ 0.1859507592277053 │ │ 160 │ 0.22007759757363546 │ │ 170 │ 0.20406936638195144 │ │ 180 │ 0.1412102467834332 │ │ 190 │ 0.20677550885049117 │ └─────────────┴─────────────────────┘ 20 rows in set. Elapsed: 0.167 sec. Processed 15.07 million rows, 101.74 MB (90.51 million rows/s., 610.98 MB/s.) ``` 励みになることに、我々のコメント % はかなり安定していて、著者が寄与する期間が長くなるほど劣化しません。 ## コードが書き換えられるまでの平均時間と中央値(コードの decay の半減期)は? すべてのファイルを考慮して書き換えを特定するために、[最も多く再書き換えられたファイルや作者をリストする](#list-files-that-were-rewritten-most-number-of-time-or-by-most-of-authors)と同じ原則を用いることができます。ウィンドウ関数を使用して、各ファイルの書き換え間隔の時間を計算します。これから、すべてのファイルにわたって平均と中央値を計算できます。 [プレイ](https://sql.clickhouse.com?query_id=WSHUEPJP9TNJUH7QITWWOR) ```sql WITH changes AS ( SELECT path, commit_hash, max_time, type, num_added, num_deleted, sum(num_added - num_deleted) OVER (PARTITION BY path ORDER BY max_time ASC) AS current_size, if(current_size > 0, num_added / current_size, 0) AS percent_add, if(current_size > 0, num_deleted / current_size, 0) AS percent_delete FROM ( SELECT path, max(time) AS max_time, commit_hash, any(lines_added) AS num_added, any(lines_deleted) AS num_deleted, any(change_type) AS type FROM git.file_changes WHERE (change_type IN ('Add', 'Modify')) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path, commit_hash ORDER BY path ASC, max_time ASC ) ), rewrites AS ( SELECT *, any(max_time) OVER (PARTITION BY path ORDER BY max_time ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS previous_rewrite, dateDiff('day', previous_rewrite, max_time) AS rewrite_days FROM changes WHERE (type = 'Modify') AND (percent_add >= 0.5) AND (percent_delete >= 0.5) AND (current_size > 50) ) SELECT avgIf(rewrite_days, rewrite_days > 0) AS avg_rewrite_time, quantilesTimingIf(0.5)(rewrite_days, rewrite_days > 0) AS half_life FROM rewrites ┌─avg_rewrite_time─┬─half_life─┐ │ 122.2890625 │ [23] │ └──────────────────┴───────────┘ 1 row in set. Elapsed: 0.388 sec. Processed 266.05 thousand rows, 22.85 MB (685.82 thousand rows/s., 58.89 MB/s.) ``` ## どのような時がコードが書き換えられる可能性が最も高いのか? [コードが書き換えられるまでの平均時間と中央値(コードの decay の半減期)](#what-is-the-average-time-before-code-will-be-rewritten-and-the-median-half-life-of-code-decay)と[最も多く再書き換えられたファイルや作者をリストする](#list-files-that-were-rewritten-most-number-of-time-or-by-most-of-authors)に似ていますが、こちらは曜日によって集計します。必要に応じて月ごとなどに調整できます。 [プレイ](https://sql.clickhouse.com?query_id=8PQNWEWHAJTGN6FTX59KH2) ```sql WITH changes AS ( SELECT path, commit_hash, max_time, type, num_added, num_deleted, sum(num_added - num_deleted) OVER (PARTITION BY path ORDER BY max_time ASC) AS current_size, if(current_size > 0, num_added / current_size, 0) AS percent_add, if(current_size > 0, num_deleted / current_size, 0) AS percent_delete FROM ( SELECT path, max(time) AS max_time, commit_hash, any(file_lines_added) AS num_added, any(file_lines_deleted) AS num_deleted, any(file_change_type) AS type FROM git.line_changes WHERE (file_change_type IN ('Add', 'Modify')) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path, commit_hash ORDER BY path ASC, max_time ASC ) ), rewrites AS ( SELECT any(max_time) OVER (PARTITION BY path ORDER BY max_time ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS previous_rewrite FROM changes WHERE (type = 'Modify') AND (percent_add >= 0.5) AND (percent_delete >= 0.5) AND (current_size > 50) ) SELECT dayOfWeek(previous_rewrite) AS dayOfWeek, count() AS num_re_writes FROM rewrites GROUP BY dayOfWeek ┌─dayOfWeek─┬─num_re_writes─┐ │ 1 │ 111 │ │ 2 │ 121 │ │ 3 │ 91 │ │ 4 │ 111 │ │ 5 │ 90 │ │ 6 │ 64 │ │ 7 │ 46 │ └───────────┴───────────────┘ 7 rows in set. Elapsed: 0.466 sec. Processed 7.54 million rows, 701.52 MB (16.15 million rows/s., 1.50 GB/s.) ``` ## どの著者のコードが最も安定しているか? 「安定している」とは、著者のコードが書き換えられるまでの時間を定義します。以前の質問[コードが書き換えられるまでの平均時間と中央値(コードの decay の半減期)](#what-is-the-average-time-before-code-will-be-rewritten-and-the-median-half-life-of-code-decay)と同じ指標を使用した重みを付けます。つまり、ファイルの追加および削除の比率が50%であることです。各著者ごとの平均書き換え時間を計算し、2ファイル以上の寄稿者のみを考慮します。 [プレイ](https://sql.clickhouse.com?query_id=BKHLVVWN5SET1VTIFQ8JVK) ```sql WITH changes AS ( SELECT path, author, commit_hash, max_time, type, num_added, num_deleted, sum(num_added - num_deleted) OVER (PARTITION BY path ORDER BY max_time ASC) AS current_size, if(current_size > 0, num_added / current_size, 0) AS percent_add, if(current_size > 0, num_deleted / current_size, 0) AS percent_delete FROM ( SELECT path, any(author) AS author, max(time) AS max_time, commit_hash, any(file_lines_added) AS num_added, any(file_lines_deleted) AS num_deleted, any(file_change_type) AS type FROM git.line_changes WHERE (file_change_type IN ('Add', 'Modify')) AND (file_extension IN ('h', 'cpp', 'sql')) GROUP BY path, commit_hash ORDER BY path ASC, max_time ASC ) ), rewrites AS ( SELECT *, any(max_time) OVER (PARTITION BY path ORDER BY max_time ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS previous_rewrite, dateDiff('day', previous_rewrite, max_time) AS rewrite_days, any(author) OVER (PARTITION BY path ORDER BY max_time ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_author FROM changes WHERE (type = 'Modify') AND (percent_add >= 0.5) AND (percent_delete >= 0.5) AND (current_size > 50) ) SELECT prev_author, avg(rewrite_days) AS c, uniq(path) AS num_files FROM rewrites GROUP BY prev_author HAVING num_files > 2 ORDER BY c DESC LIMIT 10 ┌─prev_author─────────┬──────────────────c─┬─num_files─┐ │ Michael Kolupaev │ 304.6 │ 4 │ │ alexey-milovidov │ 81.83333333333333 │ 4 │ │ Alexander Kuzmenkov │ 64.5 │ 5 │ │ Pavel Kruglov │ 55.8 │ 6 │ │ Alexey Milovidov │ 48.416666666666664 │ 90 │ │ Amos Bird │ 42.8 │ 4 │ │ alesapin │ 38.083333333333336 │ 12 │ │ Nikolai Kochetov │ 33.18421052631579 │ 26 │ │ Alexander Tokmakov │ 31.866666666666667 │ 12 │ │ Alexey Zatelepin │ 22.5 │ 4 │ └─────────────────────┴────────────────────┴───────────┘ 10 rows in set. Elapsed: 0.555 sec. Processed 7.54 million rows, 720.60 MB (13.58 million rows/s., 1.30 GB/s.) ``` ## ある著者による最も連続したコミットの日数 このクエリは、まず著者がコミットした日を計算する必要があります。ウィンドウ関数を使用して著者ごとに分割し、コミット間の日数を計算できます。各コミットについて、前回のコミットからの時間が1日であればそれを連続(1)としてマークし、そうでない場合は0として `consecutive_day` に結果を保存します。 その後、配列関数を使って各著者の最長の連続1のシーケンスを計算します。まず、`groupArray` 関数を使って著者ごとのすべての `consecutive_day` 値をまとめます。この1と0の配列は、0の値で分割され、サブ配列に変換されます。最後に、最も長いサブ配列を計算します。 [プレイ](https://sql.clickhouse.com?query_id=S3E64UYCAMDAYJRSXINVFR) ```sql WITH commit_days AS ( SELECT author, day, any(day) OVER (PARTITION BY author ORDER BY day ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS previous_commit, dateDiff('day', previous_commit, day) AS days_since_last, if(days_since_last = 1, 1, 0) AS consecutive_day FROM ( SELECT author, toStartOfDay(time) AS day FROM git.commits GROUP BY author, day ORDER BY author ASC, day ASC ) ) SELECT author, arrayMax(arrayMap(x -> length(x), arraySplit(x -> (x = 0), groupArray(consecutive_day)))) - 1 AS max_consecutive_days FROM commit_days GROUP BY author ORDER BY max_consecutive_days DESC LIMIT 10 ┌─author───────────┬─max_consecutive_days─┐ │ kssenii │ 32 │ │ Alexey Milovidov │ 30 │ │ alesapin │ 26 │ │ Azat Khuzhin │ 23 │ │ Nikolai Kochetov │ 15 │ │ feng lv │ 11 │ │ alexey-milovidov │ 11 │ │ Igor Nikonov │ 11 │ │ Maksim Kita │ 11 │ │ Nikita Vasilev │ 11 │ └──────────────────┴──────────────────────┘ 10 rows in set. Elapsed: 0.025 sec. Processed 62.78 thousand rows, 395.47 KB (2.54 million rows/s., 16.02 MB/s.) ``` ## ファイルの行ごとのコミット履歴 ファイルは名前が変更されることがあります。この場合、`path` カラムはファイルの新しいパスに設定され、`old_path` は前の場所を示します。例えば: [プレイ](https://sql.clickhouse.com?query_id=AKTW3Z8JZAPQ4H9BH2ZFRX) ```sql SELECT time, path, old_path, commit_hash, commit_message FROM git.file_changes WHERE (path = 'src/Storages/StorageReplicatedMergeTree.cpp') AND (change_type = 'Rename') ┌────────────────time─┬─path────────────────────────────────────────┬─old_path─────────────────────────────────────┬─commit_hash──────────────────────────────┬─commit_message─┐ │ 2020-04-03 16:14:31 │ src/Storages/StorageReplicatedMergeTree.cpp │ dbms/Storages/StorageReplicatedMergeTree.cpp │ 06446b4f08a142d6f1bc30664c47ded88ab51782 │ dbms/ → src/ │ └─────────────────────┴─────────────────────────────────────────────┴──────────────────────────────────────────────┴──────────────────────────────────────────┴────────────────┘ 1 row in set. Elapsed: 0.135 sec. Processed 266.05 thousand rows, 20.73 MB (1.98 million rows/s., 154.04 MB/s.) ``` これにより、ファイルの完全な履歴を表示するのは難しいです。すべての行またはファイルの変更を接続する単一の値が存在しないからです。 これに対処するために、ユーザー定義関数(UDF)を使用することができます。これらは現在再帰的ではないため、ファイルの履歴を特定するためには、互いに明示的に呼び出す一連の UDF を定義する必要があります。 これにより、名前変更を最大深度まで追跡できるようになります - 次の例は5深です。ファイルがこの回数以上に名前が変更される可能性は低いため、現段階ではこれで十分です。 ```sql CREATE FUNCTION file_path_history AS (n) -> if(empty(n), [], arrayConcat([n], file_path_history_01((SELECT if(empty(old_path), Null, old_path) FROM git.file_changes WHERE path = n AND (change_type = 'Rename' OR change_type = 'Add') LIMIT 1)))); CREATE FUNCTION file_path_history_01 AS (n) -> if(isNull(n), [], arrayConcat([n], file_path_history_02((SELECT if(empty(old_path), Null, old_path) FROM git.file_changes WHERE path = n AND (change_type = 'Rename' OR change_type = 'Add') LIMIT 1)))); CREATE FUNCTION file_path_history_02 AS (n) -> if(isNull(n), [], arrayConcat([n], file_path_history_03((SELECT if(empty(old_path), Null, old_path) FROM git.file_changes WHERE path = n AND (change_type = 'Rename' OR change_type = 'Add') LIMIT 1)))); CREATE FUNCTION file_path_history_03 AS (n) -> if(isNull(n), [], arrayConcat([n], file_path_history_04((SELECT if(empty(old_path), Null, old_path) FROM git.file_changes WHERE path = n AND (change_type = 'Rename' OR change_type = 'Add') LIMIT 1)))); CREATE FUNCTION file_path_history_04 AS (n) -> if(isNull(n), [], arrayConcat([n], file_path_history_05((SELECT if(empty(old_path), Null, old_path) FROM git.file_changes WHERE path = n AND (change_type = 'Rename' OR change_type = 'Add') LIMIT 1)))); CREATE FUNCTION file_path_history_05 AS (n) -> if(isNull(n), [], [n]); ``` `file_path_history('src/Storages/StorageReplicatedMergeTree.cpp')`を呼び出すことによって、名前変更の履歴を再帰的にたどります。各関数は `old_path` で次のレベルを呼び出します。結果は `arrayConcat` を使用して組み合わされます。 例えば、 ```sql SELECT file_path_history('src/Storages/StorageReplicatedMergeTree.cpp') AS paths ┌─paths─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ['src/Storages/StorageReplicatedMergeTree.cpp','dbms/Storages/StorageReplicatedMergeTree.cpp','dbms/src/Storages/StorageReplicatedMergeTree.cpp'] │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 1 row in set. Elapsed: 0.074 sec. Processed 344.06 thousand rows, 6.27 MB (4.65 million rows/s., 84.71 MB/s.) ``` この機能を使用して、ファイルの完全な履歴のためのコミットを組み立てることができます。この例では、各 `path` 値のために1つのコミットを示します。 ```sql SELECT time, substring(commit_hash, 1, 11) AS commit, change_type, author, path, commit_message FROM git.file_changes WHERE path IN file_path_history('src/Storages/StorageReplicatedMergeTree.cpp') ORDER BY time DESC LIMIT 1 BY path FORMAT PrettyCompactMonoBlock ┌────────────────time─┬─commit──────┬─change_type─┬─author─────────────┬─path─────────────────────────────────────────────┬─commit_message──────────────────────────────────────────────────────────────────┐ │ 2022-10-30 16:30:51 │ c68ab231f91 │ Modify │ Alexander Tokmakov │ src/Storages/StorageReplicatedMergeTree.cpp │ fix accessing part in Deleting state │ │ 2020-04-03 15:21:24 │ 38a50f44d34 │ Modify │ alesapin │ dbms/Storages/StorageReplicatedMergeTree.cpp │ Remove empty line │ │ 2020-04-01 19:21:27 │ 1d5a77c1132 │ Modify │ alesapin │ dbms/src/Storages/StorageReplicatedMergeTree.cpp │ Tried to add ability to rename primary key columns but just banned this ability │ └─────────────────────┴─────────────┴─────────────┴────────────────────┴──────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────┘ 3 rows in set. Elapsed: 0.170 sec. Processed 611.53 thousand rows, 41.76 MB (3.60 million rows/s., 246.07 MB/s.) ``` # 未解決の質問 ## Git blame これは、状態を配列関数で保持できないことに起因して特に困難です。これは、各反復で状態を保持できる `arrayFold` または `arrayReduce` で可能になります。 高レベルの分析に十分な近似的な解決策は次のようになるかもしれません: ```sql SELECT line_number_new, argMax(author, time), argMax(line, time) FROM git.line_changes WHERE path IN file_path_history('src/Storages/StorageReplicatedMergeTree.cpp') GROUP BY line_number_new ORDER BY line_number_new ASC LIMIT 20 ┌─line_number_new─┬─argMax(author, time)─┬─argMax(line, time)────────────────────────────────────────────┐ │ 1 │ Alexey Milovidov │ #include │ │ 2 │ s-kat │ #include │ │ 3 │ Anton Popov │ #include │ │ 4 │ Alexander Burmak │ #include │ │ 5 │ avogar │ #include │ │ 6 │ Alexander Burmak │ #include │ │ 7 │ Alexander Burmak │ #include │ │ 8 │ Alexander Burmak │ #include │ │ 9 │ Alexander Burmak │ #include │ │ 10 │ Alexander Burmak │ #include │ │ 11 │ Alexander Burmak │ #include │ │ 12 │ Nikolai Kochetov │ #include │ │ 13 │ alesapin │ #include │ │ 14 │ alesapin │ │ │ 15 │ Alexey Milovidov │ #include │ │ 16 │ Alexey Zatelepin │ #include │ │ 17 │ CurtizJ │ #include │ │ 18 │ Kirill Shvakov │ #include │ │ 19 │ s-kat │ #include │ │ 20 │ Nikita Mikhaylov │ #include │ └─────────────────┴──────────────────────┴───────────────────────────────────────────────────────────────┘ 20 rows in set. Elapsed: 0.547 sec. Processed 7.88 million rows, 679.20 MB (14.42 million rows/s., 1.24 GB/s.) ``` ここでの正確で改善された解決策を歓迎します。 ## 関連コンテンツ - Blog: [Gitコミットと私たちのコミュニティ](https://clickhouse.com/blog/clickhouse-git-community-commits) - Blog: [Gitコミットシーケンスのためのウィンドウと配列関数](https://clickhouse.com/blog/clickhouse-window-array-functions-git-commits) - Blog: [ClickHouseとHexでリアルタイム分析アプリを構築する](https://clickhouse.com/blog/building-real-time-applications-with-clickhouse-and-hex-notebook-keeper-engine) - Blog: [ClickHouse + Grafanaを使用したオープンソースGitHubアクティビティの物語](https://clickhouse.com/blog/introduction-to-clickhouse-and-grafana-webinar) ```