MySQLのこと。

MySQLのことについてまとめているブログ。他人に見せる用でもなく、自分の勉強備忘録。検索インデックスも外してるので、辿りついた方・・・ようこそ。そんな大した情報ないですよ?!たまにアルゴリズムの練習も

Fighting Churn With Dataのシミュレーションデータの生成方法[PostgreSQL]

SaaSサンプルデータ生成のまとめ

"Fighting Churn With Data: Science and strategy for keeping your customers"というSaaSデータの分析をまとめたCarl S. Goldさんの書籍のサンプルデータを生成するまでの流れをまとめたもの。下記のYouTubeにある動画でも解説されているが、私の理解が足りず、いくつか躓いた部分があったので、メモしておく。

リポジトリのクローン

まずは下記のリポジトリをダウンロードしてデスクトップにでもおいておく。

% git clone https://github.com/carl24k/fight-churn.git

PostgreSQLとPyCharmのインストール

  • Python 3.9
    • pip3 install -r requirements.txtでパッケージをインストール(リポジトリにおいてある)
  • PyCharm
    • Community EditionでOK
  • PostgreSQL
    • データベース(churn)を作成する。スキーマーをやテーブル定義はPythonファイルで行うので必要なし。

スキーマの作成

次はスキーマーを作成する。まずはPyCharmを起動して、クローンしてきたfight-churn-masterをプロジェクトに指定して開く。スキーマーを作成するPythonファイルはchurndb.py、データを生成するのはchurnsim.py

churndb.pyにはschema_name='socialnet7'がデフォルトのスキーマー名として設定されている。変更する必要がなければ、このままにしておく。コンフィグレーションファイルの設定を行い、スクリプトパスは下記を設定する。

  • /Users/<name>/Desktop/fight-churn-master/fightchurn/datagen/churndb.py

コンフィグレーションファイルの設定でPostgreSQLへの接続設定をEnvironmentに記載する。

  • CHURN_DB: churn
  • CHURN_DB_USER: PostgreSQLに接続するユーザー名
  • CHURN_DB_PASS: PostgreSQLに接続するユーザーのパスワード
  • CHURN_OUT_DIR: ログを書き出すディレクト

これらの設定が終わったらchurndb.pyを実行する。実行完了後、PostgreSQLchurn.socialnet7という形でテーブルが複数作成されている。

シミュレーションデータの生成

次はテーブルにシミュレーションデータをインサートする。使用するファイルはchurnsim.pychurnsim.pymain関数のところで、シミュレーションする期間やユーザー数が指定できるが、ここもそのままでよければ変更しない。デフォルトの6ヶ月の設定でも、12GBくらいのデータが生成される。スペックにもよるが私のPCでは1時間程度かかった。シミュレーションの結果はsubscriptioneventに挿入される。accountevent_typeにもデータはインサートされる。

コンフィグレーションファイルの設定を行い、スクリプトパスは下記を設定する。

  • /Users/<name>/Desktop/fight-churn-master/fightchurn/datagen/churnsim.py

コンフィグレーションファイルの設定でPostgreSQLへの接続設定をEnvironmentに記載する。

  • CHURN_DB: churn
  • CHURN_DB_USER: PostgreSQLに接続するユーザー名
  • CHURN_DB_PASS: PostgreSQLに接続するユーザーのパスワード
  • CHURN_OUT_DIR: ログを書き出すディレクト

実行すると下記のログが出力される。

Creating 10000 initial customers for month of 2020-01-01
Simulated customer 0/10000: 4 subscriptions & 108 events
Simulated customer 100/10000: 453 subscriptions & 132,390 events
[略]

[略]
Simulated customer 1300/1331: 1,329 subscriptions & 383,867 events
Created 1331 new customers for month 2020-05-01, now 55231 subscriptions

Process finished with exit code 0

データがインサートされているか確認しておく。

% qsql -U postgres -d churn -W 

churn=# SELECT COUNT(1) FROM socialnet7.subscription;
 count 
-------
 55231
(1 row)

churn=# SELECT * FROM socialnet7.subscription LIMIT 10;
 id | account_id |   product    | start_date |  end_date  | mrr  | quantity | units | bill_period_months 
----+------------+--------------+------------+------------+------+----------+-------+--------------------
  0 |          1 | 'socialnet7' | 2020-01-13 | 2020-02-13 | 9.99 |          |       |                  1
  1 |          1 | 'socialnet7' | 2020-02-13 | 2020-03-13 | 9.99 |          |       |                  1
  2 |          1 | 'socialnet7' | 2020-03-13 | 2020-04-13 | 9.99 |          |       |                  1
  3 |          1 | 'socialnet7' | 2020-04-13 | 2020-05-13 | 9.99 |          |       |                  1
  4 |          2 | 'socialnet7' | 2020-01-04 | 2020-02-04 | 9.99 |          |       |                  1
  5 |          2 | 'socialnet7' | 2020-02-04 | 2020-03-04 | 9.99 |          |       |                  1
  6 |          2 | 'socialnet7' | 2020-03-04 | 2020-04-04 | 9.99 |          |       |                  1
  7 |          2 | 'socialnet7' | 2020-04-04 | 2020-05-04 | 9.99 |          |       |                  1
  8 |          2 | 'socialnet7' | 2020-05-04 | 2020-06-04 | 9.99 |          |       |                  1
  9 |          3 | 'socialnet7' | 2020-01-10 | 2020-02-10 | 9.99 |          |       |                  1
(10 rows)

churn=# SELECT COUNT(1) FROM socialnet7.event;
  count   
----------
 16995997
(1 row)

churn=# SELECT * FROM socialnet7.event LIMIT 10;
 account_id |     event_time      | event_type_id 
------------+---------------------+---------------
          1 | 2020-01-14 20:03:13 |             4
          1 | 2020-01-15 04:42:10 |             4
          1 | 2020-01-16 11:57:11 |             0
          1 | 2020-01-17 07:16:53 |             0
          1 | 2020-01-17 00:23:51 |             4
          1 | 2020-01-17 03:39:04 |             4
          1 | 2020-01-20 23:59:07 |             4
          1 | 2020-01-22 16:20:53 |             2
          1 | 2020-01-23 03:04:57 |             2
          1 | 2020-01-25 02:40:13 |             2
(10 rows)

churn=# SELECT * FROM socialnet7.event_type;
 event_type_id | event_type_name 
---------------+-----------------
             0 | post
             1 | newfriend
             2 | like
             3 | adview
             4 | dislike
             5 | unfriend
             6 | message
             7 | reply
(8 rows)


churn=# SELECT COUNT(1) FROM socialnet7.account;
 count 
-------
 14641
(1 row)

churn=# SELECT * FROM socialnet7.account LIMIT 10;
 id |  channel  | date_of_birth | country 
----+-----------+---------------+---------
  1 | appstore1 | 2002-12-05    | US
  2 | appstore2 | 1971-07-24    | NZ
  3 | appstore2 | 1949-02-17    | GB
  4 | appstore1 | 1987-09-23    | NZ
  5 | appstore1 | 1972-07-11    | CA
  6 | appstore2 | 1976-10-25    | IN
  7 | appstore2 | 1994-04-19    | SE
  8 | web       | 1958-05-16    | CN
  9 | web       | 1976-03-10    | AR
 10 | appstore2 | 1973-11-26    | CA
(10 rows)

下記のER図は私が勝手に作ったもの。多分こんな感じだと思われる。そして、dbdiagramすごく便利。

f:id:AZUMINO:20211227171358p:plain

別のサーバに移動する必要があったので、ダンプファイルを作成して、インポート。

[PC1]
% pg_dump churn > ~/Desktop/churndump

[PC2]
$ psql -U aki -d postgres -W
>> OSのスーパユーザーのパスワードが必要

postgres=> CREATE DATABASE churn
postgres=> quit

$ psql churn < ~/Desktop/churndump
>> OSのスーパユーザーのパスワードが必要

# workerにデータベースとテーブル権限を付与
# もっと効率的かつセキュアにやれるっぽいが、ここらへんの理解が足りてない。
$ \c churn
>> OSのスーパユーザーのパスワードが必要

churn=# GRANT ALL PRIVILEGES ON DATABASE churn TO worker;
churn=# GRANT ALL ON TABLE socialnet7.account TO worker;
churn=# GRANT ALL ON TABLE socialnet7.active_period TO worker;
churn=# GRANT ALL ON TABLE socialnet7.active_week TO worker;
churn=# GRANT ALL ON TABLE socialnet7.event TO worker;
churn=# GRANT ALL ON TABLE socialnet7.event_type TO worker;
churn=# GRANT ALL ON TABLE socialnet7.metric TO worker;
churn=# GRANT ALL ON TABLE socialnet7.metric_name TO worker;
churn=# GRANT ALL ON TABLE socialnet7.observation TO worker;
churn=# GRANT ALL ON TABLE socialnet7.subscription TO worker;

以上でおわり。