Nova postagem

Pesquisar

Artigo
· Maio 16, 2024 27min de leitura

オンラインバックアップの仕組みとバックアップとリストア方法について

この記事は、「インターシステムズ製品をバックアップする前に確認したいこと」に続く記事で、InterSystems製品のバックアップの手法の中の「オンラインバックアップ」の仕組みと、バックアップ・リストア手順について解説します。

オンラインバックアップは、InterSystems製品が用意するバックアップ機能を利用する方法で、バックアップ対象に設定した全データベースの使用済ブロックをバックアップする方法です。

InterSystems製品のデータベースには、サーバ側で記述したコード、テーブル定義/クラス定義、データ(レコード、永続オブジェクト、グローバル)が格納されていますので、これらすべてが1つのファイルにバックアップされます。

データ量が増えればバックアップファイルサイズも大きくなります。 また、データ量の増加に伴いバックアップ時間も長くなります。

バックアップ時間に制限のない環境や、ユーザからのアクセスがない環境(例:ディザスタリカバリの目的で配置しているミラーリングの非同期メンバ)のバックアップ方法としては最適ですが、バックアップ時間に制限がある場合は不向きです。

バックアップ時間をできるだけ短くしたい場合は、推奨方法である「外部バックアップ」や、手順が少し複雑になりますが「並行外部バックアップ」を取り入れるなどご検討ください。

外部バックアップもオンラインでバックアップが行えますが、バックアップ方法が異なります。

 

オンラインバックアップの仕組み

ユーザプロセスが停止しない仕組みを作るため、オンラインバックアップでは、3つのパスに分けてバックアップを実行しています。

データベースリストに複数のデータベースが含まれている場合は、パス毎にすべてのデータベースのバックアップを実行します。

✅最初のパス

バックアップ開始時点で使用されているすべてのブロックをバックアップします。開始以降に更新が発生したブロックは、バックアップ・ビットマップに記録して次のパス以降でバックアップできるようにします。

✅2番目~n番目のパス

バックアップ・ビットマップに記録された、前のパス開始以降に変更のあったブロックを処理します。このパスは変更ブロックが少なくなるまで実行されます。

✅最後のパス

前のパス開始以降に変更のあったブロックを処理しますが、最後のパスが完了するまでの間ライトデーモン(WRTDMN)を一時停止させてこれ以上の更新が発生しないようにしてすべての更新を処理します。

 

以下のログは、2つのデータベースをデータベースリストに設定したときのフルバックアップ時のログです。

最初のパス

*** The time is: 2024-04-25 09:42:06 ***

              InterSystems IRIS Backup Utility
              --------------------------------
Performing a Full backup.
Backing up to device: /usr/irissys/mgr/backup/FullDBList_20240425_001.cbk
Description
Full backup of all databases that are in the backup database list.


Backing up the following directories:
 /usr/irissys/mgr/t1/
 /usr/irissys/mgr/user/


Journal file switched to:
/usr/irissys/mgr/journal/20240425.002


Starting backup pass 1
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 09:42:07
Copied 14083 blocks in 0.287 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 09:42:07
Copied 194 blocks in 0.007 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 1 complete at 04/25/2024 09:42:07

それぞれデータベースの全てのバックアップ対象ブロックをバックアップファイルコピーしていることがわかります。

また、バックアップを開始する前にジャーナルファイルを切り替えていることが確認できます。

次に、2番目のパスです。

Starting backup pass 2
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 09:42:08
Copied 1 blocks in 0.001 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 09:42:08
Copied 1 blocks in 0.002 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 2 complete at 04/25/2024 09:42:08

2番目以降も、それぞれのデータベースの全ての変更ブロックをバックアップファイルにコピーしていることがわかります。

次は、最後のパスです。

Starting backup pass 3

Journal file '/usr/irissys/mgr/journal/20240425.002' and the subsequent ones are required for recovery purpose if the backup were to be restored

Journal marker set at
offset 198264 of /usr/irissys/mgr/journal/20240425.002

 - This is the last pass - Suspending write daemon
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 09:42:10
Copied 1 blocks in 0.002 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 09:42:10
Copied 1 blocks in 0.002 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 3 complete at 04/25/2024 09:42:10

***FINISHED BACKUP***

Global references are enabled.

Backup complete.

最後のパスでは、- This is the last pass - Suspending write daemon のログがあり、ライトデーモン(WRTDMN)を一次停止させ全てのブロックをバックアップしていることがわかります。

3つのパスは以下で解説するオンラインバックアップの種類に関わらず必ず実行されます。

 

オンラインバックアップの種類

オンラインバックアップには、フルバックアップ/累積バックアップ/差分バックアップの3種類のバックアップ方法があります。

バックアップ時間については、フルバックアップよりも累積バックアップ、累積バックアップよりも差分バックアップが短くなりますが、累積バックアップと差分バックアップを行うためには、必ず事前にフルバックアップを取得する必要があります。

なるべくバックアップ時間が短くなるように3種類のバックアップ方法を組み合わせて利用する事もできます。

累積バックアップ・差分バックアップの違いや組み合わせ例については、コミュニティの記事「累積バックアップと差分バックアップの違いについて」をご参照ください。

 

オンラインバックアップの事前準備

データベースのバックアップリストを作成する必要があります。

作成は、管理ポータルから、またはAPIから行えます。

✅管理ポータルから作成する場合

管理ポータル > [システム管理] > [構成] > [データベースバックアップ] > [データベース・バックアップ・リスト] で設定します。

✅APIで作成する場合

BackUp.GeneralAddDatabaseToList()ClearDatabaseList()RemoveDatabaseFromList()を利用します。

管理ポータルのデータベースリストを一旦クリアし、データベースUSERとT1を追加する例は以下の通りです。(%SYSネームスペースで実行します)

実行が成功するとステータスOKとして1が返ります($$$OK)。

// 既存のデータベースリストをクリアする
set status=##class(Backup.General).ClearDatabaseList()
write status

// T1とUSERをデータベースリストに追加する。
set status=##class(Backup.General).AddDatabaseToList("USER")
write status
set status=##class(Backup.General).AddDatabaseToList("T1")
write status

 

オンラインバックアップの取得方法

管理ポータルには、手動で行うバックアップメニューとタスクスケジュールに設定しておけるバックアップメニューがあります。

プログラムから実行する場合は、BACKUP^DBACKルーチンを使用します。

以下順序で解説します。

1. 管理ポータルのバックアップメニュー

2. 管理ポータルのタスクスケジュール

3. ^BACKUPルーチン

4. BACKUP^DBACKルーチン

※上記方法で実行する前にバックアップ対象データベースを「バックアップリスト」に指定する必要があります。詳しくはオンラインバックアップの事前準備をご参照ください。

 

1.管理ポータルのバックアップメニュー

管理ポータル > [システムオペレーション] > [バックアップ] からバックアップを実行できます。

メニューの「すべてのデータベースのフルバックアップ」は、インストール環境のすべてのデータベースをバックアップします。

データベースリストで指定したデータベースのバックアップを行う場合は「フルバックアップのリスト」のメニューを選択してください。

以下、実際のバックアップを実行する画面です。画面内の「バックアップを保存するデバイス」に出力可能なディレクトリを指定してから実行してください。

バックアップログは「ログファイル」の場所に配置されます。

 

2.管理ポータルのタスクジュール

新しいタスクを作成するときに、オンラインバックアップ用タイプを指定してタスクを設定します。

管理ポータル > [システムオペレーション] > [タスクマネージャ] > [新しいタスク]

タイプは以下の通りです。

  • リストデータベースのインクリメンタルバックアップ
  • リストデータベースのフルバックアップ
  • リストデータベースの累積差分バックアップ

後は日時指定を行えば、指定の時刻に対象のバックアップを開始できます。

 

3.^BACKUPルーチン

システムルーチン^BACKUPは%SYSネームスペースに移動して実行します。

【注意】 バックアップ実行結果のログ出力を指定できないため、画面ログなどをご利用ください。

メニュー詳細についてはドキュメント「^BACKUP によるバックアップおよびリストアのタスクの実行」をご参照ください。

以下ルーチン実行例です。

Start the Backup (y/n)? => y 以降は前述:オンラインバックアップの仕組み で説明した各バックアップパスのログが出力されます。

%SYS>do ^BACKUP
1) Backup
2) Restore ALL
3) Restore Selected or Renamed Directories
4) Edit/Display List of Directories for Backups
5) Abort Backup
6) Display Backup volume information
7) Monitor progress of backup or restore

Option? 1
*** The time is: 2024-04-25 17:18:19 ***

              InterSystems IRIS Backup Utility
              --------------------------------
What kind of backup:
   1. Full backup of all in-use blocks
   2. Incremental since last backup
   3. Cumulative incremental since last full backup
   4. Exit the backup program
1 => 1
Specify output device (type STOP to exit)
Device: /usr/irissys/mgr/backup/FullDBList_20240425_001.cbk => /usr/irissys/mgr/backup/FullDBList_20240425_002.cbk
Backing up to device: /usr/irissys/mgr/backup/FullDBList_20240425_002.cbk
Description: ^BACKUPルーチンを利用したフルバックアップの実行
Backing up the following directories:
 /usr/irissys/mgr/t1/
 /usr/irissys/mgr/user/


Start the Backup (y/n)? => y
Journal file switched to:
/usr/irissys/mgr/journal/20240425.003


Starting backup pass 1
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 17:19:11
Copied 14083 blocks in 0.288 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 17:19:12
Copied 371 blocks in 0.017 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 1 complete at 04/25/2024 17:19:12

Starting backup pass 2
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 17:19:14
Copied 1 blocks in 0.002 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 17:19:14
Copied 1 blocks in 0.002 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 2 complete at 04/25/2024 17:19:14

Starting backup pass 3

Journal file '/usr/irissys/mgr/journal/20240425.002' and the subsequent ones are required for recovery purpose if the backup were to be restored

Journal marker set at
offset 197596 of /usr/irissys/mgr/journal/20240425.003

 - This is the last pass - Suspending write daemon
Backing up /usr/irissys/mgr/t1/ at 04/25/2024 17:19:15
Copied 1 blocks in 0.003 seconds

Finished this pass of copying /usr/irissys/mgr/t1/

Backing up /usr/irissys/mgr/user/ at 04/25/2024 17:19:15
Copied 1 blocks in 0.005 seconds

Finished this pass of copying /usr/irissys/mgr/user/

Backup pass 3 complete at 04/25/2024 17:19:15

***FINISHED BACKUP***

Global references are enabled.

Backup complete.


1) Backup
2) Restore ALL
3) Restore Selected or Renamed Directories
4) Edit/Display List of Directories for Backups
5) Abort Backup
6) Display Backup volume information
7) Monitor progress of backup or restore

Option?   //Enter押下
%SYS>

 

4.BACKUP^DBACK

システムルーチン^DBACKルーチンのBACKUPプロシージャを利用して、プログラムからバックアップを実行することができます。

引数詳細はドキュメント「BACKUP^DBACK」をご参照ください。

✅フルバックアップ

第2引数はフルバックアップのタイプである"F"を指定します。

第4引数はバックアップファイル名

第6引数はバックアップログのファイル名

第5、8、9はバックアップ開始後にジャーナルを切り替えるための指定のため"Y"(切り替える)を推奨しています。

第7引数は、実行時のカレントデバイスへの出力指定

set modori=$$BACKUP^DBACK("","F","フルバックアップの実行","/usr/irissys/mgr/backup/FullBackUp-DBACK-20240425.cbk","Y","/usr/irissys/mgr/backup/FullBackUp-DBACK-20240425.log","QUIET","Y","Y")

✅累積バックアップ

フルバックアップの実行例の第2引数に"C"を指定します。

✅差分バックアップ

フルバックアップの実行例の第2引数に"I"を指定します。

 

リストア方法

リストアは、システムルーチン^DBRESTを利用する方法と、プログラムから実行する方法を選択できます。

リストアはリストア時の確認項目が多いため、テスト環境などでリストアテストを実施いただくことを強く推奨します。

リストアにかかる時間についても、HW構成、リストア対象データベース数、データ量に依存するためリストアテストを行った際の計測値から予測いただくこととなります。

それでは、具体的な方法をご説明します。

 

システムルーチンを利用したリストア(手動)

システムルーチン^DBRESTを利用します。

または、^BACKUPルーチンの 2) Restore ALL または 3) Restore Selected or Renamed Directories からも実行できます。

%SYS>do ^DBREST
                        Cache DBREST Utility
         Restore database directories from a backup archive

Restore: 1. All directories
         2. Selected and/or renamed directories
         3. Display backup volume information
         4. Exit the restore program
    1 =>

リストアメニューについては、

1.All directories

バックアップファイルに含まれるデータベースすべてをリストアします。

画面表示例はドキュメント:^DBRESTによるすべてのデータベースのリストアをご参照ください。

2.Selected and/or renamed directories

バックアップファイルに含まれる一部のデータベースだけをリストアしたい場合、また、バックアップ時点のデータベースディレクトリと異なるディレクトリにリストアを行う場合に使用します。

参考ドキュメント:^DBREST による選択したデータベースまたは名前を変更したデータベースのリストア

 

以下例では、「2. Selected and/or renamed directories」を使用して、バックアップファイルに含まれるデータベースを選択し、別ディレクトリのデータベースにリストアする手順を説明します。

 

リストア実行例(データベースディレクトリ変更)

例ではバックアップファイルに以下データベースが含まれています。

  • USERデータベース= /usr/irissys/mgr/user
  • T1データベース=/usr/irissys/mgr/t1

以下例では、T1データベースのあるディスクが壊れたことを想定し、リストア時のT1データベースディレクトリがバックアップ時点とは異なるディレクトリにリストアしなくてはならない場合の流れで解説します。

なお、バックアップファイルのリストア後、ジャーナルファイルを利用したリストアも行う必要がありますので以下の流れで試していきます。

1、バックアップ前にT1データベースに任意データ登録する(^prebackup=1)

2、フルバックアップを実行する

3、切り替わったジャーナルファイル名を確認する

4、バックアップ後だとわかる任意データをT1データベースに登録する(^postbackup=1)

5、ジャーナルファイルに 4で登録した情報が含まれているか確認する

6、T1データベース(/usr/irissys/mgr/t1)を削除

7、T1データベースを別ディレクトリ(/usr/irissys/mgr/t1rest)に再作成

8、バックアップからのリストアを実行する

T1データベースのみリストアするように指定します。

  • バックアップ時点のディレクトリ:/usr/irissys/mgr/t1
  • リストア時に指定するディレクトリ:/usr/irissys/mgr/t1rest

9、^prebackup=1 が戻ることを確認する

10、ジャーナルリストアを実行

T1データベースのみリストアするように指定します。

  • バックアップ時点のディレクトリ:/usr/irissys/mgr/t1
  • リストア時に指定するディレクトリ:/usr/irissys/mgr/t1rest

11、^postbackup=1 が戻ることを確認する


 

1、バックアップ前にT1データベースに任意データ登録する(^prebackup=1)

ネームスペースT1に接続し、以下実行します。

Linuxやコンテナを利用されている場合は、iris session インスタンス名 -U T1でログインすると簡単です。

set $namespace="T1"
set ^prebackup=1

管理ポータルでデータを確認します。

[システムエクスプローラ] > [グローバル] > T1ネームスペース選択

グローバル変数名が多く一覧される場合、画面左端の「フィルタ」の「グローバル名」に pre* と書くとフィルタされた結果が表示されます。

 

2、フルバックアップを実行する

オンラインバックアップの取得方法のいずれかの方法を利用してフルバックアップを実行します。

例では管理ポータルメニューを利用しています。

以下の例で使用するバックアップファイル名は「/usr/irissys/mgr/Backup/FullDBList_20240426_001.cbk」です。

 

3、切り替わったジャーナルファイル名を確認する

管理ポータル > [システムオペレーション] > [ジャーナル] 「バックアップにより」切り替わったジャーナルファイルを確認します。

以下の例でジャーナルリストアの開始ファイルとして指定するファイル名は「/usr/irissys/mgr/journal/20240426.002」です。

 

4、バックアップ後だとわかる任意データをT1データベースに登録する(^postbackup=1)

ネームスペースT1に接続し、以下実行します。

Linuxやコンテナを利用されている場合は、iris session インスタンス名 -U T1でログインすると簡単です。

set $namespace="T1"
set ^postbackup=1
 

5、ジャーナルファイルに 4で登録した情報が含まれているか確認する  

管理ポータル > [システムオペレーション] > [ジャーナル] で現在のジャーナルファイルを開き、^postbackupが記録されているか確認します。

画面右端のデータベースディレクトリ名を確認し、「/usr/irissys/mgr/t1」で記録されていることを確認します。

 

6、T1データベース(/usr/irissys/mgr/t1)を削除

管理ポータルメニューから削除します。

稼働中に削除する場合、一旦データベースをディスマウントすることをお勧めします。

管理ポータル > [システムオペレーション] > [データベース] > T1を選択 > ディスマウントボタンをクリック

ディスマウント後、構成メニューに移動しデータベースを削除します。

管理ポータル > [システム管理] > [構成] > [システム構成] > [ローカルデータベース] > T1を削除


この削除時に ”チェックしたネームスペースを削除します” の T1 にチェックを入れてT1ネームスペースも削除します。

 

7、T1データベースを別ディレクトリ(/usr/irissys/mgr/t1rest)に再作成

管理ポータルでT1ネームスペース、データベースを作成します。

このときのデータベースは最初に作成したディレクトリとは異なるディレクトリで作成します。

例では、/usr/irissys/mgr/t1rest としています。


 

8、バックアップからのリストアを実行する

システムルーチン^DBRESTの例でご紹介します。

InterSystems製品にログインし、%SYSネームスペースに移動します。

Linuxやコンテナの場合はは、iris session インスタンス名 -U %SYS で%SYSネームスペースにログインできます。

set $namespace="%SYS"
do ^DBREST

画面で指定する内容は以下の通りです。

%SYS>do ^DBREST
                        Cache DBREST Utility
         Restore database directories from a backup archive

Restore: 1. All directories
         2. Selected and/or renamed directories
         3. Display backup volume information
         4. Exit the restore program
    1 => 2

バックアップファイルに含まれるデータベースを選択し、さらにディレクトリをリダイレクトしてリストアを実行するため、2を選択します。

続いて以下質問されます。

Do you want to set switch 10 so that other processes will be
prevented from running during the restore? Yes =>

リストア実行中 switch 10 を設定したいか?と聞かれています。switch 10 を設定するとカレントプロセス以外の他のプロセスからのRead/Writeを禁止します。

リストア実行中に他プロセスからのデータ参照・更新を防ぎたいときはYes(デフォルト)を指定します。(推奨)

この回答をYesにした場合、リストアが完了するまで管理ポータルを使用したり、新規のログインなどはできなくなります。

続いて、バックアップファイルを指定します。管理ポータルからバックアップを行ったため、バックアップ履歴より直近のフルバックアップファイル名を表示しています。

ディレクトリに変更がないか確認し正しい場合ははEnterを押下します。

異なる場合は、フルパスでフルバックアップのファイル名を指定します。

最終行にリストアを開始したいか?と質問されるので、Enter(またはYes)を押下します。

Specify input file for volume 1 of backup 1
 (Type STOP to exit)
Device: /usr/irissys/mgr/Backup/FullDBList_20240426_001.cbk =>

This backup volume was created by:
   IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2024.1

The volume label contains:
   Volume number      1
   Volume backup      APR 26 2024 11:36AM Full
   Previous backup    APR 25 2024 05:34PM Full
   Last FULL backup   APR 25 2024 05:34PM
   Description        Full backup of all databases that are in the backup database list.
   Buffer Count       0
Is this the backup you want to start restoring? Yes =>

続いて、バックアップファイルに含まれるデータベースディレクトリが出力されるので、同じディレクトリにリストアする場合はEnterを押下します。

今回は異なるディレクトリにリダイレクトしたいため、/usr/irissys/mgr/t1restを入力しています。

次に、もう1つのバックアップ対象である /usr/irissys/mgr/user のディレクトリが表示されます。リストア対象外に設定したいので、X(大文字)を入力します。

「(ここまで入力した)ディレクトリリストを変更したいか?」と質問されるので、変更不要の場合は、Noを入力します。

For each database included in the backup file, you can:

 -- press RETURN to restore it to its original directory;
 -- type X, then press RETURN to skip it and not restore it at all.
 -- type a different directory name.  It will be restored to the directory
    you specify.  (If you specify a directory that already contains a
    database, the data it contains will be lost).

/usr/irissys/mgr/t1/ => /usr/irissys/mgr/t1rest
/usr/irissys/mgr/user/ => X
Do you want to change this list of directories? No => no

リストアによりデータベースをオーバーライドするけど良いか?と質問されます。 リストアを開始してよい場合は、yesを入力します。

Restore will overwrite the data in the old database. Confirm Restore? No => yes

リストアが開始されます。

/usr/irissys/mgr/t1 を /usr/irissys/mgr/t1rest にリストアし、/usr/irissys/mgr/userはスキップされることが出力されています。

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 13:39:00
14085 blocks restored in 0.4 seconds for this pass, 14085 total restored.

Starting skip of /usr/irissys/mgr/user/.

     skipped 371 blocks in .011176 seconds.

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 13:39:00
1 blocks restored in 0.0 seconds for this pass, 14086 total restored.

Starting skip of /usr/irissys/mgr/user/.

     skipped 1 blocks in .000005 seconds.

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 13:39:00
1 blocks restored in 0.0 seconds for this pass, 14087 total restored.

Starting skip of /usr/irissys/mgr/user/.

     skipped 1 blocks in .000005 seconds.

今回のバックアップファイルに続きがあるかどうか確認されます。ない場合は STOP を入力します。

Specify input file for volume 1 of backup following APR 26 2024  11:36AM
 (Type STOP to exit)
Device: STOP

リストアしたいバックアップファイルがあるか再度確認されます。

利用例として、フルバックアップをリストア後に続けてインクリメンタル(差分)バックアップがあり、続けてリストアしたい場合にファイル名を指定できます。

リストアしたいファイルがある場合はYES(デフォルト)、ない場合は、Noを入力します。

Do you have any more backups to restore? Yes => no
Mounting /usr/irissys/mgr/t1rest/
    /usr/irissys/mgr/t1rest/  ... (Mounted)

/usr/irissys/mgr/t1rest がマウントされました。

通常、リストア対象データベースにはジャーナルファイルのリストアも行いますが、一旦、バックアップ時点に戻ったかどうか確認のため、練習の流れでは 4を選択し、ユーティリティを一旦終了しています。

Restoring a directory restores the globals in it only up to the
date of the backup.  If you have been journaling, you can apply
journal entries to restore any changes that have been made in the
globals since the backup was made.

What journal entries do you wish to apply?

     1. All entries for the directories that you restored
     2. All entries for all directories
     3. Selected directories and globals
     4. No entries

Apply: 1 => 4
%SYS>

リストア中 switch 10 の設定により、カレントプロセス以外のREAD/WRITEが禁止されます。

リストアを終了する場合、必ずシステムルーチンを終了し、%SYSのプロンプトが表示されている状態に戻してください。

 

9、^prebackup=1 が戻ることを確認する

管理ポータル > [システムエクスプローラ] > [グローバル] > T1ネームスペース選択

^prebackupは表示されますが、^postbackupがまだ戻っていないことを確認します。

 

10、ジャーナルリストアを実行

ジャーナルリストアの流れは、「外部バックアップの仕組みとバックアップとリストア方法について:10、ジャーナルリストア」をご参照ください。

 

11、^postbackup=1 が戻ることを確認する

管理ポータル > [システムエクスプローラ] > [グローバル] > T1ネームスペース選択

^postbackupが存在するか確認します。

 

プログラムによるリストア

✅EXTALL^DBREST

バックアップファイルに含まれるすべてのデータベースをリストアできます。

また、例では、バックアップファイルに含まれるデータベースのバックアップファイルからのリストアとジャーナルファイルのリストアを行っています。

引数詳細については、ドキュメントの^DBRESTによる自動リストアをご参照ください。

例では、以下の引数を指定します。

  • 第1引数:1を指定(非インタラクティブモードであることを指定)
  • 第2引数:0を指定(リストア処理中に更新を許可しない)
  • 第3引数:バックアップファイル名を指定
  • 第4引数:このシナリオでは指定なし
  • 第5引数:1を指定(ジャーナルをリストアするためのオプションで、1はバックアップをリストアしたすべてのディレクトリを指定)
  • 第6引数:バックアップリストア後にリストアしたいジャーナルファイル名

実行例は以下の通りです。

%SYS>do EXTALL^DBREST(1,0,"/usr/irissys/mgr/Backup/FullDBList_20240426_001.cbk",,1,"/usr/irissys/mgr/journal/20240426.002",1)

The following directories will be restored:
/usr/irissys/mgr/t1/ =>
/usr/irissys/mgr/user/ =>

Expanding /usr/irissys/mgr/t1/ from 1 MB to 114 MB

***Restoring /usr/irissys/mgr/t1/ at 14:45:30
14085 blocks restored in 0.8 seconds for this pass, 14085 total restored.

***Restoring /usr/irissys/mgr/user/ at 14:45:31
371 blocks restored in 0.0 seconds for this pass, 371 total restored.

***Restoring /usr/irissys/mgr/t1/ at 14:45:31
1 blocks restored in 0.0 seconds for this pass, 14086 total restored.

***Restoring /usr/irissys/mgr/user/ at 14:45:31
1 blocks restored in 0.0 seconds for this pass, 372 total restored.

***Restoring /usr/irissys/mgr/t1/ at 14:45:31
1 blocks restored in 0.0 seconds for this pass, 14087 total restored.

***Restoring /usr/irissys/mgr/user/ at 14:45:31
1 blocks restored in 0.0 seconds for this pass, 373 total restored.

Mounting /usr/irissys/mgr/t1/
    /usr/irissys/mgr/t1/  ... (Mounted)

Mounting /usr/irissys/mgr/user/
    /usr/irissys/mgr/user/  ... (Mounted)


We know something about where journaling was at the time of the backup:
0: offset 196976 in /usr/irissys/mgr/journal/20240426.002
/usr/irissys/mgr/journal/20240426.002
Journal reads completed. Applying changes to databases...
20.00%  40.00%  60.00%  80.00% 100.00%100.00%
***Journal file finished at 14:45:33

 

✅EXTSELCT^DBREST

バックアップファイルに含まれるデータベースディレクトリを指定したリストア、またディレクトリ先を指定したリストアが行えます。

以下の実行例は、/usr/irissys/mgr/t1 で記録されていた情報を /usr/irissys/mgr/t1rest にリストアしています。

このラベル名からのジャーナルリストアは、リダイレクト先が指定できません。以下の例では、バックアップからのリストアだけで終了するようにしています。

例では、以下の引数を指定します。

  • 第1引数:1を指定(非インタラクティブモードであることを指定)
  • 第2引数:0を指定(リストア処理中に更新を許可しない)
  • 第3引数:バックアップファイル名を指定
  • 第4引数:リストア先ディレクトリを含むファイル名 ファイルには、以下指定します。
    ソースディレクトリ,ターゲットディレクトリ,ターゲットディレクトリが存在しないとき作成するかどうかのY/Nのどちらか
    
  • 第5引数:4を指定(ジャーナルリストア指定しない)

事前に第4引数のファイルを準備します。ファイルには以下の記載をしています。

$ cat restdir.txt
/usr/irissys/mgr/t1/,/usr/irissys/mgr/t1rest/,N

以下実行例です。バックアップファイルから /usr/irissys/mgr/t1 を /usr/irissys/mgr/t1rest にリダイレクトしてリストアしていますが、ジャーナルリストアは行われていません。

%SYS>do EXTSELCT^DBREST(1,0,"/usr/irissys/mgr/Backup/FullDBList_20240426_001.cbk","/usr/irissys/mgr/Backup/restdir.txt",4)

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 15:06:39
14085 blocks restored in 0.2 seconds for this pass, 14085 total restored.

Starting skip of /usr/irissys/mgr/user/.

    skipped 371 blocks in .006246 seconds.

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 15:06:39
1 blocks restored in 0.0 seconds for this pass, 14086 total restored.

Starting skip of /usr/irissys/mgr/user/.

    skipped 1 blocks in .00001 seconds.

***Restoring /usr/irissys/mgr/t1/ to /usr/irissys/mgr/t1rest/ at 15:06:39
1 blocks restored in 0.0 seconds for this pass, 14087 total restored.

Starting skip of /usr/irissys/mgr/user/.

    skipped 1 blocks in .000008 seconds.

Mounting /usr/irissys/mgr/t1rest/
    /usr/irissys/mgr/t1rest/  ... (Mounted)

[Journal not applied to any directory]

%SYS>

現時点では、/usr/irissys/mgr/t1rest のデータベースには ^postbackupが存在しませんん。

選択したデータベースディレクトリをリダイレクトしながらジャーナルリストアを行うには、Journal.Restoreクラスを利用します。

 

ジャーナルファイルのリストア

ジャーナルファイルに記録されている  /usr/irissys/mgr/t1 の情報を /usr/irissys/mgr/t1rest にリストアする例でご紹介します。

サンプルコード:ZRestore.Journal

(メソッド、プロパティの使い方についてはサンプルコードのコメント文をご確認ください。)

Class ZRestore.Journal
{

ClassMethod RedirectTest() As %Status
{
    #dim ex As %Exception.AbstractException
    set status=$$$OK
    try {
        #;ジャーナルリストア用インスタンス生成
        set jrnrest=##class(Journal.Restore).%New()
        
        #;リストアのジャーナルファイルを指定します
        #; CurrentFileは以下メソッドで取得可
        #; ##class(%SYS.Journal.System).GetCurrentFile().Name
        set jrnrest.FirstFile="/usr/irissys/mgr/journal/20240426.002"
        #;LastFileの指定がない場合は最後のファイルまでリストアします
        set jrnrest.LastFile="/usr/irissys/mgr/journal/20240426.002"
        #;ジャーナルディレクトリの設定(カレントインスタンスのジャーナルを利用する場合の例)
        #; UseJournalLocation() ジャーナルディレクトリを指定するメソッド
	    #; 現在のプライマリディレクトリの場所を指定する場合は、メソッドで場所を特定できる
	    set location1=##class(%SYS.Journal.System).GetPrimaryDirectory()
	    do jrnrest.UseJournalLocation(location1)
	    set location2=##class(%SYS.Journal.System).GetAlternateDirectory()
	    do jrnrest.UseJournalLocation(location2)

        #; ソースDBとターゲットDBの指定
        #; ディレクトリは全て小文字で記載する+末尾のパスのマーク必須
        set source="/usr/irissys/mgr/t1/"
        set target="/usr/irissys/mgr/t1rest/"
        #; リストア対象データベースの指定
        $$$ThrowOnError(jrnrest.SelectUpdates(source))
        #; リダイレクト先の指定 
        $$$ThrowOnError(jrnrest.RedirectDatabase(source,target))

        #; ジャーナルの整合性チェック
	    $$$ThrowOnError(jrnrest.CheckJournalIntegrity(1)) 

        #; リストア実行
        $$$ThrowOnError(jrnrest.Run())
    }
    catch ex {
        set status=ex.AsStatus()
    }
    return status
}

}

 

サンプルコード実行例

%SYS>set status=##class(ZRestore.Journal).RedirectTest()

Journal file being applied: /usr/irissys/mgr/journal/20240426.002
/usr/irissys/mgr/journal/20240426.002
  2.91% 100.00%
[Journal restore completed at 20240426 15:38:32]

The following databases have been updated:

1. /usr/irissys/mgr/t1rest/

%SYS>

 

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Maio 16, 2024 2min de leitura

Busca de empresas usando Vector Search.

A introdução da "Pesquisa Vetorial" da InterSystems marca uma mudança de paradigma no processamento de dados. Esta tecnologia de ponta emprega um modelo de incorporação para transformar dados não estruturados, como texto, em vetores estruturados, resultando em capacidades de pesquisa significativamente aprimoradas. Inspirados por esta inovação, desenvolvemos um motor de busca especializado e adaptado às empresas.

Aproveitamos a inteligência artificial generativa para gerar resumos abrangentes dessas empresas, oferecendo aos usuários uma ferramenta poderosa e informativa.

Companies Search é uma API REST que aproveita o InterSystems Vector Search para extrair informações da empresa de um banco de dados vetorial usando palavras-chave. Este banco de dados, proveniente de um conjunto de dados Kaggle Glassdoor Job Review, passou por conversão para formato vetorial.

Uma vez identificadas as empresas por meio da busca vetorial, elas passam pelo processo de sumarização, onde uma IA generativa elabora um resumo com base em todos os comentários recebidos pela empresa no conjunto de dados, e não apenas naqueles identificados. 

Em essência, a API serve como uma porta de entrada para que os usuários obtenham rapidamente insights sobre as empresas, facilitando com facilidade possíveis colaborações ou avaliações de serviços.

Solução:

Para facilitar o entendimento, apresentamos abaixo o diagrama de sequência, que detalha as ações realizadas quando um usuário faz uma solicitação à API.

   

Implemente:

Agora, você pode aproveitar essa API para encontrar empresas de forma rápida e eficiente, integrando-a perfeitamente ao seu site para aprimorar a experiência do usuário. Transforme a busca de empresas em um processo ágil e preciso, aumentando o engajamento e a satisfação dos seus visitantes.:

https://openexchange.intersystems.com/package/companies-search

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Maio 16, 2024 2min de leitura

Search for companies using smart search engines

The introduction of InterSystems' "Vector Search" marks a paradigm shift in data processing. This cutting-edge technology employs an embedding model to transform unstructured data, such as text, into structured vectors, resulting in significantly enhanced search capabilities. Inspired by this breakthrough, we've developed a specialized search engine tailored to companies.

We harness generative artificial intelligence to generate comprehensive summaries of these companies, delivering users a powerful and informative tool.

Companies Search is a API REST, harnesses InterSystems Vector Search to extract company information from a vector database using keywords. This database, sourced from a Kaggle dataset Glassdoor Job Reviewunderwent conversion into vector format.

Once company are identified through vector search, they undergo the summarization process, where a Generative AI crafts a summary based on all comments received by the company in dataset, not just those identified. 

In essence, the API serves as a gateway for users to swiftly gain insights into companies, facilitating potential collaborations or service assessments with ease.

Solution:

To facilitate understanding, we present the sequence diagram below, which details the actions performed when a user makes a request to the API.

 

Enjoy:

Now, you can leverage this API to find businesses quickly and efficiently, seamlessly integrating it into your website to enhance the user experience. Transform the company search into an agile and accurate process, increasing the engagement and satisfaction of your visitors.:

https://openexchange.intersystems.com/package/companies-search

1 Comment
Discussão (1)1
Entre ou crie uma conta para continuar
Pergunta
· Maio 16, 2024

Iris Client on MacOS - how to run it after installation

Hi,

I have succesfully installed IRIS client on MacOS (see bottom half of this post).  What's next?  How do I access the menu to launch IRIS Client, access Studio, and connect to remote server etc??

Thanks,

W

----------------------------------------------------------------------------------------------------------

$$> sudo sh /Users/xxx/Downloads/HealthConnect-2023.1.3.517.0-macx64/irisinstall_client

Password:

Your system type is 'Mac OS X/x86/64-bit'.

Enter a destination directory for client components.

Directory: /Users/xxx/InterSystems/Iris_Client

Directory '/Users/xxx/InterSystems/Iris_Client' does not exist.

Do you want to create it <Yes>?  yes

Installation completed successfully

1 Comment
Discussão (1)2
Entre ou crie uma conta para continuar
Artigo
· Maio 16, 2024 9min de leitura

Similaridade e Classificação de DNA por Vector Search e Machine Learning

DNA Similarity and Classification é uma API REST utilizando a tecnologia InterSystems Vector Search para investigar semelhanças genéticas e classificar eficientemente sequências de DNA. Este é um aplicativo que utiliza técnicas de inteligência artificial, como aprendizado de máquina, aprimorado por recursos de pesquisa vetorial, para classificar famílias genéticas e identificar DNAs semelhantes conhecidos a partir de um DNA de entrada desconhecido.

Análise K-mer: Fundamentos em Análise de Sequência de DNA

A fragmentação de uma sequência de DNA em k-mers é uma técnica fundamental no processamento de dados genéticos. Esta abordagem envolve quebrar a sequência de DNA em subsequências menores de tamanho fixo, conhecidas como k-mers. Por exemplo, se tomarmos a sequência "ATCGTAGCTA" e definirmos k como 3, obteremos os seguintes k-mers: "ATC", "TCG", "CGT", "GTA", "TAG", "AGC", "GCT" e "CTA".

Este processo é realizado deslizando uma janela de tamanho k ao longo da sequência, extraindo cada subsequência de tamanho k e registrando-a como um k-mer. A janela então se move para o próximo conjunto de bases, permitindo a sobreposição entre os k-mers. Esta sobreposição é crucial para garantir que nenhuma informação seja perdida durante o processo de fragmentação.

Os k-mers resultantes retêm informações locais cruciais sobre a estrutura da sequência de DNA. Isto é crítico porque muitas informações biologicamente relevantes estão contidas em regiões específicas do DNA. A análise subsequente destes k-mers pode revelar padrões, identificar regiões conservadas ou semelhantes entre diferentes sequências de DNA e auxiliar na investigação de funções e interações genéticas.

Em resumo, Similaridade e Classificação de DNA oferecem uma abordagem para identificar semelhanças genéticas e classificar sequências de DNA.

Aplicativo

O código a seguir inicializa o projeto, realizando a configuração necessária antes da construção:

ClassMethod init()
{
    write "START INIT"
    Do ##class(dc.data.DNAClassification).CreateTheModelML()
    Do ##class(dc.data.HumanDNA).UploadData()
}

O UploadDatamétodo implementado no código é responsável por fragmentar sequências de DNA em k-mers, converter esses k-mers em vetores usando um modelo de codificação específico e, em seguida, armazenar esses vetores no banco de dados.

print("Reading dataset")
human_df = pd.read_table('/opt/irisbuild/data/human_data.txt')
human_df = human_df.sample(n=1500, random_state=42)

Para melhorar o desempenho e reduzir o tempo de processamento durante a fase de construção do projeto, é implementado um processo de amostragem, limitando a leitura aos primeiros 1.500 registros do arquivo. Embora esta estratégia acelere o processo, vale a pena notar que uma análise abrangente do arquivo poderia fornecer uma compreensão mais completa dos dados. Porém, devido ao compromisso com a eficiência e ao ritmo de construção, esta abordagem foi adotada.

def getKmers(sequence, size=6, max_length=5000):
    kmers = [sequence[x:x+size].lower() for x in range(len(sequence) - size + 1)]
    kmers = [kmer for kmer in kmers if len(kmer) > 0]
    if len(kmers) == 0:
        return [sequence]
    return kmers[:max_length]

O parâmetro MAX_LEN em getKmers é usado para limitar o tamanho máximo dos k-mers processados ​​para otimizar o tempo de execução do processo. No entanto, é importante notar que esta abordagem pode não ser ideal em termos de representação completa dos dados de ADN.

 print("Creating K-mers groups")
    human_df['K_mers'] = human_df['sequence'].apply(getKmers)

    print("Combining K-mers into strings")
    human_df['K_mers_str'] = human_df['K_mers'].apply(lambda x: ' '.join(x))

    print("Download stsb-roberta-base-v2 model")
    model = SentenceTransformer('stsb-roberta-base-v2')

    print("Encode K_mers")
    embeddings = model.encode(human_df['K_mers_str'].tolist(), normalize_embeddings=True)

    print("Creating column sequence_vectorized")
    human_df['sequence_vectorized'] = embeddings.tolist()

O código vetoriza sequências de DNA usando o modelo de codificação stsb-roberta-base-v2 da biblioteca SentenceTransformer. Esta etapa converte sequências de DNA em vetores numéricos, facilitando sua manipulação vetorial e análise computacional. Após a vetorização, os dados são armazenados no banco de dados para uso futuro. Esta etapa é crucial para garantir que os vetores de sequência de DNA estejam disponíveis para consultas e análises adicionais.

Posteriormente, o método findSimilarity é responsável por encontrar as sequências de DNA mais semelhantes com base em uma entrada de sequência de DNA recebida. Ele fragmenta a sequência de DNA em k-mers e consulta o banco de dados para encontrar as cinco sequências de DNA mais próximas.

ClassMethod findSimilarity(pSequence As %String) As %String [ Language = python ]
{
    import iris
    from sentence_transformers import SentenceTransformer

    results = []

    def getKmers(sequence, size=6, max_length=5000):
        kmers = [sequence[x:x+size].lower() for x in range(len(sequence) - size + 1)]
        kmers = [kmer for kmer in kmers if len(kmer) > 0]
        if len(kmers) == 0:
            return [sequence]
        return kmers[:max_length]
        

    model = SentenceTransformer('stsb-roberta-base-v2') 
    kmers = getKmers(pSequence)
    kmers_str = ' '.join(kmers)
    search_vector = model.encode(kmers_str, normalize_embeddings=True).tolist()

    stmt = iris.sql.prepare("SELECT TOP 5 ID FROM dc_data.HumanDNA ORDER BY VECTOR_DOT_PRODUCT(kMersVector, TO_VECTOR(?)) DESC ")
    rs = stmt.execute(str(search_vector))

    class_mapping = {
            0: 'G protein coupled receptors',
            1: 'tyrosine kinase',
            2: 'tyrosine phosphatase',
            3: 'synthetase',
            4: 'synthase',
            5: 'lon channel',
            6: 'transcription factor',
    }

    for idx, row in enumerate(rs):
        humanDNA = iris.cls("dc.data.HumanDNA")._OpenId(row[0])    

        results.append({
            "sequence": humanDNA.sequence,
            "dnaClass": class_mapping[humanDNA.dnaClass]
        })
    return results
}

Esses processos são essenciais para o projeto, pois permitem a análise comparativa de sequências de DNA e a identificação de padrões ou semelhanças entre elas.

Aprendizado de Máquina Aplicado

O aprendizado de máquina tem sido utilizado para realizar a classificação de sequências de DNA. A classe DNAClassification contém métodos para treinar um modelo de classificação multinomial Naive Bayes e para classificar sequências de DNA com base neste modelo.

O método CreateTheModelML é responsável por treinar o modelo de classificação. Primeiramente, as sequências de DNA são pré-processadas, transformadas em k-mers e agrupadas. Em seguida, esses grupos k-mer são convertidos em uma representação numérica utilizando a técnica de vetorização. O modelo multinomial Naive Bayes é então treinado com esses dados vetorizados. Após o treinamento, o desempenho do modelo é avaliado por meio de análises como precisão, recall e pontuação F1.

ClassMethod CreateTheModelML()
{
    import pandas as pd

    def getKmers(sequence, size=6):
        kmers = [sequence[x:x+size].lower() for x in range(len(sequence) - size + 1)]
        kmers = [kmer for kmer in kmers if len(kmer) > 0]
        if len(kmers) == 0:
            return [sequence]
        return kmers

    print("Reading dataset")
    human_df = pd.read_table('/opt/irisbuild/data/human_data.txt')

    print("Creating K-mers groups")
    human_df['K_mers'] = human_df['sequence'].apply(getKmers)
    
    human_df['words'] = human_df.apply(lambda x: getKmers(x['sequence']), axis=1)
    human_df = human_df.drop('sequence', axis=1)

    human_texts = list(human_df['words'])
    for item in range(len(human_texts)):
        human_texts[item] = ' '.join(human_texts[item])
    y_data = human_df.iloc[:, 0].values        
    
    from sklearn.feature_extraction.text import CountVectorizer
    cv = CountVectorizer(ngram_range=(4,4))
    X_human_dna = cv.fit_transform(human_texts)

    print(X_human_dna.shape)

    print("PREPARING FIT DATA")
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X_human_dna, 
                                                        y_data, 
                                                        test_size = 0.20, 
                                                        random_state=42)
    
    print("FIT THE MODEL")
    from sklearn.naive_bayes import MultinomialNB
    classifier = MultinomialNB(alpha=0.1)
    classifier.fit(X_train, y_train)

    y_pred = classifier.predict(X_test)

    print("VALIDATING THE MODEL")

    from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
    print("Confusion matrix\n")
    print(pd.crosstab(pd.Series(y_test, name='Actual'), pd.Series(y_pred, name='Predicted')))
    def get_metrics(y_test, y_predicted):
        accuracy = accuracy_score(y_test, y_predicted)
        precision = precision_score(y_test, y_predicted, average='weighted')
        recall = recall_score(y_test, y_predicted, average='weighted')
        f1 = f1_score(y_test, y_predicted, average='weighted')
        return accuracy, precision, recall, f1
    accuracy, precision, recall, f1 = get_metrics(y_test, y_pred)
    print("accuracy = %.3f \nprecision = %.3f \nrecall = %.3f \nf1 = %.3f" % (accuracy, precision, recall, f1))


    print("SAVE THE MODEL")
    import joblib
    joblib.dump(classifier, '/opt/irisbuild/data/multinomial_nb_model.pkl')
    joblib.dump(cv, '/opt/irisbuild/data/cv_to_multinomial_nb_model.pkl')
}

Por outro lado, o método ClassifyDnaSequence é responsável por classificar as sequências de DNA recebidas como entrada. Primeiramente, a sequência é pré-processada e transformada em k-mers. Então, esses k-mers são vetorizados usando o mesmo processo usado durante o treinamento do modelo. O modelo treinado é então carregado e usado para prever a classe da sequência de DNA. O resultado da classificação inclui a classe prevista e as probabilidades associadas a cada classe.

ClassMethod ClassifyDnaSequence(sequence As %String) As %Status
{
    import joblib
    from sklearn.feature_extraction.text import CountVectorizer

    classifier = joblib.load('/opt/irisbuild/data/multinomial_nb_model.pkl')
    cv = joblib.load('/opt/irisbuild/data/cv_to_multinomial_nb_model.pkl')

    def getKmers(sequence, size=6):
        kmers = [sequence[x:x+size].lower() for x in range(len(sequence) - size + 1)]
        kmers = [kmer for kmer in kmers if len(kmer) > 0]
        if len(kmers) == 0:
            return [sequence]
        return kmers
    k_mers = getKmers(sequence)

    k_mers_vec = cv.transform([' '.join(k_mers)])

    predicted_class = classifier.predict(k_mers_vec)[0]
    probabilities = classifier.predict_proba(k_mers_vec)[0]

    class_mapping = {
            0: 'G protein coupled receptors',
            1: 'tyrosine kinase',
            2: 'tyrosine phosphatase',
            3: 'synthetase',
            4: 'synthase',
            5: 'lon channel',
            6: 'transcription factor',
    }
    

    result = {
        "Classification": class_mapping[predicted_class],
        "Probabilities": {
            class_mapping[class_index]: float(probability)
            for class_index, probability in enumerate(probabilities)
        }
    }
    
    return result
}

Uso do aplicativo

Os usuários interagem com o sistema enviando sequências de DNA por meio de consultas e podem solicitar uma resposta no formato JSON contendo informações sobre as sequências semelhantes descobertas e suas classificações, simplificando o processo de análise genética.

Abaixo está a API a ser usada: http://localhost:52773/api/dna/find?&dna=<YOUR_DNA>

  • dna: Digite a sequência de DNA que você deseja pesquisar

Exemplo: http://localhost:52773/api/dna/find?&dna=ATGAACTGTCCAGCCCCTGTGGAGATCTCCT...

Usando o Postman para visualizar a resposta da API (pode ser feito usando um navegador ou outros aplicativos como o Insomnia):

Projeto:  GitHub

Votação:  similaridade e classificação de DNA

1 Comment
Discussão (1)2
Entre ou crie uma conta para continuar