Docker上でPostgreSQL+RDKitカートリッジ環境作って遊ぶ

# 背景
化学のデータベース周りの話になります。
- PostgreSQLにRDKitカートリッジ(拡張機能)を入れると構造類似検索とかをSQLベースでできて楽しいらしい
- でも環境構築に関する情報があまり見つからない…
- 簡単に環境を作ることだけを考えてやってみた

# 前提
- Docker Desktopが入っている
- psql(postgreSQLのクライアント)が入っており、PATHも通っている

# 流れ
- Dockerfileをビルドしてイメージ作成、コンテナを立てる
- データベース作成&拡張機能を有効に
- テーブルを作ってデータを追加する
- いろいろ遊んでみる。楽しい！

## Dockerfile、イメージの準備
一から環境を作るのは大変です。DockerのPostgreSQLイメージにRDKitを追加するためのDockerfileが、Git hubでいくつか公開されているのでこれらを使います。

https://github.com/rvianello/docker-postgres-rdkit/tree/master

この記事を書いた時点で更新が直近だったので今回は上のDockerFileを使いました。
これを適当なフォルダ(ここではD:\rdgresとします)に置き、Powershellで次のコマンドを順に実行します。

```powershell:Powershellで順番に実行
cd D:\rdgres # Dockerfileのあるフォルダに移動
docker image build -t rdgres . #イメージをビルド -t [名前] で好きな名前を付けられる。今回はrdgres
```

私の場合は、20-30分くらいビルドにかかりました。
無事終わったら次はイメージからコンテナを生成し動かします。

```powershell:コンテナを生成
docker run --name myrdgres -p 5432:5432 -e POSTGRES_PASSWORD=mypassword -d rdgres 
# --name コンテナ名 今回はmyrdgres
# -p [ホスト側のポート]:[コンテナ側のポート]
# -e 環境変数 
# -d バックグラウンド実行 [イメージ名]
```
念のため説明すると、runコマンドによってイメージからコンテナ(独立したプロセス)が生成され、稼働します。

## データベースの作成と拡張機能の適用
今、コンテナmyrdgresでpostgreSQLが動いている状態です。次にデータベースを作っていきます。
(以下では本来#である部分がコメントアウトにならないように全角文字に変更されています。)

```powershell:まずコンテナに入る
docker exec -it myrdgres /bin/bash #まずPowershellでこれを実行すると
>> root@aa0bb1234567:/＃ #こんな風になりコンテナ(PostgreSQL)のbashを操作できるようになる 
```

```powershell:データベースを作成
root@aa0bb1234567:/＃ psql -U postgres #ユーザーpostgresでpostgresqlにログイン 
postgres=＃ create database testdb; #データベース作成
postgres=＃ \l #データベースが作成できてるか確認
```
新しいデータベース(ここではtestdb)が追加されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/9e39933a-bee0-57f3-4008-fc81326105fa.png)

次にRDKitの拡張機能をtestdbに追加します。

```powershell:拡張機能の適用
postgres=＃ \q #一旦出る
root@aa0bb1234567:/＃ psql -c 'CREATE EXTENSION rdkit' testdb -U postgres #拡張機能適用
CREATE EXTENSION
root@aa0bb1234567:/＃ psql testdb -U postgres #testdbにログイン
testdb=＃ \dx #確認
```
うまくっていればrdkitがtestdbの拡張機能に追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/8646ebdf-c94e-a5d1-53ac-aff51fdf7cce.png)

## テーブルを作ってデータを追加する
次にテーブルを作っておきます。そのままの画面から、下記のコマンドでテーブルを作成します。
```powershell:テーブルの作成
testdb=＃ CREATE TABLE compounds (
id serial PRIMARY KEY,
name TEXT,
mol_weight REAL,
xlogp REAL,
smiles TEXT);
```

続いて化学構造の情報を含むデータを入れていきます。
今回はpubchemからダウンロードしたcsvデータをてきとうに成形したものを使います。構造式検索をしたいため、smiles列を残してあります。

[compound.csv]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/b0f77132-5e26-0296-9c09-01effbfc6452.png)


このデータをdockerコマンドでコンテナ内に送ります。コンテナの外から操作したいので、これまで操作していたものとは別にpowershellを立ち上げます。
```powershell:新しく立ち上げたpowershell
docker cp (ホストPC側のファイルパス)/compound.csv myrdgres(コンテナ名):/tmp/data.csv
#Successfully copied ookB to myrdgres:/tmp/data.csv
```
そうしたらこちらのPowershellはもう使わないので閉じてしまって、先ほどまでpostgreSQLを操作していたほうのPowershellでCOPYコマンドでテーブルにデータを追加します。

```Powershell:テーブルへのデータのコピー
testdb=＃\COPY compounds(name,mol_weight,xlogp,smiles) FROM '/tmp/data.csv' DELIMITER ',' CSV HEADER;
#COPY 1000
```

```sql:データの確認
SELECT name,smiles FROM compounds;
```
データを追加できてました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/5f90c0f2-4fe5-9466-fda1-80cae92108f1.png)

## いろいろ遊んでみる
RDKitカートリッジならではの構造検索を使って遊んでみます。

### 部分構造検索
```sql:SQL
SELECT * FROM compounds where smiles @> 'C1=CC=C(C=C1)C(=O)O'
ORDER BY mol_weight ASC;

# 安息香酸骨格を含む構造、分子量小さい順
```
できた！楽しい！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/1ffdd6d2-73cc-327b-4d61-a16cae54d3ea.png)


### 類似構造検索
```sql:SQL
SELECT *, tanimoto_sml(rdkit_fp(smiles), rdkit_fp('CCCCOC(=O)C1=CC=CC=C1C(=O)OCCCC')) as tani
FROM compounds
WHERE tanimoto_sml(rdkit_fp(smiles), rdkit_fp('CCCCOC(=O)C1=CC=CC=C1C(=O)OCCCC')) > 0.8
ORDER BY tani DESC;

#ジブチルフタレートっぽい構造、似てる順(谷本類似度順)
```
できた！すごい！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/8dbeba90-7104-67f1-1f73-c68f1c78d0fb.png)



非常に楽しめました。RDKit+pythonで接続したりするともっと楽しいことができそうですね。

## 参考にしたサイト
https://web.chaperone.jp/w/index.php?RDKit/Cartridge