ユーザ、アイテム、評価値テーブルの設計とデータの登録
推薦システムで利用する各テーブルを設計しましょう。まず、基本的なデータとして、ユーザ、アイテム、評価値に関するテーブルを設計します。それぞれ、次のようなテーブルを設計することにします。
users
カラム名 | 説明 | データ型 | 制約 |
---|---|---|---|
user_id | ユーザID | INT | PRIMARY KEY |
name | ユーザ名 | TEXT | NOT NULL |
age | 年齢 | INT | |
sex | 性別 | CHAR(1) |
items
カラム名 | 説明 | データ型 | 制約 |
---|---|---|---|
item_id | アイテムID | INT | PRIMARY KEY |
name | アイテム名 | TEXT | NOT NULL |
red | 赤身 | INT | |
white | 白身 | INT | |
shining | 光物 | INT |
ratings
カラム名 | 説明 | データ型 | 制約 |
---|---|---|---|
id | ID | SERIAL | PRIMARY KEY |
user_id | ユーザID | INT | FOREIGN KEY(users.user_id), NOT NULL |
item_id | アイテムID | INT | FOREIGN KEY(items.item_id), NOT NULL |
rating | 評価値 | INT | NOT NULL |
ここで、ratings
テーブルではid
を主キーとしています。(user_id, item_id)
の複合キーを主キーとしても良いのですが、Djangoのモデルで複合キーを扱おうとすると複雑になりますので、ここでは別途id
を用意し、これを主キーとすることにします。また、id
のデータ型をSERIAL
としています。これは、データ登録時にid
を省略したとき、id
には自動的に連番が振られることを表しています。
以上のテーブルをPostgreSQLのrecsys_django
データベース上で作成します。PostgreSQL上で下記のコマンドを実行してください。
recsys_django=#
CREATE TABLE users(
user_id INT,
name TEXT NOT NULL,
age INT,
sex CHAR(1),
PRIMARY KEY(user_id)
);
recsys_django=#
CREATE TABLE items(
item_id INT,
name TEXT NOT NULL,
red INT,
white INT,
shining INT,
PRIMARY KEY(item_id)
);
recsys_django=#
CREATE TABLE ratings(
id SERIAL,
user_id INT NOT NULL,
item_id INT NOT NULL,
rating INT NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY(user_id) REFERENCES users(user_id),
FOREIGN KEY(item_id) REFERENCES items(item_id)
);
下記のコマンドで、作成されたテーブルを確認してみましょう。
recsys_django=# \dt
List of relations
Schema | Name | Type | Owner
--------+--------------------------------------+-------+----------
...(略)...
public | items | table | postgres
public | ratings | table | postgres
public | users | table | postgres
(13 rows)
users
、items
、ratings
の三つのテーブルが作成されていることが確認できました。ただし、テーブルの所有者Owner
がpostgres
となっているので、recsys_django
プロジェクトからアクセスできるように、これをrsl
に変更しておきましょう。それぞれ、下記のコマンドを実行して各テーブルの所有者を変更してください。
recsys_django=# ALTER TABLE users OWNER TO rsl;
ALTER TABLE
recsys_django=# ALTER TABLE items OWNER TO rsl;
ALTER TABLE
recsys_django=# ALTER TABLE ratings OWNER TO rsl;
ALTER TABLE
下記のように、Owner
がrsl
に変更されました。
recsys_django=# \dt
List of relations
Schema | Name | Type | Owner
--------+--------------------------------------+-------+----------
...(略)...
public | items | table | rsl
public | ratings | table | rsl
public | users | table | rsl
(13 rows)
作成したテーブルの構造は下記のコマンドで表示することができます。
recsys_django=# \d users
Table "public.users"
Column | Type | Collation | Nullable | Default
---------+--------------+-----------+----------+---------
user_id | integer | | not null |
name | text | | not null |
age | integer | | |
sex | character(1) | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (user_id)
Referenced by:
TABLE "ratings" CONSTRAINT "ratings_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
設計したとおりのテーブル構造になっていることが確認できます。items
テーブル、ratings
テーブルについても確認しておきましょう。
さて、現時点では、それぞれテーブルの枠組みを用意しただけで、データはまだ登録されていません。それぞれ、ユーザ、アイテム、評価値に関するデータを登録していきましょう。本チュートリアルでは、サンプルデータをrecsyslab/recsys-django/contents/recsys_django/offline/data/に置いています。この中のusers.csv
、items.csv
、ratings.csv
を任意のディレクトリにダウンロードしてください。そして、PostgreSQL上でそれぞれ下記のコマンドを実行してください。ここで、【ディレクトリ】には各ファイルを置いているディレクトリを入力してください。
recsys_django=# COPY users FROM '【ディレクトリ】/users.csv' (DELIMITER E'\t', FORMAT csv, HEADER TRUE, ENCODING 'UTF-8');
COPY 5
recsys_django=# COPY items FROM '【ディレクトリ】/items.csv' (DELIMITER E'\t', FORMAT csv, HEADER TRUE, ENCODING 'UTF-8');
COPY 9
recsys_django=# COPY ratings FROM '【ディレクトリ】/ratings.csv' (DELIMITER E'\t', FORMAT csv, HEADER TRUE, ENCODING 'UTF-8');
COPY 28
recsys_django=# SELECT setval('ratings_id_seq', (SELECT max(id) FROM ratings));
setval
--------
28
(1 row)
ここで、最後のコマンドでid
のシーケンス値を更新しています。今回はratings.csv
からid=28
までを強制的に登録しましたので、シーケンス値を28
に設定することで、次回データが登録されるときにその次の値である29
が自動的に振られるようにしています。
これで、各テーブルへのデータの登録ができました。users
テーブルの内容を確認してみましょう。
recsys_django=# SELECT * FROM users;
user_id | name | age | sex
---------+--------+-----+-----
1 | Alice | 20 | f
2 | Bruno | 22 | m
3 | Chiara | 21 | f
4 | Dhruv | 21 | m
5 | Emi | 20 | f
(5 rows)
items
テーブル、ratings
テーブルについても内容を確認しておきましょう。