ほぼ老人のプログラミング日記

定年後の平凡なサラリーマンの趣味の日記

Knowledge→GROWI 移行 (1)

移行元データを探る

さて、

tiger62shin.hatenablog.com

にも書きましたが、個人で利用している情報共有サービスを Knowledge - Free knowledge base system から OSS開発wikiツールのGROWI に移行する話を進めていきます。

まずは、Knowledge のデータベースから移行元のデータ (本文と添付ファイル) を探っていきます。

Knowledge のデータベースは PostgreSQL なのでクライアントアプリケーションである psql を使って接続します。

$ psql -U postgres -d knowledge
psql (11.14 (Debian 11.14-0+deb10u1))
"help" でヘルプを表示します。

knowledge=>

テーブルの一覧を確認してみます

knowledge=> \dt;
                      リレーション一覧
 スキーマ |            名前             |    型    | 所有者
----------+-----------------------------+----------+---------
 public   | access_logs                 | テーブル | kbadmin
 public   | account_images              | テーブル | kbadmin
 public   | activities                  | テーブル | kbadmin
 public   | badges                      | テーブル | kbadmin
 public   | comments                    | テーブル | kbadmin
 public   | confirm_mail_changes        | テーブル | kbadmin
 public   | draft_item_values           | テーブル | kbadmin
 public   | draft_knowledges            | テーブル | kbadmin
 public   | events                      | テーブル | kbadmin
 public   | functions                   | テーブル | kbadmin
 public   | groups                      | テーブル | kbadmin
 public   | hash_configs                | テーブル | kbadmin
 public   | item_choices                | テーブル | kbadmin
 public   | knowledge_edit_groups       | テーブル | kbadmin
 public   | knowledge_edit_users        | テーブル | kbadmin
 public   | knowledge_files             | テーブル | kbadmin
 public   | knowledge_groups            | テーブル | kbadmin
 public   | knowledge_histories         | テーブル | kbadmin
 public   | knowledge_item_values       | テーブル | kbadmin
 public   | knowledge_tags              | テーブル | kbadmin
 public   | knowledge_users             | テーブル | kbadmin
 public   | knowledges                  | テーブル | kbadmin
 public   | ldap_configs                | テーブル | kbadmin
 public   | like_comments               | テーブル | kbadmin
 public   | likes                       | テーブル | kbadmin
 public   | locales                     | テーブル | kbadmin
 public   | login_histories             | テーブル | kbadmin
 public   | mail_configs                | テーブル | kbadmin
 public   | mail_hook_conditions        | テーブル | kbadmin
 public   | mail_hook_ignore_conditions | テーブル | kbadmin
 public   | mail_hooks                  | テーブル | kbadmin
 public   | mail_locale_templates       | テーブル | kbadmin
 public   | mail_posts                  | テーブル | kbadmin
 public   | mail_properties             | テーブル | kbadmin
 public   | mail_templates              | テーブル | kbadmin
 public   | mails                       | テーブル | kbadmin
 public   | notices                     | テーブル | kbadmin
 public   | notification_status         | テーブル | kbadmin
 public   | notifications               | テーブル | kbadmin
 public   | notify_configs              | テーブル | kbadmin
 public   | notify_queues               | テーブル | kbadmin
 public   | participants                | テーブル | kbadmin
 public   | password_resets             | テーブル | kbadmin
 public   | pins                        | テーブル | kbadmin
 public   | point_knowledge_histories   | テーブル | kbadmin
 public   | point_user_histories        | テーブル | kbadmin
 public   | provisional_registrations   | テーブル | kbadmin
 public   | proxy_configs               | テーブル | kbadmin
 public   | read_marks                  | テーブル | kbadmin
 public   | role_functions              | テーブル | kbadmin
 public   | roles                       | テーブル | kbadmin
 public   | service_configs             | テーブル | kbadmin
 public   | service_locale_configs      | テーブル | kbadmin
 public   | stock_knowledges            | テーブル | kbadmin
 public   | stocks                      | テーブル | kbadmin
 public   | survey_answers              | テーブル | kbadmin
 public   | survey_choices              | テーブル | kbadmin
 public   | survey_item_answers         | テーブル | kbadmin
 public   | survey_items                | テーブル | kbadmin
 public   | surveys                     | テーブル | kbadmin
 public   | system_attributes           | テーブル | kbadmin
 public   | system_configs              | テーブル | kbadmin
 public   | systems                     | テーブル | kbadmin
 public   | tags                        | テーブル | kbadmin
 public   | template_items              | テーブル | kbadmin
 public   | template_masters            | テーブル | kbadmin
 public   | tokens                      | テーブル | kbadmin
 public   | user_alias                  | テーブル | kbadmin
 public   | user_badges                 | テーブル | kbadmin
 public   | user_configs                | テーブル | kbadmin
 public   | user_groups                 | テーブル | kbadmin
 public   | user_notifications          | テーブル | kbadmin
 public   | user_roles                  | テーブル | kbadmin
 public   | users                       | テーブル | kbadmin
 public   | view_histories              | テーブル | kbadmin
 public   | votes                       | テーブル | kbadmin
 public   | webhook_configs             | テーブル | kbadmin
 public   | webhooks                    | テーブル | kbadmin
(78 行)

knowledge=>

たくさんありますね。この中から名前から想像してめぼしいものをピックアップします。

  • knowledge_files
  • knowledges
  • draft_knowledges

一つ一つ、確認していきます。knowledge_files はたぶん添付ファイルだと思うので、後回しにします。
knowledges のカラムを確認

knowledge=> \d knowledges;
                                                テーブル "public.knowledges"
       列        |             型              | 照合順序 | Null 値を許容 |                    デフォルト
-----------------+-----------------------------+----------+---------------+--------------------------------------------------
 knowledge_id    | bigint                      |          | not null      | nextval('knowledges_knowledge_id_seq'::regclass)
 title           | character varying(1024)     |          | not null      |
 content         | text                        |          |               |
 public_flag     | integer                     |          |               |
 tag_ids         | character varying(1024)     |          |               |
 tag_names       | text                        |          |               |
 like_count      | bigint                      |          |               |
 comment_count   | integer                     |          |               |
 view_count      | bigint                      |          |               |
 type_id         | integer                     |          |               |
 notify_status   | integer                     |          |               |
 point           | integer                     |          | not null      | 0
 anonymous       | integer                     |          |               |
 insert_user     | integer                     |          |               |
 insert_datetime | timestamp without time zone |          |               |
 update_user     | integer                     |          |               |
 update_datetime | timestamp without time zone |          |               |
 delete_flag     | integer                     |          |               |
インデックス:
    "knowledges_pkc" PRIMARY KEY, btree (knowledge_id)

knowledge=>

knowledge_id, title, content, tag_names あたりが怪しそうなので、下の画像の記事を確認してみます

f:id:tiger62shin:20220128170301p:plain

knowledge=> select knowledge_id, title, content, tag_names from knowledges where knowledge_id = 235;

f:id:tiger62shin:20220128170638p:plain

移行に必要なデータ「見出し」、「本文」、「タグ」はここから取り出せそうです。
実はこのことは後から気付いたのですが、delete_flag をたてて論理削除されているデータがあるようです。まず、delete_flag がどのような値を取るかを確認します。

knowledge=> select delete_flag, count(*) from knowledges group by delete_flag;
 delete_flag | count 
-------------+-------
           0 |   234
           1 |     5
(2 行)

予想通り '1' で削除されているようです。なので、移行に必要なデータを取り出す SQL

select knowledge_id, title, content, tag_names from knowledges where delete_flag = 0;

のようになりそうです。


draft_knowledges は下書きと思います。同じようにして確認していきます。

knowledge=> \d draft_knowledges;
                                              テーブル "public.draft_knowledges"
       列        |             型              | 照合順序 | Null 値を許容 |                     デフォルト
-----------------+-----------------------------+----------+---------------+----------------------------------------------------
 draft_id        | bigint                      |          | not null      | nextval('draft_knowledges_draft_id_seq'::regclass)
 knowledge_id    | bigint                      |          |               |
 title           | character varying(1024)     |          | not null      |
 content         | text                        |          |               |
 public_flag     | integer                     |          |               |
 accesses        | text                        |          |               |
 editors         | text                        |          |               |
 tag_names       | text                        |          |               |
 type_id         | integer                     |          |               |
 insert_user     | integer                     |          |               |
 insert_datetime | timestamp without time zone |          |               |
 update_user     | integer                     |          |               |
 update_datetime | timestamp without time zone |          |               |
 delete_flag     | integer                     |          |               |
インデックス:
    "draft_knowledges_pkc" PRIMARY KEY, btree (draft_id)

knowledge=>

knowledges と同じように draft_id, title, content, tag_names があるのでここから取り出せそうです。下書きの ID は別になっていることに加え knowledge_id というカラムがあります。内容を確認してみます。

knowledge=> select knowledge_id from draft_knowledges;
 knowledge_id
--------------
            0
            0
            0
            0
            0
            0
            0
            0
            0
            0
            0




          230
(16 行)

たいていは 0 か null みたいですが、1 つだけ値が入ってます。draft_knowledges.knowledge_id の値で knowledges の方を確認してみます。

knowledge=> select knowledge_id, title, content, tag_names from knowledges where knowledge_id = 230;

つまり、「公開されている記事の下書き」の公開されている記事の ID が入っているようです。1 つしかないし、内容も忘れているのでこの下書きの記事は移行しないことにしました
このような SQL で下書きのデータは取り出せそうです。knowledges と同様に論理削除されているデータは除外しています。

knowledge=> select draft_id, title, content, tag_names from draft_knowledges where (knowledge_id is null or knowledge_id not in (select knowledge_id from knowledges)) and delete_flag = 0;


次は添付ファイルです
同様にカラムを確認します

knowledge=> \d knowledge_files;
                                              テーブル "public.knowledge_files"
       列        |             型              | 照合順序 | Null 値を許容 |                    デフォルト                    
-----------------+-----------------------------+----------+---------------+--------------------------------------------------
 file_no         | bigint                      |          | not null      | nextval('knowledge_files_file_no_seq'::regclass)
 knowledge_id    | bigint                      |          |               | 
 comment_no      | bigint                      |          |               | 
 draft_id        | bigint                      |          |               | 
 file_name       | character varying(256)      |          |               | 
 file_size       | double precision            |          |               | 
 file_binary     | bytea                       |          |               | 
 parse_status    | integer                     |          | not null      | 
 insert_user     | integer                     |          |               | 
 insert_datetime | timestamp without time zone |          |               | 
 update_user     | integer                     |          |               | 
 update_datetime | timestamp without time zone |          |               | 
 delete_flag     | integer                     |          |               | 
インデックス:
    "knowledge_files_pkc" PRIMARY KEY, btree (file_no)
    "idx_knowledge_files_knowledge_id" btree (knowledge_id)

knowledge=> 

knowledge_id または draft_id 毎に file_no で識別されるファイルが格納されているようです。file_name にファイル名、file_size にファイルのサイズ、file_binary にファイル本体があるようです。
試しに SQL だけでファイルを取りだしてみようとして、Google で検索した結果、下記のサイトを見つけました

kenpg.bitbucket.io

COPY コマンドでバイナリデータをファイルに出力することはできるが、ファイルの先頭に 25 byte 分のヘッダがついているようです。

copy (select file_binary from knowledge_files where file_name = 'clip-20210606104110.png') to '/var/lib/postgresql/clip-20210606104110.png' (format binary);

Mac で使用できるバイナリエディタを持っていなかったので Windows の Stirling というバイナリエディタを使ってファイルの先頭 25 byte を削ってみました。

f:id:tiger62shin:20220128214336p:plain

Postfix をインストールしたときのスクリーンショットのようです。
これで添付ファイルも取り出せることがわかりました。

本文と添付ファイルとの関係も確認しておこうと思います。上の添付ファイルは下図の記事の赤枠で囲った部分の添付ファイルと思います

f:id:tiger62shin:20220128224211p:plain

knowledge=> select file_no, knowledge_id, file_name from knowledge_files where file_name = 'clip-20210606104110.png';
 file_no | knowledge_id |        file_name
---------+--------------+-------------------------
     556 |          236 | clip-20210606104110.png
(1 行)

knowledge=>

#236 の記事に添付されている 556 番のファイルということで間違いなさそうです。実際の記事はこんな感じです。

f:id:tiger62shin:20220128224717p:plain


次は、これらの SQLPython プログラムから実行するサンプルを作ります。