クリアフィルター
記事
Mihoko Iijima · 2021年6月17日
開発者のみなさん、こんにちは!
2023/2/21追記
チュートリアルページが新しくなり「Developer Hub」に変わりました!
Full Stackチュートリアルの開始方法や他のチュートリアルについて詳しくは、「InterSystems Developer Hub:クリック1回で開始できるチュートリアル(4種)のご紹介」をご参照ください。
この記事では、GettingStarted ページの無料体験環境(Sandbox)で試せるチュートリアルの中から、「Full Stack Tutorial」の使い方をご紹介します。
GettingStarted ページでできることについては、こちらの記事でご紹介しています。
無料体験環境(Sandbox)の開始手続きについては、こちらの記事でご紹介しています。ぜひご参照ください。
この記事では、チュートリアルを GettingStarted ページの Sandbox でご体験いただく流れを記載しています。Full Stack Tutorial のパート1 を開き、ログインいただくと Sandbox へのアクセス情報が表示されますので、Sandbox 用 IDE のリンクなどはお手元の環境でご確認ください。
また、チュートリアルの流れの中で、IRIS への接続情報を Sandbox 用 IDE で修正する内容があります。Full Stack Tutorial の対象ページを開き、お使いの Sandbox の情報をご確認ください。
Full Stack Tutorial 概要
(オリジナルはこちらから👉 https://gettingstarted.intersystems.com/full-stack/)
InterSystems IRIS data platform は、マルチモデル(SQL、NoSQL)や、マルチワークロード(トランザクションとリアルタイム分析)が行える DBMS 機能、システム統合、変換、API管理、ビジネスロジックを操作できるプラットフォームで、組み込みの統合、分析機能、BI、機械学習、自然言語処理を含む強力で様々な機能を提供しています。これら機能を利用するために、別製品を追加することも、データを別の構成に移動することも不要で、全て 1 つのプラットフォームで操作いただけます。
フルスタックチュートリアルでは、小さな製造会社(焙煎したてのコーヒーを販売する会社)の基本的な情報管理インフラを作成していくテーマを用意しています。
この会社では、焙煎したばかりのおいしいコーヒー豆を焙煎、包装、販売しています。
このチュートリアルを通して、InterSystems IRIS data platform が IT アーキテクチャのバックボーンとしてどのように機能するかを学習いただけます。
このチュートリアルは、3つのパートに分かれています。
コーヒーメーカーとして、生豆の在庫管理からオンラインポータルでの販売までを設定するためのプロセスをご紹介します。
パート1
架空会社「IRIS コーヒーカンパニー」で使用する、簡単な在庫処理システムを作成します。
IRIS が他の多くのデータベースと同様に、テーブルの作成やデータの読み込みに標準的な SQL を使用できることをチュートリアルを通して学習します。また、Python を使用して JSON 形式で送付されてくる注文情報を処理します。
パート1の終わりには、新しいコーヒー豆の納品を会社の在庫として処理できるようになります。
パート2
在庫管理、焙煎、販売など、ビジネスのさまざまな処理を RESTful サービスを介して通信できるようにします。
コーヒーの焙煎所は在庫から豆を要求し、焙煎と包装の後、REST サービスを使って最終製品をカタログに載せ、オンラインで販売します。
これらの処理は全て、チュートリアルで作成する RESTful サービスを利用して実行されます。
パート3
人気のある JavaScript フレームワーク Vue.js を使用して、焙煎職人が作ったコーヒー豆を販売するオンラインストアを作成します。
1) パート1:SQLを使用してデータベースを作成する
このチュートリアルを完成させるためには、無料体験環境の Sandbox の準備が必要です。
こちらのページにアクセスし👉https://gettingstarted.intersystems.com/full-stack/full-stack-part-one/)まだログインされていない場合は、ログインを行ってください。
ユーザ登録がまだの場合は、こちらの記事をご覧いただき、ユーザ登録後、ログインを行ってください。
ログイン後、 ボタンをクリックします。既にクリックされている場合は、アクセス情報が以下のように表示されます。
情報表示の一番上に「Sandbox IDE」と書かれたリンクがあります。こちらをクリックするとブラウザでアクセスできる Sandbox 専用 IDE が開きます(下図)。
チュートリアルは、この IDE を使用します。
準備ができたら、フルスタックチュートリアル用ソースコードを git clone するため、画面中央下のターミナルウィンドウで以下実行します。
git clone https://github.com/intersystems/quickstarts-full-stack.git
IDE の画面左側に quickstarts-full-stack フォルダが参照できれば、git clone 成功です。
この IDE は Theia で、Visual Studio Code とよく似た機能を持っています。左側にファイルエクスプローラーがあります。右側にはコード編集パネルがあり、編集パネルの下にはターミナル・ウィンドウがあります。
✨いよいよチュートリアルの開始です!✨
データベースを作成します。
IRIS コーヒーカンパニーは、3つの部門に分かれています。
倉庫にはコーヒーの生豆の在庫が保管されています。テーブル名:ICO.inventory にデータが格納されます。
焙煎所は、コーヒー豆を焙煎する部門で、データを保存する必要がない部門です。
Storefront は、焙煎したコーヒーを販売する店舗です。販売データはテーブル名:ICO.catalog に格納されます。
IRIS ターミナルをSQL用モードに切り替え、CREATE文を使って2つのテーブルを作成します。
手順は以下の通りです(IDEからアクセスできます)。
(1) Sandbox の IDE を開きます(パート1:https://gettingstarted.intersystems.com/full-stack/full-stack-part-one/#database-creation を開き、ログインしていると以下のように IDE へのリンクが表示されます)。
(2) IDE のメニューから、InterSystems > Web Terminal を選択します。別タブで Web ターミナルが開きます。
(3) ログイン画面が出てきたら、ユーザ名:tech パスワード:demo を入力してログインします。
(4) プロンプトに USER> と表示される画面が開きます。
(5) Web ターミナルのモードを SQL 実行モードに変えるため、/sql を入力します。
(Web ターミナル専用コマンドです)。
(6) 以下のSQL文をコピーして、Web ターミナルに貼り付けます(Ctrl +v でペーストできます)。
CREATE TABLE ICO.inventory
(
vendor_id VARCHAR(128),
vendor_product_code VARCHAR(128),
quantity_kg DECIMAL(10,2),
date_arrival DATE
)
プロンプトが戻ってくるまでお待ちください。
テーブルが作成できたか確認のため、SELECT * from ICO.inventory を実行してみます(まだレコードがないので、「Nothing to display」と表示されます)。
SELECT * from ICO.inventory
7) 次に、ICO.catalog テーブルを作成するため、以下 SQL をコピーし、Web ターミナルに貼り付け実行します。
CREATE TABLE ICO.catalog
(
catalog_id BIGINT IDENTITY,
product_code VARCHAR(128),
quantity INTEGER,
price DECIMAL(10,2),
time_roasted DATETIME,
roasting_notes VARCHAR(2048),
img VARCHAR(2048)
)
(8) 作成が完了したら、データはありませんが、SELECT * from ICO.catalog を実行します(これも、Nothing to display と表示されれば成功です)。
SELECT * from ICO.catalog
ここまでで、テーブル定義の作成は終了です。
(9) Web ターミナルで、 /sql を実行すると、元のターミナルプロンプトに戻ります(=IRIS の ObjectScript が実行できるターミナルに戻ります)。
Python を利用してデータをロードします。
チュートリアルでは、Python でデータをロードする処理を作成しています。
大まかな処理の流れは以下の通りです。
世界中のベンダーから生豆の出荷依頼が来ると想定し、生豆の注文をデータベースに入力できるようにします。出荷情報は JSON 形式とし、単一の注文マニフェストファイルで送付される仕様としています。
注文マニフェストの例は、quickstarts-full-stack/setup/order_manifest.json にあります。IDE の左画面を利用してファイルを開いてみましょう。
データロードには、Python のプログラムを使用します。プログラム内では、注文マニフェストの JSON ファイルを解析し、データベースに接続し INSERT を実行しています(データ登録時に SQL が使用されますが、今回はWeb ターミナルではなく、Python のプログラム内で実行しています)。
注文マニフェストをデータベースにインポートする処理を作成します。
Python の標準ライブラリを使用して、指定ディレクトリから JSON ファイルを読み込みます。その後 ODBC 経由でデータベースに接続し、SQL の INSERT をし湯押して、JSON データを IRIS に登録します。
次の Python コードの解説が不要な場合は、サンプルスクリプトの実行に移動してください。
Python コードの中身解説
スクリプトは setup/manifest_importer.py にあります。
以下、データロード用スクリプトで行っている重要な要素について解説します。
main() 関数では、JSON 注文マニフェストファイルをインポートし、検証を行い、inventory テーブルに登録するために必要な構造をチェックしています。
def main():
with open('./order_manifest.json') as f:
data = json.load(f)
data, status, exp = validate_manifest(data)
次に、connection.config ファイルにあるデータベースの接続情報を読み込んでいます。
connection_detail = get_connection_info("connection.config")
ip = connection_detail["ip"]
port = int(connection_detail["port"])
namespace = connection_detail["namespace"]
username = connection_detail["username"]
password = connection_detail["password"]
driver = "{InterSystems ODBC}"
ODBCドライバーを使ってデータベースへの接続を設定します。
connection_string = 'DRIVER={};SERVER={};PORT={};DATABASE={};UID={};PWD={}' \
.format(driver, ip, port, namespace, username, password)
connection = pyodbc.connect(connection_string)
JSON データ(data)とデータベース接続オブジェクト(connection)を使って load_manifest() 関数を呼び出します。
msg = load_manifest(data, connection)
load_manifest() 関数では、JSON ファイル内のすべてのアイテムを繰り返し取得しながら INSERT 文を組み立て、前の手順で作成した ICO.inventory テーブルに各アイテムを挿入します。
方法は以下の通りです。最初に、INSERT 文を作成しています。
fieldnamesql = "INSERT INTO ICO.inventory (vendor_id, vendor_product_code, quantity_kg, date_arrival)"
次の2行では、現在の日付を使用して「2021-06-16」の形式の日付文字列を作成します。この日付は、製品が倉庫に到着した日付に使用します。
today = date.today()
mydate = today.strftime("%Y-%m-%d")
このコードは、JSON ファイル内の各アイテムのオブジェクトをループし、取得したデータを使用して INSERT 文の VALUES の部分を作成しています。
その結果、次のような INSERT 文が完成します。
INSERT INTO ICO.inventory (vendor_id, vendor_product_code, quantity_kg, date_arrival) VALUES (ETRADER, ETHIOPIA32, 200, ‘2021-06-16’)
次に、ここまでの解説で作成した SQL 文(変数 valsql)を実行します。
load_manifest() 関数の1行目でデータベースカーソルを定義しているので、カーソルに SQL 文を入力して execute() を実行しています。
cursor.execute(valsql)
Pythonのデータローダスクリプトを実行する
コードの解説が終了しましたので、プログラムを実行してみましょう。
最初に、ODBCドライバのインストールを行います。
Sandbox の IDE を開きます。IDEを開く URL は https://gettingstarted.intersystems.com/full-stack/full-stack-part-one/#jsondataimport を開き、「Run the Python import」近くに表示されます。表示されない場合は、ログインを行ってください。
IDE を開いたら、ターミナルウィンドウで、以下実行してください。
cd /home/project/quickstarts-full-stack/setup
sudo odbcinst -i -d -f pyodbc_wheel/linux/odbcinst.ini
次に、データベースの接続情報を確認します。
(1) Sandbox の IDE で /home/project/quickstarts-full-stack/setup/connection.config を開きます。
(2) IP アドレスに記載されている文字列を、修正します。
https://gettingstarted.intersystems.com/full-stack/full-stack-part-one/#jsondataimport を開き 「Database connection settings for your sandbox」の近くに変更対象の IP アドレスが表示されます。
図例だと、ip の設定に 34.71.28.209 を指定します。
port の設定も、27404 に変更します。
(3) 変更後、ファイルを保存します(Ctrl + s)。
接続情報変更後、Sandbox の IDE のターミナルウィンドウで以下実行します。
python manifest_importer.py
図例にあるような、INSERT 文の実行ログを確認できると思います。
IRIS は、Python だけでなく、Java、.NET、Node.js からもアクセスできます。言語別のアクセス方法の体験については、QuickStart をご参照ください。
SQLでデータを確認
Python から登録したデータが正しくテーブルに登録できているかを、Web ターミナルを使用して確認します。手順は以下の通りです。
(1) Sandbox 用 IDE 開きます。
https://gettingstarted.intersystems.com/full-stack/full-stack-part-one/#database-query を開き「SQL database queries」の近くに下図のように情報が表示されます。
(2) InterSystems > Web Terminal を開きます。
(3) ログイン画面が表示されたら、ユーザ名:tech パスワード:demo でログインしてください。
(4) /sql を入力し、SQL 実行モードに切り替えます。
以下実行します。
select * from ICO.inventory
詳細情報を参照するため、いくつかのクエリを実行してみましょう。
100 kg 以上の大型商品を検索するクエリ
SELECT * FROM ICO.inventory WHERE quantity_kg > 100
特定のベンダー(例では、DKEの文字から始まるベンダー名を抽出)のすべての在庫を確認するクエリ
SELECT * FROM ICO.inventory WHERE vendor_id LIKE 'DKE'
独自の在庫を追加してみましょう!
最後に、在庫を増やしてみましょう。vendor id、verdor_product_code、quantity_kg に独自の値を登録した JSON マニフェストファイルを作成します。
(1) Sandbox の IDE の左画面を利用して、order_manifest.json を開き、File > Save As... メニューを利用して、別名保存します(order_manifest-original.json)。
注意:データロード用スクリプトでは、JSON マニフェストファイルに含まれるコメント行の対応を行っていません。コメントは使用しないでください。
(2) Sandbox の IDE で order_manifest.json ファイルを開きます。
(3) 好きな値を登録します(英数字でご記入ください)。
(4) python manifest_importer.py を実行します。
パート1で確認できたこと
IRIS をリレーショナルデータベースとして使用できることが確認できました。
また、Python から SQL 文を実行できることを確認できました。
この後は、パート2 に進み、会社全体で使用する REST サービスを作成します。
パート2:ObjectScript を使用した REST サービスの開発
(オリジナルページはこちら👉 https://gettingstarted.intersystems.com/full-stack/part-two-rest-services/)
適切に設計されたシステムでは、ビジネスアプリケーションをデータベース上で直接操作することはありません。その代わりに、サービスを介したアクセスを提供し、実行されるアクションを制御/監視できるようにします。
パート2では、ビジネスを機能させるために必要な RESTful Web サービスを作成します。
ほとんどのデータベースでは、Java Spring、Python Flask、Node.js Express などのミドルウェアフレームワークを使用して、SQLでデータレイヤーとやり取りしています。IRIS でもその方法を利用することはできますが、より簡単で高性能な別の選択肢があります。
ObjectScriptでコードを記述する:ストアドプロシージャのパフォーマンスと、プログラミング言語の柔軟性、パワー、使いやすさを手に入れることができます。
ミドルウェアが不要です:ミドルウェア層が組み込まれています。
コツさえつかめば、ObjectScript は Web アプリケーションのバックエンドを構築するための最速の方法と言えます!
ObjectScript を使用したデータの操作
パート1 では、Python と SQL を使ってデータベースにアクセスする方法をご紹介しました。
パート2では、ObjectScript によるアクセスがいかに簡単か、特に主キーを使ってレコードを取得したい場合について見ていきたいと思います。
(1) Sandbox の IDE を開きます。
https://gettingstarted.intersystems.com/full-stack/part-two-rest-services/#query-cos を開き、「ObjectScript database query」の近くに IDE へのリンクが表示されます。
IDE などのアクセス情報の表示が、 のように表示されていたら、ピンク色のリンクをクリックしてください。
(2) IDE のメニューから InterSystems > Web Terminal を選択します。
(3) ログイン画面が表示されたらユーザ名:tech パスワード:demo でログインしてください。
(4) 以下の ObjectScript のコマンドをコピーし、ターミナルに貼り付けて実行してください。
以下のコードは 主キーが 1 である ICO.Inventory のレコードを取得しています。
set item = ##class(ICO.inventory).%OpenId(1)
zwrite item
set item.quantitykg = 300
zwrite item
do item.%Save()
1行ずつコードを解説します。
1行目:データベースからレコードを 1 件ロードしています。
2行目:レコードデータをターミナルに表示しています。
3行目:在庫数が設定されている quantitykg の値を 300(kg) に変更しています。
4行目:変更を確認するため、画面に再度表示しています。
5行目:データベースに変更データを保存しています。
InterSystems Web Terminal は、通常のコマンド・ライン・ターミナルと同様に動作しますが、ObjectScript コマンドも実行できます。
ObjectScript と SQL によるデータベースの操作
それでは、ObjectScript を使用して SQL を使ったより複雑なクエリを実行してみましょう。
Web Terminal に戻って、次のように入力してください。
set sqlquery = "SELECT * FROM ICO.inventory"
set resultset = ##class(%SQL.Statement).%ExecDirect(,sqlquery)
while resultset.%Next() { Write !, resultset.%Get("vendor_id") }
1行ずつコードを解説します。
1行目:実行したい SELECT 文を変数に設定しています。
2行目:%SQL.Statement クラスを使用して、1 行目で設定した変数に設定した SQL 文を実行し、変数 resultset に検索結果のインスタンスを設定しています。
3行目:resultset 変数を使用して、検索結果を繰り返し行移動(%Next())しながら vendor_id プロパティの値を画面表示しています。
ObjectScript のクラスを書いてみる
今まで試した Web Terminal のスクリプトは、1行に沢山のコードを指定しているので、見やすいとは言えません。
今度は、ObjectScript のコードをファイルにまとめてみましょう。
(1) Sandbox の IDE を開きます
(2) 画面左のフォルダから、quickstarts-full-stack > services > cls > ICO を開きます。
(3) ICO フォルダを右クリックし、New File メニューを選択します。
(4) ファイル名に Test.cls を指定し、OK ボタンをクリックします。
(5) ファイルに以下の文字列を記述します(ICO.Test クラスを作成しています)。
Class ICO.Test{/// DescriptionClassMethod QueryDB() As %Status{ set sqlquery = "SELECT * FROM ICO.inventory" set resultset = ##class(%SQL.Statement).%ExecDirect(,sqlquery) while resultset.%Next() { Write !, resultset.%Get("vendor_id") }}}
記述後、ファイルを保存し(Ctrl + s)Web Terminal で以下実行します。
do ##class(ICO.Test).QueryDB()
SQL と ObjectScript の使い分けや、マルチモデル機能については、開発者コミュニティの記事で詳しく紹介しています。
Web サービスの作成
ここまでの内容は、ObjectScript のプログラミング入門編でした。
ここからは、確認した内容を活かして、コーヒー焙煎ビジネスに必要な Web サービスを構築してみましょう。
作成概要は以下の通りです。
(1) 事前に作成されたコードをコピーしてコンパイルします。
(2) JSON の操作が行えるようにテーブル定義を変更します(JSONアダプタクラスの継承を追加します)。
(3) RESTful API がどのように構築されているか確認します。
(4) curl とブラウザを使い、Web サービスのデプロイとテストを行います。
(5) Web サービスを利用して、コーヒーの在庫を店舗に移動させます。
(6) 販売情報を記録します。
パート1では、標準的な SQL を使用してデータベースのテーブルを作成しました。
実は、その作成の裏では、対応する ObjectScript クラスも作成されていることをご説明していませんでした。
テーブルを作成するとクラス定義(永続クラス)も用意される仕組みにより、開発者は目的に応じて、SQL とコードの記述が簡単に行えるようになっています。
SQL で取得したデータを JSON としても出力できるようにするためには、データベースのテーブル定義に ObjectScript のコードに少し加える必要があります。その前に、データベースに登録されているコードを見てみましょう。
(1) Sandbox の IDE を開き、InterSystems のアイコン をクリックします。
(2) IDE の画面左側で Classes > ICO を展開します。catalog.cls と inventory.cls の名称のファイルが確認できます。
パート1 で SQL 文を使ってデータベースにテーブルを作成した際に、それに対応する ObjectScript クラスも同時に作成されていることが確認できます。
(3) catalog.cls をクリックします(上図)。カラムの定義は Property 定義として表示されています。また、データ型や文字長の設定は見覚えのある値が登録されているはずです。同様に、inventory.cls をご参照ください。
(4) 開いたファイルはすべて閉じておいてください。
JSON の操作が行えるテーブル定義に変更する
JSON の入出力を可能するため、確認したクラスを少し変更する必要があります。以下の手順で変更しましょう。
(1) Sandbox の IDE の ファイルのアイコンをクリックします。
(2) quickstarts-full-stack > services > cls > ICO を開きます。
(3) ICO フォルダの上で右クリック > New File を選択し、catalog.cls の名称で保存します。
(4) ICO フォルダの上で右クリック > New File を選択し、inventory.cls の名称で保存します。
(5) quickstarts-full-stack > services > cls_Sample > ICO を開きます。
(6) catlog.cls を開き、ファイル内を全てコピーし、quickstarts-full-stack > services > cls > ICO > catalog.cls に貼り付けます。
(7) quickstarts-full-stack > services > cls_Sample > ICO > inventory.cls を開き、ファイル内を全てコピーし、quickstarts-full-stack > services > cls > ICO > inventory.cls に貼り付けます。
(8) 変更したファイル(quickstarts-full-stack > services > cls > ICO > catalog.cls と inventory.cls )を保存します。
保存時、画面右下に選択欄が表示されるので "Overwrite on Server" を選択します。この操作により、%JSON.Adapter と プロパティのパラメータ:%JSONFIELDNAME を追加したクラスの新しいバージョンがサーバにアップロードされ、コンパイルされます。
(9) 2つのファイルに以下の操作を行いました。
A:%JSON.Adapter を継承し、テーブルのデータに対して自動的に JSON 出力が行えるように設定しました。
B:プロパティのパラメータ:%JSONFIELDNAME を追加し、JSON 出力時に使用するプロパティ名を変更しました。
ここまでの流れで、データベース用意したテーブル定義が、ObjectScript のクラス定義としても表現され、SQL と ObjectScript を使ってデータベースに対する操作ができることを確認できました。
これで、Web API を構築する準備が整いました!
RESTful サービスを作ってみよう!
テーブル定義(クラス定義)へ JSON アダプタを継承することで JSON の操作が行えるようになり、REST サービスを作成する準備が整いました!
先ほどと同様の手順で、クラス定義を追加します。
quickstarts-full-stack > services > cls > ICO 以下に Handler.cls を新規に作成します。手順は以下の通りです。
(1) Sandbox の IDE の ファイルのアイコンをクリックします。
(2) quickstarts-full-stack > services > cls > ICO フォルダを開きます。
(3) ICO フォルダを右クリックし New File を選択し、クラス名に Handler.cls を設定します。
(4) quickstarts-full-stack > services > cls_Samples > ICO フォルダを開きます。
(5) quickstarts-full-stack > services > cls_Samples > ICO> Handler.cls クラスを開き、クラス定義の中身を全部コピーし、(3) で作成した quickstarts-full-stack > services > cls > ICO > Handler.cls に貼り付けます。
(6) ファイルを保存します(今回は "Overwrite on Serve" のオプション表示は出てきません)。
Handler.cls の作成により、ミドルウェアとなる REST API が作成できました。
サービスを起動させるための最後の手順として、Web に公開するための設定を追加します。
IRIS では、Node.js の Express や Python の Flask と同じように、Web リクエストを ObjectScript コードにルーティングするツールを提供しています。
管理ポータルを使用して作成した ICO.Handler クラスを Web リクエスト時に呼び出されるように設定してみましょう。
管理ポータルを開きます。
Sandbox の IDE のメニューから InterSystems > Management Portal を選択します。
管理ポータルが開いたら、以下メニューにアクセスします。
システム管理 > セキュリティ > アプリケーション > ウェブ・アプリケーション
以下の手順で、REST のエンドポイントのパスを作成します。
(1) ボタンをクリックします。
(2) 名前 に /api/coffeeco を設定します。
(3) ネームスペースに USER を設定します。
(4) アプリケーション有効 にチェックが入っていることを確認します。
(5) REST にチェックします。
(6) ディスパッチクラス に ICO.Handler を設定します。
(7) 許可された認証方法では、「認証なし」と「パスワード」にチェックを入れます。
(8) 保存ボタンをクリックし、設定を保存します。
保存後、「アプリケーション・ロール」タブが表示されるので、クリックし、「アプリケーションロール」に %All を設定します。
設定には、「利用可能」の一覧から %All を選択し、 をクリックし、画面右側の「選択済み」に移動させます。
その後、ボタンをクリックすると、「アプリケーションロール」に %All が追加されます。
REST インターフェースでは、ここで紹介しているように手動でコーディングすることもできますし、Open API v2.0 の仕様を作成して自動的にコードを生成する、API ファーストのアプローチをとることもできます。詳しくはドキュメントをご覧ください。
作成したサービスのテストをしましょう
ここまでの設定で、REST 用エンドポイントの作成が完了しました。エンドポイントは https://gettingstarted.intersystems.com/full-stack/part-two-rest-services/#json-enable-the-data-tables を開き「Test the service」の近くに表示されます(Sandbox 毎に情報は異なります)。
https://Sandbox で利用できるWebサーバアドレス/api/coffeeco/inventory/listbeans
上記 URL(Webサーバアドレスはお試しいただいている環境に合わせてご変更ください)をコピーし、ブラウザのアドレスバーに入力し、REST サービスをテストすると、以下のような結果が返ります。
見易い表示に変えると、以下のような結果が返ります。
{
"rowcount": 5,
"items": [{
"id": "1",
"vendor_product_code": "ETHIOPA32",
"date_arrival": "65541",
"quantity_kg": 400
}, {
"id": "2",
"vendor_product_code": "BRAZILPREM",
"date_arrival": "65541",
"quantity_kg": 200
}, {
"id": "3",
"vendor_product_code": "GUATEMALAALT30",
"date_arrival": "65559",
"quantity_kg": 200
}, {
"id": "4",
"vendor_product_code": "SUMATRA2",
"date_arrival": "65559",
"quantity_kg": 200
}, {
"id": "5",
"vendor_product_code": "SUMATRA3",
"date_arrival": "65559",
"quantity_kg": 400
}]
}
コーヒー豆を焙煎します
現在、ブラウザからのリクエストでレスポンスが返ってくることを確認できたので、サービスが動作していることがわかりました。ここからは、コーヒービジネスを操作するためのサービスを作成します。
最初に、コーヒーの生豆を在庫から取り出し、焙煎します。この動作には、/api/coffeeco/inventory/getbeans の URL を使用します。
Handler.cls を開き、ファイル末尾に定義された XData UrlMap の <Routes> のタグ内部をご参照ください。
URL /api/coffeeco/inventory/getbeans に対して、クラスメソッド GetRawBeans() が呼び出されるように定義されていることがわかります。
URL で値を渡すための URL に含めるパラメータの記載方法にも注目してください。
クラス定義内で GetRawBeans()メソッドを参照します。
レコードの主キーとなる値が URL の :id で渡されます。GetRawBeans() メソッドが実行されるとき、メソッドの第 1 引数に :id の情報が渡されます。
この値を %OpenId() メソッドの引数に指定することで、ObjectScript を使用してデータベースから対象のデータをロードすることができます(とても簡単な方法です)。
残りのコードは以下の通りです。
(1) quantity に設定されている値が十分な量であるかの確認
(2) 在庫から要求された量を減らす処理
(3) 要求元に新しい在庫量を返す処理
在庫から豆を取り出し、焙煎を行うためのリクエストを実行してみます。
今回のリクエストは、ブラウザでテストすることはできません(ブラウザで、POST 要求を送信することができないためです)。
Sandbox の IDE のターミナルウィンドウでは、curl コマンドを実行できるので、以下のように入力してみください。
注意:リクエストに使用する Web サーバアドレスは Sandbox の利用環境により異なります。お使いの環境のサーバ名に修正して実行してください。
curl -X POST https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/inventory/getbeans/1/2.4
お店にコーヒーを並べる
このチュートリアルではシンプルな例を利用しているため、リクエストされた生豆の量はどこにも記録されていません。
コーヒーを焙煎し、袋詰めし、店頭に並べて販売する処理についてはリクエストする Web アプリケーション側で処理することとします。
その処理を追加するため、quickstarts-full-stack > services > samples ディレクトリに 2 つのスクリプトが用意されています。
createproducts.sh
5 つのサンプルコーヒー製品の情報を作成するシェルです。最初の 3 つは本日焙煎されたもので、最後の 2 つは 6 日前に焙煎されたものです。
このシェルの実行で、鮮度の古い6日前の焙煎豆情報を作成しています。オンラインショップでは、鮮度が古い焙煎豆を割引して販売したいので、割引対象データとして準備しています。
loadproducts.sh
curl コマンドを実行して、対象ディレクトリ内のすべての JSON ファイルを繰り返し参照し、用意した REST サービスを使用して JSON ファイル内のデータを ICO.catalog にロードします。
それではシェルを実行してみましょう。手順は以下の通りです。
(1) Sandbox の IDE のターミナルウィンドウで以下実行します。
cd /home/project/quickstarts-full-stack/services/samples
sh createproducts.sh
(2) IDE で、quickstarts-full-stack > services > samples ディレクトリに 5 つの JSON ファイルが作成できたことを確認してください。
(3) loadproducts.sh を IDE で開きます。
(4) 環境変数 IRISDB の値を修正します(Sandbox のウェブサーバアドレスに修正します)。
https://gettingstarted.intersystems.com/full-stack/part-two-rest-services/#coffee-to-store を開き「Put coffee in the store」の近くに表示される情報をご利用ください。
(5) loadproducts.sh を保存します。
(6) Sandbox の IDE のターミナルウィンドウで以下実行します。
cd /home/project/quickstarts-full-stack/services/samples
sh loadproducts.sh
シェルを実行したくない場合は、curl コマンドを利用してデータを読み込むこともできます。
コマンド実行例は以下の通りです(Webサーバアドレスは Sandbox ごとに異なります。実行環境に合わせて実行してください。)。
curl -d "@product_brazil_dark.json" -H "Content-Type: application/json" -X POST https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/catalogproduct
この時点で、生豆を出荷し在庫に入れ、一部は焙煎してパッケージ化し ICO.catalog テーブルに保存したため、オンラインショップで販売できるようになりました。
コーヒーカタログを提供する
ここからは、フロントエンドのオンラインストアフロントに必要なサービスを考えていきます。Web 開発者は、以下の用途で利用できる一連のサービスを必要としています。
(1) 焙煎したばかりの新鮮なコーヒーを販売してほしい
(2) 値引きして販売する必要のある鮮度の古いコーヒーバック情報を入手したい
(3) コーヒーバックの販売記録を作りたい
最初の2項目は非常に簡単です。読み取り専用のサービスとなるので、GET要求を使用すれば取得できます。
両方の GET 要求を 1 つの GetProducts()メソッドで処理できるように、新鮮な在庫と古い鮮度の在庫のどちらを返すか指定できる入力引数を用意することもできます。
Handler.cls (quickstarts-full-stack > services > cls > ICO > Handler.cls)の下の方に定義されている UrlMap 定義をご参照ください。
/catalog/getproducts は、全て新しい鮮度のコーヒーを返すUrlです。
/catalog/getproducts/:fresh は、/catalog/getproducts に似ていますが、鮮度の古いコーヒーを取得できる追加のパラメータを用意しています(fresh が 0 の場合に鮮度が古い情報を返します)。
/catalog/sellproduct/:id/:quantity は、クライアントが特定の商品のバッグを販売したことを記録する処理の Url です。
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/inventory/listbeans" Method="GET" Call="ListRawBeans" />
<Route Url="/inventory/getbeans/:id/:quantity" Method="POST" Call="GetRawBeans" />
<Route Url="/catalog/catalogproduct" Method="POST" Call="CatalogProduct" />
<Route Url="/catalog/getproducts" Method="GET" Call="GetProducts" />
<Route Url="/catalog/getproducts/:fresh" Method="GET" Call="GetProducts" />
<Route Url="/catalog/sellproduct/:id/:quantity" Method="POST" Call="SellProduct" />
</Routes>
}
GetProducts() メソッドでは、SQL を使用してクエリを実行し、返されたレコードを繰り返し処理で取得し、取得できた情報を JSON オブジェクトに設定し、 JSON 配列に追加し、最後に呼び出し元に作成した JSON データを返送しています。
以上の流れで、Web 開発者が販売中の商品を紹介する素敵なサイトを構築するために必要な情報がすべて揃いました!
コーヒーを販売する
販売したコーヒーを記録するサービスの SellProduct() は、プロダクト ID と販売されるバッグの数量が引数として指定されます。
ここでは、エラーチェックや特別な支払い処理、発送などは行わず、非常にシンプルな処理を行っていて、カタログのコーヒーバッグの数量を減少させるだけの処理としています。
また、お客様が複数の商品を購入した場合、クライアントはそれぞれの商品に対して SellProduct リクエストを送信するものとします。
GetRawBeans() メソッドの処理と同様に、レコード ID がわかっている場合にレコードを照会する ObjectScript の便利なメソッド %ExistsId()、%OpenId()、%Save() を利用します。このメソッドは GetRawBeans() と非常によく似ているため、新たに追加する説明はありません。
サービスを試してみます。
実行に使用する URL の Web サーバアドレスは Sandbox 毎に異なります。
https://gettingstarted.intersystems.com/full-stack/part-two-rest-services/#catalog-services を開き、「Try out the services」の近くの表示をご確認ください。
新鮮なコーヒー豆を問い合わせるサービス
curl https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/getproducts
セール商品を問い合わせるサービス(末尾のパラメータに 0 を指定しています)
curl https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/getproducts/0
商品を販売します
curl -X POST https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/sellproduct/1/2
この実行結果の例は以下の通りです。
{"catalog_id":1,"product_code":"BRAZILDARK","quantity":38,"price":13.99,"time_roasted":"2021-02-03T09:00:00Z","roasting_notes":"Full bodied and low acidity. Thick, creamy, nutty and semi-sweet.","img":"brazil_dark.jpg"}
パート3:コーヒーストア用 Web アプリの構築
オリジナルページはこちら👉 https://gettingstarted.intersystems.com/full-stack/part-three-front-end/
Introduction
このチュートリアルの最後のパート 3 では、あなたが運営するコーヒーショップのオンライン storefront を作成します。
アプリケーションでは、Vue.js という JavaScript フレームワークを使用して、シングルページウェブアプリケーション(SPA)を作成しています。
Vue.js についての説明はこのチュートリアルの範囲外ですが、Vue.js を使用してどのように Web アプリケーションが構築されるか、また、パート2 で作成した REST サービスがこのアプリでどのように使用されているかを確認することができます。
コードをカスタマイズする
Web アプリケーション用コードは全て準備済です。実際に動かして動作を確認してみましょう。
まず、必要なパッケージのインストールを行います。インストールには数分かかります。また、インストール後にいくつかの編集を行います。
Sandbox の IDE のターミナルウィンドウで以下のコマンドを入力してください。
IDE へのリンク情報は、https://gettingstarted.intersystems.com/full-stack/part-three-front-end/#customize-code を開き、ログインすると以下図のように表示されます。
IDE などのアクセス情報の表示が、 のように表示されていたら、ピンク色のリンクをクリックしてください。
IDE のターミナルウィンドウで以下実行してください。インストールには数分時間がかかります。
cd /home/project/quickstarts-full-stack/frontend
npm install
npm install yarn
インストールが完了したら、お使いの IRIS サーバのアドレスをソースコードに指定します。
(1) IDE で quickstarts-full-stack > frontend > src > views > Home.vue を開きます。
(2) localhost:52773 と記載されている部分(url の設定)を、お使いの IRIS 用アドレスに書き換えます(例:52773-1-4e734fe2.try.learning.intersystems.com)。
https://gettingstarted.intersystems.com/full-stack/part-three-front-end/#customize-code を開き、「Customize the code」の近くにアクセス情報が表示されます。ご確認ください。
(3) IDE で quickstarts-full-stack > frontend > src > views > Sale.vue を開き、(2)と同様に、IRIS の接続情報を書き換えてください。
(4) IDE で quickstarts-full-stack > frontend > src > components > ProductCard.vue を開き、orderurl の設定を (2) と同様に、IRIS の接続情報を書き換えてください。
では、このアプリのテスト用の組み込み Web サーバで実行してみましょう。
(1) Sandbox の IDE のターミナルウィンドウで以下実行します(実行には時間がかかります)。
cd /home/project/quickstarts-full-stack/frontend
yarn serve
(2) ブラウザに、パート3の画面で指定された URL にアクセスしてください。
URL は https://gettingstarted.intersystems.com/full-stack/part-three-front-end/#store-view を開き、「View the storefront」の近くに表示されます。
URL にアクセスすると、以下の画面が表示されます。
Vue.js の中で、どのように実行されているか少し解説します。
React や Angular などの多くのフレームワークと同様に、URLはコンポーネントに「ルーティング」されます。
IDE で、quickstarts-full-stack > frontend > src > router > index.js を参照すると、デフォルトの URL パスである「/」が Home コンポーネントにルーティングされています。
Webアプリケーションで「/」 が指定されると、quickstarts-full-stack > frontend > src > views > Home.vue が表示され、/catalog/getproducts/1 を GET 要求で実行しています。
IRIS では、quickstarts-full-stack > services > cls > ICO > Handler.cls の GetProducts() メソッドが引数に 1 を指定された状態で実行され(=新鮮な豆を取得)過去5日間に焙煎されたすべての販売商品のリストをJSONで返します。
URL のパラメータに 1 を渡すか、指定しない場合、焙煎されたばかりのバッグのみが要求されます
GET https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/getproducts/1
実行結果例は以下の通りです。
{
"rowcount": 5,
"products": [{
"catalog_id": "1",
"product_code": "BRAZILDARK",
"quantity": 38,
"time_roasted": "2021-02-09 09:00:00",
"roasting_notes": "Full bodied and low acidity. Thick, creamy, nutty and semi-sweet.",
"img": "brazil_dark.jpg",
"price": 13.99
}, {
"catalog_id": "2",
"product_code": "ETHIOPIAMEDIUM",
"quantity": 40,
"time_roasted": "2021-02-08 09:00:00",
"roasting_notes": "Sweet floral notes, followed by the potent citrus notes, perfectly married into bergamot.",
"img": "ethiopia_medium.jpg",
"price": 14.99
}, {
"catalog_id": "3",
"product_code": "GUATEMALALIGHT",
"quantity": 120,
"time_roasted": "2021-02-09 17:30:00",
"roasting_notes": "Full body and a rich chocolatey-cocoa flavor, and a toffee-like sweetness.",
"img": "guatemala_light.jpg",
"price": 11.99
}, {
"catalog_id": "4",
"product_code": "SUMATRADARK",
"quantity": 80,
"time_roasted": "2021-02-07 13:01:30",
"roasting_notes": "Smooth and chocolaty with a sweet edge and minimal earthiness.",
"img": "sumatra_dark.jpg",
"price": 12.99
}, {
"catalog_id": "5",
"product_code": "SUMATRALIGHT",
"quantity": 40,
"time_roasted": "2021-02-07 09:00:00",
"roasting_notes": "This rich and juicy Sumatra carries sustained notes of cherry and citrus.",
"img": "sumatra_light.jpg",
"price": 12.99
}]
}
REST サービスの処理詳細については、quickstarts-full-stack > services > cls > ICO > Handler.cls の GetProducts() メソッドをご参照ください。
Home.vue は、JSON オブジェクトを繰り返し処理して、JSON 内の各アイテムに対して ProductCard (quickstarts-full-stack > frontend > src > components > ProductCard.vue) を作成します。
ProductCard.vue は、単一の商品を表示し、それを注文するための UI を作成する方法を知っているだけです。
では、Web ページの「Last chance」のリンクをクリックしてみましょう。
製品の短いリストが表示されるはずです(表示されない場合は、ICO.catalog テーブルの time_roasted の値をいくつか変更して、5日以上前の値にする必要があります)。この表示は、同じバックエンドのサービスを呼び出していますが、5日以上前の焙煎珈琲を返すようにパラメータを指定しています(1 以外の任意の数字を渡すことで指定できます)。
REST の呼び出しは以下の通りです。
GET /api/coffeeco/catalog/getproducts/2
応答結果例は、以下の通りです。
{
"rowcount": 1,
"products": [{
"catalog_id": "10",
"product_code": "SUMATRALIGHT",
"quantity": 40,
"time_roasted": "2021-02-02 09:00:00",
"roasting_notes": "This rich and juicy Sumatra carries sustained notes of cherry and citrus.",
"img": "sumatra_light.jpg",
"price": 12.99
}]
}
Home.vue と同様に、Sale.vue でも ProductCard コンポーネントを使用して商品を表示していますが、fetchProducts() 関数の実行結果(=RESTの応答)から ProductCard にデータを渡す前に価格を 3 ドル分値引きしています。
これは、コードを単純化するためにコンポーネントを再利用する簡単な例であり、価格設定と在庫管理を分離していることを示しています。
購入処理
いよいよチュートリアルの最後の項目です!コーヒーを買ってみましょう!
商品の数量を変更し「Place Order」ボタンをクリックします。注文が完了したことを示すポップアップが表示されるはずです(チュートリアルは架空サンプルです。実際のアプリであれば、ショッピングカートに商品を入れて、顧客が支払いを済ませるまで注文は行われないでしょう)。
チュートリアルは簡単な例としているため、ProductCard が RESTサービスの SellProduct() メソッドを呼び出し、注文されたコーヒー豆をカタログから取り出す様子を示しています。
REST 呼び出しは以下の通りです。
POST /api/coffeeco/catalog/sellproduct/商品のカタログID/販売したコーヒーバッグ数
POST要求なので、ブラウザからは実行できません。
IDE のターミナルを新規に開きます(Terminal > New Terminal)。
以下コマンドを新規ターミナルで実行してください。
コマンド実行例は、https://gettingstarted.intersystems.com/full-stack/part-three-front-end/#purchaseを開き、「Making a purchase」近くの表示をご確認ください。
curl -X POST https://52773-1-4e734fe2.try.learning.intersystems.com/api/coffeeco/catalog/sellproduct/1/2
応答結果の例は、以下の通りです。
{
"catalog_id": 1,
"product_code": "BRAZILDARK",
"quantity": 36,
"price": 13.99,
"time_roasted": "2021-02-09T09:00:00Z",
"roasting_notes": "Full bodied and low acidity. Thick, creamy, nutty and semi-sweet.",
"img": "brazil_dark.jpg"
}
ここでは、もう少しアプリケーションを使って遊んでいただく方法をご紹介します。
(1) 在庫が足りなくなるまで、コーヒーバッグを注文し続けます。最終的にはStorefront から商品を消滅させることができる予定です。
(2) Web 開発の経験がある方は、quickstarts-full-stack > frontend > src > components >ProductCard.vue コンポーネントの CSS を変更してみてください (ファイルの最後の <style> セクションにあります)。
(3) Vue.js の経験があれば、ProductCard.vue の processOrder() 関数で使われている基本的な JavaScript の警告メッセージを、もっと面白いものに変更してみましょう。また、独自のコンポーネントを作成して、ポップアップ・アラートの代わりにこの情報を表示することもできます。
最後に、Webアプリケーションの終了方法をご案内します。
Sandbox の IDE のターミナルウィンドウがプロンプトが戻っていない状態になっています。Web アプリケーションを終了して良い場合は、Ctrl + C を実行し、元のプロンプトに戻してください。
Next Steps
InterSystems IRIS の基本的な機能をご紹介しましたが、いかがでしたでしょうか。
このチュートリアルで学習したことを振り返ります。
パート1では、テーブル作成やデータの読み込みに SQL を使用し、直接ターミナルから SQL を入力したり、Python プログラムから実行する方法を確認しました。
パート2では、高速で柔軟なデータベースプログラミング言語である ObjectScript のご紹介と、ObjectScript を使用して RESTサービスを構築する方法をご紹介します。
パート3では、人気の高い JavaScript フレームワークを使って、顧客向けのフロントエンド Web アプリを構築する方法を学習しました。
以上でフルスタックチュートリアルは終了です!
最後までお付き合いいただきありがとうございました!
https://gettingstarted.intersystems.com/ には、まだまだ他のチュートリアルをご用意しています。ぜひご体験ください!
記事
Mihoko Iijima · 2020年12月28日
これは InterSystems FAQ サイトの記事です。
データベース暗号化は、ディスクヘの書き込みまたはディスクからの読み取りで暗号化と復号が実行されるため、アプリケーションのロジックに手を加える必要はありません。
この機能のドキュメントについては、以下ご参照ください。
マネージド・キー暗号化【IRIS】
マネージド・キー暗号化
暗号化データベース作成までの流れは、以下の通りです。
(1) 暗号化キーの作成
(a) 管理者 ユーザ名/パスワード
(b) 暗号化キーファイル
(2) 暗号化キーの有効化
(3) 暗号化されたデータベースの作成
暗号化データベース作成後の運用のための設定は以下の通りです。
〇 データベース暗号化の起動設定(暗号化キーの有効化をどのように行うか)
暗号化されたデータベースは、"暗号化キーの有効" が行われてアクセスできるようになります。既定の設定では、"暗号化キーの有効"を行いませんので、以下3種類の方法から選択します。
① キーを有効化しない起動の構成
既定の設定のまま、インスタンス起動時に "暗号化キーの有効" が行われません。暗号化されたデータベースをマウントする前に管理ポータルなどから "暗号化キーの有効" を行う必要があります。
以下の場合、この運用は適応できません。
起動時に暗号化データベースのマウントが必要な場合
暗号化されたジャーナル・ファイルを利用している場合
監査ログが暗号化されている場合
② インタラクティブ(対話式)にキーを有効化する起動の構成
インスタンス起動時に、インタラクティブに "暗号化キーの有効" を行います。
③ 無人でキーを有効化する起動の構成
インスタンス起動時に、自動的に "暗号化キーの有効" を行います。
セキュリティの強度については、①および②の運用の方が、③よりも強度が高くなります。詳細は、下記ドキュメントページをご確認ください。
データベース暗号化の起動設定の構成【IRIS】データベース暗号化の起動設定の構成
○暗号化キーファイル および 管理者とパスワードの管理方法(管理をどうするか)
暗号化キーの有効化するには以下の 2 つの情報が必要です。
(a) 管理者 ユーザ名/パスワード (b) 暗号化キーファイル
これらに関して、ファイルの損失、管理者のユーザ名/パスワードの失念や漏えい等から防ぐ方法については、以下のドキュメントページをご確認ください。
暗号化データのアクセスにおける偶発的な損失からの保護【IRIS】 暗号化データのアクセスにおける偶発的な損失からの保護
○ 緊急事態(緊急事態の対処方法)
緊急事態として以下の場合の対処については下記ページをご確認ください。
緊急事態【IRIS】 有効なキーが保存されているファイルが損傷したり紛失した場合【IRIS】 起動時に必要なデータベース暗号化キー・ファイルが存在しない場合【IRIS】
緊急事態 有効なキーが保存されているファイルが損傷したり紛失した場合 起動時に必要なデータベース暗号化キー・ファイルが存在しない場合
記事
Mihoko Iijima · 2021年4月22日
これは InterSystems FAQ サイトの記事です。
ルーチン(*.mac)の場合
ソースプログラムのコンパイル後に生成される *.obj のみをエクスポート/インポートすることでソースの隠蔽化を実現できます。
コマンド実行例は、EX1Sample.mac と EX2Sample.mac のコンパイルで生成される EX1Sample.obj と EX2Sample.obj をエクスポート対象に指定し、第2引数のファイルにエクスポートしています。
別ネームスペースに移動したあと、エクスポートした XML ファイルを利用してインポートを実行しています。
USER>do $system.OBJ.Export("EX1Sample.obj,EX2Sample.obj","/opt/app/routine.xml")
XMLエクスポートの開始 04/22/2021 18:18:32
オブジェクトコードをエクスポート中: EX1Sample.obj
オブジェクトコードをエクスポート中: EX2Sample.obj
エクスポートが正常に完了しました。
USER>zn "test" // ネームスペース移動
TEST>do $system.OBJ.Load("/opt/app/routine.xml")
ロード開始 04/22/2021 18:18:51
ファイル /opt/app/routine.xml を xml としてロード中
インポートしたオブジェクトコード: EX1Sample
インポートしたオブジェクトコード: EX2Sample
ロードが正常に完了しました。
TEST>
クラス(*.cls)の場合
クラスの場合は、XMLで *.cls をエクスポート/インポートしたあとに、サーバで MakeClassDeployed() を実行します。
ただし、比較的新しいバージョンでは MakeClassDeployed() 実行後、ソースファイル(*.cls)は配置モードに設定されるのみで(編集はできなくなります)参照のみ行える仕様になっています。
参照も不可にしたい場合は、MakeClassDeployed() 実行後、クラスの Hidden プロパティを設定します(プロパティの属性 Hidden=True に設定)。
コマンド実行例は以下の通りです。
USER>do $system.OBJ.Export("GPS.REST.cls,GPS.DriveData.cls","/opt/app/test.xml")
XMLエクスポートの開始 04/22/2021 18:05:13
クラスをエクスポート中: GPS.DriveData
クラスをエクスポート中: GPS.REST
エクスポートが正常に完了しました。
USER>zn "test" // testネームスペースに移動
TEST>do $system.OBJ.Load("/opt/app/test.xml","ck")
ロード開始 04/22/2021 18:07:21
ファイル /opt/app/test.xml を xml としてロード中
インポートしたクラス: GPS.DriveData
インポートしたクラス: GPS.REST
, 2 クラスをコンパイル中, 個のワーカー・ジョブを使用
クラスのコンパイル中 GPS.DriveData
クラスのコンパイル中 GPS.REST
テーブルのコンパイル中 GPS.DriveData
ルーチンのコンパイル中 GPS.REST.1
ルーチンのコンパイル中 GPS.DriveData.1
ロードが正常に完了しました。
TEST>do $system.OBJ.MakeClassDeployed("GPS.DriveData")
TEST>
CSP(*.csp)の場合
CSPファイルについては、*.cspをコピーし、配置先の CSP フォルダに貼付ます。
サーバでコンパイル後、CSPの設定で自動コンパイル OFF にしたあと、*.csp の削除と MakeClassDeployed() の実行を行います
実行例は以下の通りです。
1)CSPファイルのコピー後、サーバの CSP ディレクトリに貼付&コンパイル
TEST>do $SYSTEM.CSP.LoadPageDir("/csp/test")
2)ウェブアプリケーションパスの設定で「自動コンパイル」をいいえに設定
【バージョン2013.1以降】 [管理ポータル] > [システム管理] > [セキュリティ] > [アプリケーション] > [ウェブ・アプリケーション] > 該当するアプリケーション名のリンク
【バージョン201.1~バージョン2012.2】 [管理ポータル] > [システム管理] > [セキュリティ] > [アプリケーション] > [ウェブ・アプリケーション] > 該当するアプリケーション名の[編集]
【バージョン2010.2以前】 [システム管理ポータル] > [システム] > [セキュリティ管理] > [CSPアプリケーション] > 該当するアプリケーション名の[編集]
3)MakeClassDeployed() の実行
※cspsample.csp をコピーした場合の例
TEST>do $system.OBJ.MakeClassDeployed("csp.cspsample")
記事
Megumi Kakechi · 2022年10月6日
Caché/Ensemble 時代からご使用のお客様にはなじみの機能だと思いますが、IRISには「システムがインスタンスのメッセージログ/messages.log(Cachéの場合は コンソールログ/cconsole.log) を監視し、ログ・レベル2(重大なエラー) 以上 のアラートを受け取るとメールを送信する」ログ・モニター機能があります。この機能を使用すると、アラートログ (alerts.log)へのログ書き込み管理のほかに、メールを送信することもできます。
メール送信の設定は、^MONMGR ユーティリティを使用して簡単に行えます。
以下に、サンプルをご案内します。
USER>zn "%SYS"
%SYS>do ^MONMGR
1) Start/Stop/Update Log Monitor
2) Manage Log Monitor Options
3) Exit
Option? 2 <-- ログモニター管理の設定を行います
1) Set Monitor Interval
2) Set Alert Level
3) Manage Email Options
4) Exit
Option? 3 <-- Emailオプションの設定を行います
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? 1 <-- Email設定をにONにします
Email is currently OFF <-- 現在の設定は OFF
Change Email setting? No => yes <-- y または yes を入力します
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? 2 <-- 送信元の設定をします
Sender? aaa@bbb.com <-- 送信元のメールアドレスを設定します
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? 3 <-- メールサーバの設定を行います
Mail server? mail.bbb.com <-- メールサーバ
Mail server port? 25 => <-- メールサーバポート
Mail server SSLConfiguration? <-- (必要に応じて設定)
Mail server UseSTARTTLS? 0 => <-- (必要に応じて設定)
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? 4 <-- 送信先(受信者)情報の設定
1) List Recipients
2) Add Recipient
3) Remove Recipient
4) Exit
Option? 2 <-- 送信先メールアドレスの設定
Email Address? test@abcde.com <-- 送信先メールアドレス
1) List Recipients
2) Add Recipient
3) Remove Recipient
4) Exit
Option? <-- <Enter>
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? 6 <-- 送信テスト
Sending email on Mail Server mail.bbb.com
From: aaa@bbb.com
To: test@abcde.com
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option? <-- <Enter>
1) Set Monitor Interval
2) Set Alert Level
3) Manage Email Options
4) Exit
Option? <-- <Enter>
Update running Monitor? Yes => Yes <-- Y でモニター情報を更新
Updating Log Monitor... Log Monitor updated
1) Start/Stop/Update Log Monitor
2) Manage Log Monitor Options
3) Exit
Option?
%SYS>
上記テスト送信で、「%Monitor Email Test」の件名でメールが送られます。これで設定は完了です。
設定が完了したら、メッセージログにログレベルが 2(重大なエラー) 以上のログを書き込み、メールが送られるか確認してみましょう。
次のコマンドで、メッセージログ/コンソールログに任意のメッセージを書き込むことができます。
// 第3引数がログレベル。0 (情報), 1 (警告), 2 (重大なエラー), 3 (致命的なエラー)
write ##class(%SYS.System).WriteToConsoleLog("Test log message",0,2)
上記コマンドを実行すると、メッセージログに以下のようなログが書き込まれ、
10/05/22-15:18:23:537 (3688) 2 [Utility.Event] Test log message
[InterSystems IRIS SEVERE ERROR xxxxx:IRIS] [Utility.Event] Test log message のような件名でメールが送られます。
詳細は、以下のドキュメントをご覧ください。ログ・モニタの使用
IRISには便利なユーティリティが数多くあります。以下の記事で紹介しておりますので、ぜひお試しください。【ご参考】IRISで使用できるユーティリティ一覧
記事
Mihoko Iijima · 2023年4月10日
これは InterSystems FAQ サイトの記事です。
バージョン2017.2以降から、CREATE TABLE文で作成したテーブル定義のデータを格納するグローバル変数の命名ルールが変わり ^EPgS.D8T6.1 のようなハッシュ化したグローバル変数名が設定されます。(この変更はパフォーマンス向上のために追加されました。)
※ バージョン2017.1以前については、永続クラス定義のルールと同一です。詳細は関連記事「永続クラス定義のデータが格納されるグローバル変数名について」をご参照ください。
以下のテーブル定義を作成すると、同名の永続クラス定義が作成されます。
CREATE TABLE Test.Product(
ProductID VARCHAR(10) PRIMARY KEY,
ProductName VARCHAR(50),
Price INTEGER
)
永続クラス:Test.Productの定義は以下の通りです。(パラメータ:USEEXTENTSETに1が設定されます)
Class Test.Product Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {SuperUser}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = Product ]{Property ProductID As %Library.String(MAXLEN = 10) [ SqlColumnNumber = 2 ];Property ProductName As %Library.String(MAXLEN = 50) [ SqlColumnNumber = 3 ];Property Price As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ SqlColumnNumber = 4 ];Parameter USEEXTENTSET = 1;/// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement. Do not edit the SqlName of this index.Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ];/// DDL Primary Key SpecificationIndex PRODUCTPKEY1 On ProductID [ PrimaryKey, SqlName = PRODUCT_PKEY1, Type = index, Unique ];Storage Default{<Data name="ProductDefaultData"><Value name="1"><Value>ProductID</Value></Value><Value name="2"><Value>ProductName</Value></Value><Value name="3"><Value>Price</Value></Value></Data><DataLocation>^CCar.Wt3i.1</DataLocation><DefaultData>ProductDefaultData</DefaultData><ExtentLocation>^CCar.Wt3i</ExtentLocation><ExtentSize>0</ExtentSize><IdFunction>sequence</IdFunction><IdLocation>^CCar.Wt3i.1</IdLocation><Index name="DDLBEIndex"><Location>^CCar.Wt3i.2</Location></Index><Index name="IDKEY"><Location>^CCar.Wt3i.1</Location></Index><Index name="PRODUCTPKEY1"><Location>^CCar.Wt3i.3</Location></Index><IndexLocation>^CCar.Wt3i.I</IndexLocation><StreamLocation>^CCar.Wt3i.S</StreamLocation><Type>%Storage.Persistent</Type>}}
ExtentLocation:このクラスのグローバル名の生成に使用されるハッシュ値
DataLocation:レコードデータが登録されるグローバル変数名です。
Location:各インデックス固有のグローバル変数名が指定されます。
IndexLocation:この定義では、多くの場合使用されません。
StreamLocation:ストリームプロパティのデータが格納される変数です。
ストレージ定義に表示される情報について詳細は、ドキュメント「ハッシュ化したグローバル名」をご参照ください。
2017.1以前と同様の命名ルール(^スキーマ名.テーブル名D、I、S のグローバル変数名)を使用する場合は、CREATE TABLE文実行時に以下のクラスパラメータを指定します。
WITH %CLASSPARAMETER USEEXTENTSET = 0
CREATE TABLE Test2.Product(
ProductID VARCHAR(10) PRIMARY KEY,
ProductName VARCHAR(50),
Price INTEGER
)
WITH %CLASSPARAMETER USEEXTENTSET = 0
永続クラス定義:Test2.Productのパラメータ:USEEXTENTSETは以下のように定義されます。
Parameter USEEXTENTSET = 0;
永続クラス定義:Test2.Productのストレージ定義は以下の通りです。
Storage Default{<Data name="ProductDefaultData"><Value name="1"><Value>ProductID</Value></Value><Value name="2"><Value>ProductName</Value></Value><Value name="3"><Value>Price</Value></Value></Data><DataLocation>^Test2.ProductD</DataLocation><DefaultData>ProductDefaultData</DefaultData><IdFunction>sequence</IdFunction><IdLocation>^Test2.ProductD</IdLocation><IndexLocation>^Test2.ProductI</IndexLocation><StreamLocation>^Test2.ProductS</StreamLocation><Type>%Storage.Persistent</Type>}
WITHで指定したテーブルのオプションについては詳しくは、ドキュメント「テーブルのオプション」をご参照ください。
関連記事:永続クラス定義のデータが格納されるグローバル変数名について
記事
Megumi Kakechi · 2023年4月11日
これは InterSystems FAQ サイトの記事です。
Question:
TIMESTAMP型の項目に対して、TO_CHAR() や TO_DATE() を用いた SELECT を実行すると以下のエラーになります。
実行SQL:
select
TO_CHAR(xxxDateTime,'YYYY-MM-DD')
from
Test
エラー: [SQLCODE: <-400>:<深刻なエラーが発生しました>] [%msg: <Unexpected error occurred: <ZCHAR>IllegalValuePassedToTOCHAR^%qarfunc>]
エラーの原因を教えてください。
Answer:
こちらは、IRIS2022.1以降のバージョンで CREATE TABLE (DDL) の TIMESTAMP 型が IRIS側クラスで %Library.PosixTime にマッピングするように変更されているためです。(アップグレードした環境の場合は、従来のままの %Library.TimeStamp にマッピングされています)
%TimeStamp は、データを人が読める文字列(yyyy-mm-dd hh:mm:ss.ffff)として保存します。対して、%PosixTime は64bitの整数で保持するため、ディスクやメモリ上のデータサイズを削減し、比較演算処理等のパフォーマンスが向上します。SQLクエリを高速化したい場合は、%PosixTime を使用されることをお勧めします。
TIMESTAMP型を、従来と同じ %TimeStamp にマッピングするDDLデータ型としては TIMESTAMP2 が用意されています。CREATE TABLE文で、TIMESTAMP型にしたいフィールドの箇所を TIMESTAMP2 とすることで %TimeStamp とすることができます。
例:
create table Test2 (xxxDateTime TIMESTAMP, xxxDateTime2 TIMESTAMP2)
※ xxxDateTime は %PosixTime 、xxxDateTime2 は %TimeStamp となる。全体の設定変更で対応する場合は、 管理ポータル: [システム管理] > [構成] > [SQLとオブジェクトの設定] > [システムDDLマッピング]より TIMESTAMP 行の 「編集」をクリックしてデータタイプを %Library.PosixTime から %Library.TimeStamp に変更します。
↓
この設定変更後に実行される CREATE TABLEより、この変更が反映されるようになります。管理ポータルで現在のテーブルのフィールドがどちらのデータタイプになっているかを確認できます。
管理ポータル: [システムエクスプローラ] > [SQL]
Tips:
%PosixTime のフィールドから YYYY-MM-DD の日付部分のみを取得したい場合は、次のように一旦TIMESTAMPにCAST()してから TO_CHAR() を使用します。
select
xxxDateTime,
to_char(cast(xxxDateTime as timestamp),'YYYY-MM-DD')
from
Test
%PosixTime のデータの Insert は %TimeStamp と同じように行えます。
USER>do $SYSTEM.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]USER>>set selectmode=odbc // ODBCモードでテスト
selectmode = odbc
[SQL]USER>>insert into Test2 (xxxDateTime, xxxDateTime2) values ('2023-02-20 13:45:00','2023-02-20 13:45:00')
6. insert into Test2 (xxxDateTime, xxxDateTime2) values ('2023-02-20 13:45:00','2023-02-20 13:45:00')
1 Row Affected
statement prepare time(s)/globals/cmds/disk: 0.0010s/32/4,002/0ms
execute time(s)/globals/cmds/disk: 0.0002s/3/183/0ms
cached query class: %sqlcq.XXX.cls12
---------------------------------------------------------------------------
[SQL]USER>>select * from Test2 // そのままSelect(※ xxxDateTime :%PosixTime , xxxDateTime2 :%TimeStamp )
7. select * from Test2
xxxDateTime xxxDateTime2
2023-02-20 13:45:00 2023-02-20 13:45:00
1 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0004s/26/978/0ms
execute time(s)/globals/cmds/disk: 0.0001s/2/528/0ms
cached query class: %sqlcq.XXX.cls13
---------------------------------------------------------------------------
[SQL]USER>>q
USER>zw ^poCN.Dqym.1 // %PosixTime型で実際に格納されているデータは64bit整数
^poCN.Dqym.1=1
^poCN.Dqym.1(1)=$lb(1154598405306846976,"2023-02-20 13:45:00")
現在日時を%PosixTime型で出力したり、%TimeStamp ⇔ %PosixTime 変換したい場合は以下のように行えます。
USER>write ##Class(%Library.PosixTime).CurrentTimeStamp()
1154596073773251031
USER>write ##Class(%Library.PosixTime).LogicalToTimeStamp(ptime)
2023-01-24 14:06:06.404055
USER>write ##Class(%Library.PosixTime).TimeStampToLogical("2023-01-24 14:06:06.404055")
1154596073773251031
詳細は以下のドキュメントをご覧ください日付、時刻、PosixTime、およびタイムスタンプのデータ型【ご参考】%TimeStamp型プロパティを使用した範囲指定のクエリが遅い場合の対処方法SQLベースのベンチマークを行う際に、実施していただきたい5つの項目
記事
Tomoko Furuzono · 2023年7月2日
これは、InterSystems FAQサイトの記事です。
以下の様な方法で、グローバルのインポート/エクスポート処理をプログラムに組み込むことができます。
1. グローバルエクスポート方法1.1 XML形式でのエクスポートグローバルをXML形式のファイルにエクスポートする場合、$system.OBJ.Export() を使用します。 1.1.1. 指定したグローバルをエクスポートする場合エクスポート対象グローバルを グローバル名.gbl で指定します(先頭の ^ は不要)。例:
Do $system.OBJ.Export("a.gbl,b.gbl","c:\temp\globals.xml",,.errors)
結果については、errors に格納されます。
$system.OBJ.Export() の詳細は%SYSTEM.OBJクラスのクラスリファレンスをご確認ください。クラスリファレンス:%SYSTEM.OBJ1.1.2. ネームスペース内の全グローバルをエクスポートする場合%SYS.GlobalQueryクラスでグローバル一覧を取得し、それを $system.OBJ.Export() に渡してエクスポートを実行します。
例:
Set rs=##class(%ResultSet).%New("%SYS.GlobalQuery:NameSpaceList")
Do rs.Execute()
Kill globals
While rs.Next() {
Set globals(rs.Get("Name")_".gbl")=""
}
Do $system.OBJ.Export(.globals,"c:\temp\allglobal.xml",,.errors)
(ここでは簡略化のためエラーチェックは省略しています)
1.2. ブロック形式でのエクスポート(%GOFユーティリティと同等)ブロック形式でグローバルをエクスポートするには、クラス %Library.Global のメソッドExport() を使用します。エクスポート対象グローバルは、1.1.1と同じ形式で指定します。各引数の詳細はクラスリファレンスをご確認ください。クラスリファレンス:%Library.Global
例:
USER>Set status=##class(%Library.Global).Export(,"a.gbl,b.gbl","c:\test.gof",7)
GO/GOF形式でエクスポートの開始 07/23/2008 17:01:03
グローバルをエクスポート中: ^a
グローバルをエクスポート中: ^b
エクスポートが正常に完了しました。
USER>
2. グローバルインポート方法2.1 XML形式ファイルのインポート2.1.1 ファイルに含まれる全グローバルをインポートするXMLファイルに含まれる全グローバルをインポートするには $system.OBJ.Load() を使用します。
例:
Do $system.OBJ.Load("c:\temp\globals.xml",,.errors)
2.1.2 ファイルに含まれるグローバルのうち一部のみをインポートするXMLファイルに含まれる一部のグローバルのみ選択してインポートする場合、一旦$system.OBJ.Load() で 第5引数の listonly を 1 に設定してXMLファイルを読み込み、第4引数(出力引数)で得られたリストからインポート対象を選択して第6引数で指定します。例:
Set file="c:\temp\globals.xml"
// まずXMLに含まれるアイテム一覧を取得
Do $system.OBJ.Load(file,,.errors,.list,1 /* listonly */)
Set item=$Order(list(""))
Kill loaditem
While item'="" {
If item["Sample" { // Sample を含むもののみインポート
Set loaditem(item)=""
Set item=$Order(list(item))
}
}
// 作成されたリストでインポート処理実行
Do $system.OBJ.Load(file,,.errors,,,.loaditem)
2.2 ブロック形式でのインポート(%GIFユーティリティと同等)ブロック形式でエクスポートされたグローバルをインポートするには、$system.OBJ.Load() またはクラス %Library.Global の Import() メソッドを使用します。 ファイル中の特定のグローバルのみインポートする場合は、2.1.2と同じ方法が使用できます。例1:
USER>Do $system.OBJ.Load("c:\test.gof")
ロード開始 07/23/2008 17:01:49
ファイル c:\test.gof を gbl としてロード中
インポートしたグローバル: ^a
インポートしたグローバル: ^b
ロードが正常に完了しました。
USER>
例2:
USER>Set status=##class(%Library.Global).Import(,"*","c:\test.gof",7)
記事
Toshihiko Minamoto · 2021年9月1日
記事で使用されているすべてのソースコード: https://github.com/antonum/ha-iris-k8s
[前の記事](https://jp.community.intersystems.com/node/490971)では、従来型のミラーリングではなく分散ストレージに基づいて、高可用性のあるk8sでIRISをセットアップする方法について説明しました。 その記事では例としてAzure AKSクラスタを使用しました。 この記事では引き続き、k8sで可用性の高い構成を詳しく見ていきますが、 今回は、Amazon EKS(AWSが管理するKubernetesサービス)に基づき、Kubernetes Snapshotに基づいてデータベースのバックアップと復元を行うためのオプションが含まれます。
## インストール
早速作業に取り掛かりましょう。 まず、AWSアカウントが必要です。[AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)、[kubectl](https://kubernetes.io/docs/tasks/tools/)、および[eksctl](https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html)ツールがインストールされている必要があります。 新しいクラスタを作成するために、次のコマンドを実行します。
eksctl create cluster \
--name my-cluster \
--node-type m5.2xlarge \
--nodes 3 \
--node-volume-size 500 \
--region us-east-1
このコマンドは約15分掛けてEKSクラスタをデプロイし、それをkubectlツールのデフォルトのフォルダに設定します。 デプロイを確認するには、次のコードを実行します。
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-19-7.ca-central-1.compute.internal Ready <none> 18d v1.18.9-eks-d1db3c
ip-192-168-37-96.ca-central-1.compute.internal Ready <none> 18d v1.18.9-eks-d1db3c
ip-192-168-76-18.ca-central-1.compute.internal Ready <none> 18d v1.18.9-eks-d1db3c
次に、Longhorn分散ストレージエンジンをインストールします。
kubectl create namespace longhorn-system
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.1.0/deploy/iscsi/longhorn-iscsi-installation.yaml --namespace longhorn-system
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml --namespace longhorn-system
そして最後に、IRIS自体をインストールします。
kubectl apply -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml
この時点で、Longhorn分散ストレージとIRISデプロイがインストールされたEKSクラスタが完全に機能できる状態になります。 前の記事に戻って、クラスタとIRISデプロイにあらゆるダメージを与えて、システムがどのように修復するのかを確認するとよいでしょう。 「[障害をシミュレートする](https://community.intersystems.com/post/highly-available-iris-deployment-kubernetes-without-mirroring)」セクションをご覧ください。
## 特典1 ARM上のIRIS
IRIS EKSとLonghornはARMアーキテクチャをサポートしているため、ARMアーキテクチャに基づき、AWS Gravition 2インスタンスを使用して同じ構成をデプロイできます。
EKSノードのインスタンスタイプを 'm6g' ファミリーに変更し、IRISイメージをARMベースに変更するだけです。
eksctl create cluster \
--name my-cluster-arm \
--node-type **m6g.2xlarge** \
--nodes 3 \
--node-volume-size 500 \
--region us-east-1
tldr.yaml
containers:
#- image: store/intersystems/iris-community:2020.4.0.524.0
- image: store/intersystems/irishealth-community-arm64:2020.4.0.524.0
name: iris
または、単に以下を使用します。
kubectl apply -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr-iris4h-arm.yaml
以上です! ARMプラットフォームで実行するIRIS Kubernetesクラスタが出来上がりました。
## 特典2 - バックアップと復元
本番環境グレードのアーキテクチャでよく見過ごされがちな部分に、データベースのバックアップを作成して必要なときに素早く復元するか複製する機能があります。
Kubernetesでは、一般的にPersistent Volume Snapshots(永続ボリュームスナップショット)を使用してこれを行います。
まず、必要なすべてのk8sコンポーネントをインストールする必要があります。
#Install CSI Snapshotter and CRDs
kubectl apply -n kube-system -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -n kube-system -f https://github.com/kubernetes-csi/external-snapshotter/raw/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -n kube-system -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
kubectl apply -n kube-system -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
kubectl apply -n kube-system -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
次に、LonghornのS3バケット資格情報を構成します([詳細な手順](https://longhorn.io/docs/1.1.0/snapshots-and-backups/backup-and-restore/set-backup-target/)を参照)。
#Longhorn backup target s3 bucket and credentials longhorn would use to access that bucket
#See https://longhorn.io/docs/1.1.0/snapshots-and-backups/backup-and-restore/set-backup-target/ for manual setup instructions
longhorn_s3_bucket=longhorn-backup-123xx #bucket name should be globally unique, unless you want to reuse existing backups and credentials
longhorn_s3_region=us-east-1
longhorn_aws_key=AKIAVHCUNTEXAMPLE
longhorn_aws_secret=g2q2+5DVXk5p3AHIB5m/Tk6U6dXrEXAMPLE
以下のコマンドは、前の手順から環境変数を拾い、それを使ってLonghorn Backupを構成します。
#configure Longhorn backup target and credentials
cat <<EOF | kubectl apply -f -
apiVersion: longhorn.io/v1beta1
kind: Setting
metadata:
name: backup-target
namespace: longhorn-system
value: "s3://$longhorn_s3_bucket@$longhorn_s3_region/" # backup target here
---
apiVersion: v1
kind: Secret
metadata:
name: "aws-secret"
namespace: "longhorn-system"
labels:
data:
# echo -n '<secret>' | base64
AWS_ACCESS_KEY_ID: $(echo -n $longhorn_aws_key | base64)
AWS_SECRET_ACCESS_KEY: $(echo -n $longhorn_aws_secret | base64)
---
apiVersion: longhorn.io/v1beta1
kind: Setting
metadata:
name: backup-target-credential-secret
namespace: longhorn-system
value: "aws-secret" # backup secret name here
EOF
たくさんの作業に見えるかもしれませんが、基本的にLonghornに対し、指定された資格情報で特定のS3バケットを使用し、バックアップのコンテンツを保存するように指示しています。
以上です! Longhorn UIに移動すると、バックアップを作成して復元などを行えるようになっています。

Longhorn UIに接続する方法を簡単におさらいしましょう。
kubectl get pods -n longhorn-system
# note the full pod name for 'longhorn-ui-...' pod
kubectl port-forward longhorn-ui-df95bdf85-469sz 9000:8000 -n longhorn-system
これによって、Longhorn UIへのトラフィックはhttp://localhost:9000に転送されるようになります。
## プログラムによるバックアップ/復元
Longhorn UIを介して行うバックアップと復元は、最初のステップとしては十分かもしれませんが、もう一歩先に進み、k8s Snapshot APIを使用して、プログラムでバックアップと復元を実行してみましょう。
まず、スナップショットそのものが必要です。 iris-volume-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: iris-longhorn-snapshot
spec:
volumeSnapshotClassName: longhorn
source:
persistentVolumeClaimName: iris-pvc
このボリュームスナップショットは、IRISデプロイに使用するソースボリュームである 'iris-pvc' を参照しています。 そのため、これを適用するだけですぐにバックアッププロセスが開始します。
IRIS書き込みデーモンの凍結と解凍をスナップショットの前後に実行することをお勧めします。
#Freeze Write Daemon
echo "Freezing IRIS Write Daemon"
kubectl exec -it -n $namespace $pod_name -- iris session iris -U%SYS "##Class(Backup.General).ExternalFreeze()"
status=$?
if [[ $status -eq 5 ]]; then
echo "IRIS WD IS FROZEN, Performing backup"
kubectl apply -f backup/iris-volume-snapshot.yaml -n $namespace
elif [[ $status -eq 3 ]]; then
echo "IRIS WD FREEZE FAILED"
fi
#Thaw Write Daemon
kubectl exec -it -n $namespace $pod_name -- iris session iris -U%SYS "##Class(Backup.General).ExternalThaw()"
復元プロセスは非常に簡単です。 基本的には、新しいPVCを作成して、スナップショットをソースとして指定しています。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: iris-pvc-restored
spec:
storageClassName: longhorn
dataSource:
name: iris-longhorn-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
次に、このPVCに基づいて新しいデプロイを作成するだけです。 これを順に行うこちらの[GitHubリポジトリにあるテストスクリプト](https://github.com/antonum/ha-iris-k8s/blob/main/backup/test.sh)をご覧ください。
* まったく新しいIRISデプロイを作成します。
* IRISにデータを追加します。
* 書き込みデーモンを凍結し、スナップショットを取得して、書き込みデーモンを解凍します。
* そのスナップショットをベースに、IRISデプロイのクローンを作成します。
* すべてのデータが含まれていることを確認します。
この時点で、同一のIRISデプロイが2つ存在することになります。1つはもう片方のデプロイのclone-via-backupです。
どうぞお楽しみください!
記事
Toshihiko Minamoto · 2022年11月8日
パート 1 では、Django で新しいプロジェクトを開始する方法を紹介し、新しいモデルの定義方法と既存のモデルの追加方法を説明しました。 今回は、初期状態で利用可能な管理者パネルとどのように役立つかについて説明します。 _重要な注意事項: この記事のアクションを繰り返しても、動作しません。 記事の途中で、django-iris プロジェクトにいくつか修正を行い、InterSystems が作成した DB-API ドライバーの課題もいくつか修正しました。このドライバーは現在の開発中であり、将来的に、より安定したドライバーが提供されると思います。 この記事では、すべてを実行した場合にどのようになるかを説明しているにすぎません。_ コードに戻り、すべてのウェブリクエストのメインのエントリポイントである urls.py にある内容を確認しましょう。
"""main URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
すでに URL **_admin_** がそこに定義されているのが分かります。 開発サーバーをコマンドで起動しましょう。
python manage.py runserver
URL _http://localhost:8000/admin_ に移動すると、Django 管理のログインフォームが表示されます。 .png) ここには何らかのユーザーが必要であるため、次のコマンドでそのユーザーを作成します。
$ python manage.py createsuperuser
Username (leave blank to use 'daimor'): admin
Email address: admin@example.com
Password:
Password (again):
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
このログインとパスワードをここで使用します。 現時点ではあまり何もありませんが、グループとユーザーにはアクセスできるようになっています。
その他のデータ
前回、zpm で post-and-tags パッケージをインストールしました。ここでも同じことを行えます。
zpm "install posts-and-tags"
次に、このパッケージでインストールされたすべてのテーブル(_community.post、community.comment、community.tag_)のモデルを取得します。
$ python manage.py inspectdb community.post community.comment community.tag > main/models.py
これにより多少長いファイルが生成されるので、スポイラーとして記載します。
main/models.py
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models
class CommunityPost(models.Model):
acceptedanswerts = models.DateTimeField(db_column='AcceptedAnswerTS', blank=True, null=True) # Field name made lowercase.
author = models.CharField(db_column='Author', max_length=50, blank=True, null=True) # Field name made lowercase.
avgvote = models.IntegerField(db_column='AvgVote', blank=True, null=True) # Field name made lowercase.
commentsamount = models.IntegerField(db_column='CommentsAmount', blank=True, null=True) # Field name made lowercase.
created = models.DateTimeField(db_column='Created', blank=True, null=True) # Field name made lowercase.
deleted = models.BooleanField(db_column='Deleted', blank=True, null=True) # Field name made lowercase.
favscount = models.IntegerField(db_column='FavsCount', blank=True, null=True) # Field name made lowercase.
hascorrectanswer = models.BooleanField(db_column='HasCorrectAnswer', blank=True, null=True) # Field name made lowercase.
hash = models.CharField(db_column='Hash', max_length=50, blank=True, null=True) # Field name made lowercase.
lang = models.CharField(db_column='Lang', max_length=50, blank=True, null=True) # Field name made lowercase.
name = models.CharField(db_column='Name', max_length=250, blank=True, null=True) # Field name made lowercase.
nid = models.IntegerField(db_column='Nid', primary_key=True) # Field name made lowercase.
posttype = models.CharField(db_column='PostType', max_length=50, blank=True, null=True) # Field name made lowercase.
published = models.BooleanField(db_column='Published', blank=True, null=True) # Field name made lowercase.
publisheddate = models.DateTimeField(db_column='PublishedDate', blank=True, null=True) # Field name made lowercase.
subscount = models.IntegerField(db_column='SubsCount', blank=True, null=True) # Field name made lowercase.
tags = models.CharField(db_column='Tags', max_length=350, blank=True, null=True) # Field name made lowercase.
text = models.TextField(db_column='Text', blank=True, null=True) # Field name made lowercase.
translated = models.BooleanField(db_column='Translated', blank=True, null=True) # Field name made lowercase.
type = models.CharField(db_column='Type', max_length=50, blank=True, null=True) # Field name made lowercase.
views = models.IntegerField(db_column='Views', blank=True, null=True) # Field name made lowercase.
votesamount = models.IntegerField(db_column='VotesAmount', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'community.post'
class CommunityComment(models.Model):
id1 = models.CharField(db_column='ID1', primary_key=True, max_length=62) # Field name made lowercase.
acceptedanswerts = models.DateTimeField(db_column='AcceptedAnswerTS', blank=True, null=True) # Field name made lowercase.
author = models.CharField(db_column='Author', max_length=50, blank=True, null=True) # Field name made lowercase.
avgvote = models.IntegerField(db_column='AvgVote', blank=True, null=True) # Field name made lowercase.
correct = models.BooleanField(db_column='Correct', blank=True, null=True) # Field name made lowercase.
created = models.DateTimeField(db_column='Created', blank=True, null=True) # Field name made lowercase.
hash = models.CharField(db_column='Hash', max_length=50, blank=True, null=True) # Field name made lowercase.
id = models.IntegerField(db_column='Id') # Field name made lowercase.
post = models.CharField(db_column='Post', max_length=50, blank=True, null=True) # Field name made lowercase.
text = models.TextField(db_column='Text', blank=True, null=True) # Field name made lowercase.
texthash = models.CharField(db_column='TextHash', max_length=50, blank=True, null=True) # Field name made lowercase.
type = models.CharField(db_column='Type', max_length=50) # Field name made lowercase.
votesamount = models.IntegerField(db_column='VotesAmount', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'community.comment'
unique_together = (('type', 'id'),)
class CommunityTag(models.Model):
description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase.
name = models.TextField(db_column='Name', primary_key=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'community.tag'
Django の管理ダッシュボードは、開発者が拡張できるようになっています。 また、テーブルをさらに追加することも可能です。 それには、main/admin.py という新しいファイルを追加する必要があります。コード内には、行を説明するコメントをいくつか追加しています。
from django.contrib import admin
# immport our community models for our tables in IRIS
from .models import (CommunityPost, CommunityComment, CommunityTag)
# register class which overrides default behaviour for model CommunityPost
@admin.register(CommunityPost)
class CommunityPostAdmin(admin.ModelAdmin):
# list of properties to show in table view
list_display = ('posttype', 'name', 'publisheddate')
# list of properties to show filter for on the right side of the tablee
list_filter = ('posttype', 'lang', 'published')
# default ordering, means from the latest date of PublishedDate
ordering = ['-publisheddate', ]
@admin.register(CommunityComment)
class CommunityCommentAdmin(admin.ModelAdmin):
# only this two fields show, (post is numeric by id in table post)
list_display = ('post', 'created')
# order by date of creation
ordering = ['-created', ]
@admin.register(CommunityTag)
class CommunityTagAdmin(admin.ModelAdmin):
# not so much to show
list_display = ('name', )
ポータルの拡張
Django 管理ページに戻り、そこに追加された新しい項目を確認しましょう。
右側には、フィルタパネルがあります。最も重要なのは、特定のフィールドの可能値がすべて表示されている点です。
残念ながら、InterSystems SQL は Django で期待されているまたは Django の別の方法である LIMIT, OFFSET をサポートしていません。 また、Django は TOP をサポートしていません。 そのため、ここにページ送りは表示されますが、機能しません。 また、現時点では機能できるようにもできません。残念ながら個人的には、今後も機能することはないと思っています。
オブジェクトを詳しく調べることも可能で、Django には正しいフィールド型っを使ったフォームが表示されます。(注意: このデータセットには、テキストフィールドのデータは含まれません)
コメントオブジェクト
Community Edition ではライセンスに関する課題が予想されます。
Community Edition を使用している場合は、この問題に直面する可能性があります。これは、すべての接続が占有されている場合の様子であり、非常に素早く発生する問題です。 サーバーのレスポンスが非常に遅くなっている場合は、おそらくその問題に該当しています。IRIS はこのケースでは素早く応答せず、不明な理由により、長い時間がかかっています。
IRIS が空き枠あると示す場合であってもです。
6 個以上の接続を許可しないため、動作させるには、1つ以上のプロセスを終了するか、Django サーバーを再起動しなければなりません。
開発時には、Django サーバーを非スレッドモードに制限することもできるため、1つのプロセスで動作させられます。 また、IRIS への接続をさらに取得してはいけません。
python manage.py runserver --nothreading
記事
Mihoko Iijima · 2020年11月10日
これはInterSystems FAQ サイトの記事です。
インデックスが複数定義されているクラス/テーブルへ csv 形式等のシーケンシャルファイルから大量データをデータベースに登録する際、推奨される登録方法として、データ登録時インデックスを生成させず、登録完了後に一括でインデックスを生成する 方法があります。
この方法は、新規に大量のレコードを一括登録する際に最も有効な手段となります。
<メモ>大量のデータを追加登録する際には、既存のデータ量と新規データ量のバランスにより、この手法が有効でないケースもあります。その場合は、インデックスの再構築を範囲指定で行うこともできます。
説明に使用するクラス定義例は以下の通りです。
Class ISJ.QL2 Extends %Persistent
{
Property Name As %String;
Property Title As %String;
Property Sex As %String;
Property Company As %String;
Property Phone As %String;
Property City As %String;
Property State As %String;
Property Zip As %String;
Index NameIndex On Name;
Index CompanyIndex On Company;
Index PhoneIndex On Phone;
}
データロードを行うクラスメソッド例は以下の通りです。
ClassMethod ImportFromFile(pFile As %String)
{
#dim Err As %Exception.AbstractException
//埋め込みSQLを使用してインポート
Try {
if $get(pFile)="" {
write "インポートファイルを指定してください",!
quit
}
if ##class(%File).Exists(pFile)=0 {
write "指定したファイルは存在しません。ファイル名、パスを確認してください",!
quit
}
set filestream=##class(%Stream.FileCharacter).%New()
do filestream.LinkToFile(pFile)
set tDelim=";"
while filestream.AtEnd=0 {
//改行があるところまでRead
set tLine=filestream.ReadLine()
set pCity = $Piece(tLine,tDelim,1) //City
set pCompany = $Piece(tLine,tDelim,2) //Company
set pName = $Piece(tLine,tDelim,3) //Name
set pPhone = $Piece(tLine,tDelim,4) //Phone
set pSex = $Piece(tLine,tDelim,5) //Sex
set pState = $Piece(tLine,tDelim,6) //State
set pTitle = $Piece(tLine,tDelim,7) //Title
set pZip = $Piece(tLine,tDelim,8) //Zip
&sql(INSERT %NOINDEX INTO ql2 (Name, Title, Sex, Company, Phone, City, State, Zip) values (:pName, :pTitle, :pSex, :pCompany, :pCity, :pCity, :pState, :pZip))
// SQL文でエラーがある場合の処理
if SQLCODE<0 {
throw ##class(%Exception.SQL).CreateFromSQLCODE(SQLCODE,%msg)
}
}
// 最後にテーブルのインデックス再構築を実行
set st=..%BuildIndices()
$$$THROWONERROR(Err,st) // エラーが発生した場合Catchへ移動
}
Catch Err {
write "エラーが発生しました",!
write Err.DisplayString(),!
}
}
クラスメソッドでは、以下のデータ形式で作成されたファイルを入力しながらデータ登録後にインデックスを構築しています(ランダム生成させたデータを使用しています)。
;京都市上京区;新光損保 株式会社;橋本,京子;0363-7728-2499;女;京都府;国際製品スペシャリスト;6020808;札幌市西区;NTS工業 株式会社;本田,亮;0325-6753-6990;男;北海道;アシスタント管理者;0630003;呉市;セコミ薬品 株式会社;川原,明雄;0670-9635-5468;男;広島県;副衛生士;7370145;春日部市;SESコミュニケーションズ 株式会社;大島,江美;0407-3421-5865;女;埼玉県;研究ディレクタ;3440065;上高井郡小布施町;電金証券 有限会社;松本,亮;053-3208-4665;女;長野県;副会計士;3810202;茅野市;ビーエスシ薬品 株式会社;渡部,弘明;0996-5061-8567;女;長野県;国際マーケティングマネージャ;3910212;中川郡豊頃町;電金技研 有限会社;根本,由貴;0647-5142-4961;男;北海道;国際ウェブマスタ;0895461;尼崎市;SES石油 有限会社;川口,博美;0744-3148-1523;男;兵庫県;副会計士;6610978;北松浦郡吉井町;三友製造 株式会社;阿部,陽子;0554-2270-3308;男;長崎県;副システムエンジニア;8596304
サンプルコードの以下の文で、全レコードに対してインデックスを構築しています。
Do ..%BuildIndices()
サンプルコードで使用している埋め込み SQL では、実行後に %ROWID 変数を使用して INSERT によって設定された ID 値を取得できます。
例えば、INSERT したレコードのインデックスのみを構築したい場合は、%BuildIndices() メソッドの第 2 引数(pAutPurge)に 0 を指定し、第 5 引数(pStartID)および第 6 引数(pEndID)に ID を指定することで実行できます。
インデックス構築方法について詳細は、ドキュメントもご参照ください。
記事
Mihoko Iijima · 2021年2月12日
これは InterSystems FAQ サイトの記事です。
XMLファイルの内容を格納する永続クラス定義を作成し、%XML.Adaptor を追加で継承します。
例は以下の通りです(右端の %XML.Adaptorクラスを追加で継承します)。
Class ISJ.Class1 Extends (%Persistent, %Populate, %XML.Adaptor)
次に、%XML.Reader クラスを使用して格納先のインスタンスへ、タグとクラスの関連付け(Correlate())を行い、reader.Next() でXMLを取り込みます。
set sc=reader.OpenFile(filename)
do reader.Correlate(tag,class)
while reader.Next(.x,.sc) { do x.%Save() }
サンプルコードは以下の通りです。
Class ISJ.Class1 Extends (%Persistent, %Populate, %XML.Adaptor)
{
Property a As %String;
Property b As %String;
/// 引数:入力するXMLファイルのフルパス
ClassMethod Import(filename As %String)
{
if $get(filename)="" {
write "入力ファイルを引数に指定してください",!
quit
}
// クラス名指定(..%ClassName()でクラスメソッドの存在するクラス名を返します)
set class=..%ClassName(1)
// XMLタグ指定
set tag="test"
set reader = ##class(%XML.Reader).%New()
set sc=reader.OpenFile(filename)
If $$$ISERR(sc) {
write $system.Status.GetErrorText(sc),!
Quit
}
// クラスとの関連付け
do reader.Correlate(tag,class)
while reader.Next(.x,.sc) {
set sc=x.%Save()
If $$$ISERR(sc) {
write $system.Status.GetErrorText(sc),!
Quit
}
}
quit
}
}
入力するXMLファイル例は以下の通りです。
<?xml version="1.0" encoding="UTF-8"?>
<top><test>
<a>あいうえお</a>
<b>かきくけこ</b>
</test>
<test>
<a>O8634</a>
<b>H7321</b>
</test>
<test>
<a>J5426</a>
<b>V2218</b>
</test>
<test>
<a>J7155</a>
<b>M6804</b>
</test>
<test>
<a>R7066</a>
<b>W939</b>
</test>
<test>
<a>B9731</a>
<b>I406</b>
</test>
<test>
<a>I1095</a>
<b>Z5125</b>
</test>
<test>
<a>Q1573</a>
<b>Z9241</b>
</test>
<test>
<a>T7560</a>
<b>V5693</b>
</test>
<test>
<a>J1033</a>
<b>J9616</b>
</test>
</top>
実行例は以下の通りです。
(1) ターミナルを開き(またはIRISへログインし)クラス定義を作成したネームスペースへ移動します。
ネームスペースの変更方法は以下の通りです。
set $namespace="USER"
※ Linux/Unix上の IRIS へログインする方法は、 iris session <構成名> を実行します。例は以下の通りです。
iris session IRIS
(2) 入力例のXMLをファイルに保存(UTF-8で保存)し、ファイルのフルパスを変数に設定します。
例)/ISC/data.xml に配置した例
set file="/ISC/data.xml"
(3) 例のクラス定義(ISJ.Class1)の Import() メソッドを実行します。引数に (2) で設定した変数 file を指定しています。
do ##class(ISJ.Class1).Import(file)
(4) データを確認します。
管理ポータルで確認する場合は以下の手順で画面を開きます。
管理ポータル > システムエクスプローラ > SQL > クラス定義のあるネームスペースに移動> スキーマのプルダウンから ISJ を選択 > テーブル の > をクリックし展開 > Class1を選択して、画面右側の「テーブルを開く」をクリック
または、画面右側の「クエリ実行」タブをクリックし、テーブル名をドラッグしクエリ実行タブのテキストエリアでドロップし、実行ボタン押下
ターミナルで確認する場合は、SQL 実行環境に変更します。
do $system.SQL.Shell()
プロンプトが >> に変更されたらSELECE文を記述してEnterを押下します
USER>do $system.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]USER>>select * from ISJ.Class1
1. select * from ISJ.Class1
ID a b
1 あいうえお かきくけこ
2 O8634 H7321
3 J5426 V2218
4 J7155 M6804
5 R7066 W939
6 B9731 I406
7 I1095 Z5125
8 Q1573 Z9241
9 T7560 V5693
10 J1033 J9616
10 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0822s/37396/167775/3ms
execute time(s)/globals/cmds/disk: 0.0007s/11/1370/0ms
cached query class: %sqlcq.USER.cls29
---------------------------------------------------------------------------
[SQL]USER>>quit
USER>
お知らせ
Mihoko Iijima · 2021年6月8日
これは InterSystems FAQ サイトの記事です。
現時点のサポートバージョンについては、以下のドキュメントをご参照ください。
ミニマム・サポートバージョンについて
このリストに記述されていないバージョンに関しては、該当システムの保守契約があるという前提で、
メール、お電話等の通常のお問い合わせは受け付けます。
出来うる限りの対応を努力しますが、そのバージョンでの対応が出来ず、最新バージョンへのバージョンアップによる問題解決をご提案させていただく場合がございます。
インターシステムズは、以下の理由により、出来うる限り、最新バージョンへバージョンアップしていただくことをお勧めしております。
開発部門では、定期的に内部のコードレビュを実施しており、その結果、発見された機能不全等を適宜、最新バージョンに取り込んでいます。
過去にお客様先で発見された障害への対応は、順次新バージョンに取り込んでいきます。障害の性質によっては、非常に大規模な改造となり、旧バージョンへの取り込み(バックポート)が不可能なものもございます。
古いバージョンに対し、新バージョンに追加されたバグフィックスを取り込むこと(バックポート)は、非常に困難なケースが多く、新たな副作用を生む可能性が高くなります。また、バージョンが古くなればなるほどバックポートは困難になっていく可能性が高まります。
開発をより迅速に行うための便利な機能等、新機能の恩恵を受けることができます。
新しいバージョンは以前のバージョンよりも性能が同等または高くなければならない、というインターシステムズ製品開発部門のポリシーにより、バージョンが新しくなるにつれ、アプリケーションの性能向上が期待できます。
日々品質向上に向け努力を続けております。結果として最新バージョンの品質は以前のバージョンに比べて高いことが期待できます。
新しいハードウェア対応、それに伴うオペレーティングシステムや様々なソフトウェアの新バージョンへの対応は、最新のバージョンが優先されます。
セキュリティの脆弱性等への対応は最新バージョンが優先されます。
セキュリティの脆弱性等への対応は、大規模な広範囲にわたる変更の可能性が高く、古いバージョンへの対応が大変困難となります。
サポート対象バージョンに関しては、所定のリグレッションテストを実施後出荷しますが、応急パッチ等の非定型な対応では、リグレッションテストを実施しませんので、ソフトウェアの信頼性に大きな差があります。
お使いの IT 環境は、技術の進歩、セキュリティ意識の高まり等様々な要因で変化していく可能性が高い中、古いバージョンのソフトウェアを使い続けることには想定以上のリスクがあります。
関連記事・FAQトピック
セキュリティ脆弱性に関する対応について
バグフィックス対応について
古いバージョンの購入はできますか?
記事
Mihoko Iijima · 2021年8月23日
これは InterSystems FAQ サイトの記事です。
※データベースファイルとは、IRIS.DAT、および、CACHE.DATのことを指します。
Caché/Ensemble 2018.1.4、IRIS 2019.1.2/2020.1.0 以降のバージョンより、データベースファイル のサイズの縮小に、データベースの「圧縮」と「未使用領域の削除」機能をあわせて使用できます。
※注意※Caché/Ensemble 2018.1.4、IRIS 2019.1.2/2020.1.0 より前のバージョンでは、データベースの「圧縮」機能は使用できません。使用された場合、データベース破損が引き起こされる可能性があります(「未使用領域の削除」機能は利用できます)。
詳細情報は以下、弊社ウェブサイト内のページをご確認ください。
製品ニュースとアラート>警告: データベース圧縮またはデフラグ後のデータベース整合性の問題
データベースサイズ縮小手順は以下の通りです。
管理ポータル: [システムオペレーション] > [データベース] を開き、操作したいデータベース名をクリックします。
(または、画面左上の[空き容量]ボタンをクリックし、データベースの空き容量を表示します。)
① 「圧縮」ボタンにより、データベースファイルの使用していないブロックを後ろに集めます
<圧縮のイメージ> ●が使用中ブロック、〇が未使用ブロックだとします。
●●○●●○○●○○ ←のようにブロックが並んでいるデータベースファイル(*.DAT)を「圧縮」すると
●●●●●○○○○○ ←このようになります (左が前方)
②「未使用領域削除」ボタンにより、後方に集めた未使用ブロックを削除してデータベースファイルのサイズを縮小します。
<未使用領域削除のイメージ> ●が使用中ブロック、〇が未使用ブロックだとします。
●●●●●○○○○○ ←のようにブロックが並んでいるデータベースファイルに「未使用領域削除」を実行すると
●●●●● ←このようになります
圧縮について詳細は、ドキュメント(データベースの圧縮(IRIS))をご参照ください(2018.1以前のドキュメント:データベースの圧縮)。
管理ポータルの操作と同様の処理を、^DATABASE ユーティリティを使用して実行することもできます。
%SYS ネームスペースに移動してから実行します。
USER>zn "%SYS"
%SYS>do ^DATABASE
1) Create a database
2) Edit a database
3) List databases
4) Delete a database
5) Mount a database
6) Dismount a database
7) Compact globals in a database
8) Show free space for a database
9) Show details for a database
10) Recreate a database
11) Manage database encryption
12) Return unused space for a database // 「未使用領域削除」
13) Compact free space in a database // 「圧縮」
14) Defragment a database // 「DB の断片化解消」
15) Show background database tasks
Option?
※「圧縮」 = 13) Compact freespace in a database 「未使用領域削除」= 12) Return unused space for a database
^DATABASE ユーティリティの 14) Defragment globals in a database(「DBの断片化解消」)について補足します。
「DBの断片化解消」では、指定したデータベースファイル内のグローバル毎にブロックが再編成され、データベースファイル内で連続領域に再配置します。
「圧縮」をより強力にしたものですが、この再配置を行う為には、データベースファイル末尾に十分な空きブロックが必要です(一般的に見て、デフラグを定期的に実行する必要はありません)。
<「DBの断片化解消」のイメージ>
断片化解消前♦♦○♠♠○♠♠♦♦♠♥♥♥○♦♦♥♥♦○○○○○○
断片化解消後♦♦♦♦♦♦♦♠♠♠♠♠♥♥♥♥♥○○○○○○○○○
※注意※「断片化解消」機能についても、2015.1.3、2015.2.2 より前のバージョンでは使用できません。使用された場合、「圧縮」機能と同様に、データベース破損が引き起こされる可能性があります。
詳細は、ドキュメント(データベースのグローバルのデフラグ(IRIS))をご参照ください(2018.1以前のドキュメント:データベースのグローバルのデフラグ)。
お知らせ
Toshihiko Minamoto · 2023年6月20日
先週の InterSystems Global Summit にて、今年の初めにリリースしました2023.1のエクスペリメンタル機能として、新たな 外部テーブル を発表しました。現在、 外部テーブルの Early Access Program にご参加いただきご評価いただくことで、この機能がお客さまのニーズに合っているか、次に向けてどの機能を優先するべきか、お知らせいただきたいと考えています。
外部テーブルって何なの?この素晴らしい概要ビデオを見る時間やポップコーンがない場合に備えて、外部テーブルは、ファイルやリモートデータベースなど、物理的に別の場所に保存されているデータをIRIS SQLとしてアクセスするのに役立つ機能です。外部テーブルは、通常のIRISテーブルとしてSQLに表示され、他の通常テーブルや外部テーブルとのJOINなど、あらゆるSQLステートメントで使用することができます。クエリを実行する際、外部テーブルから何を検索する必要があるのかを理解し、そのサーバーがリレーショナルデータベースの場合は、ネットワーク経由で取得するデータを最小限に抑えるようなクエリを出力しています。
なぜデータをロードするだけじゃないの?それはいい質問ですね!データをロードした後、IRISでクエリを実行すると、ソース・システムですでに変更されている可能性があります。コストのかかる同期メカニズムを構築するのではなく、外部テーブルとして投影することで、クエリ時に常に最新のデータを取得することができます。その他の使用例としては、ファイルベースの大きなデータで、IRISデータベースのストレージを消費してしまうような場合、または一般的に一度しか読まないようなデータなどがあります。ところで、外部テーブルの構文と機能は、2021.2 で紹介した LOAD DATA コマンドで知っているものと完全に一致しています。
既にリンクテーブルがあるのでは?その通りです。その機能はかなり以前からあり、私たちの顧客ではよく採用されています。しかし、JDBCとODBCの実装が異なる時期に行われたため、機能や制限が微妙に異なり、メンテナンスや機能拡張が複雑になっていました。当初の実装以降、IRISのSQL内部でいくつかの改良(Table Valued Functionsを含む)が行われ、外部とIRISをより明確に分離した、より実用的なアプローチが可能になりました。このため、新しい機能として Foreign Tables を実装し、公式の ANSI SQL 標準と一致するようにしました。
現在、外部テーブルをLinked Tablesの後継とするつもりです。現在、Foreign Tablesを使用している方は、その機能のどれがあなたのユースケースにとって重要かをぜひ教えてください。そうすれば、外部テーブルの次の開発フェーズに優先順位をつけ、迅速に多くのユーザーに参加してもらい、ラボ以外からフィードバックが得られるでしょう。
どこで申し込むの?intersystems.com/early-access-programs にお申込みいただければ、チュートリアルとデモのリポジトリから開始できます。定期的にご連絡を差し上げ、ご意見を伺い、新しい機能を追加していく予定です。
皆様からのご連絡をお待ちしております!
記事
Shintaro Kaminaka · 2020年7月30日
この記事では、RESTFormsプロジェクト(モダンなWebアプリケーション用の汎用REST APIバックエンド)を紹介します。
プロジェクトの背後にあるアイデアは単純です。私はいくつかのREST APIを書いた後、REST APIが一般的に次の2つの部分で構成されていることに気付きました。
* 永続クラスの操作
* カスタムビジネスロジック
また、独自のカスタムビジネスロジックを書く必要はありますが、RESTFormsには永続クラスの操作に関連するすべての機能を提供しています。
**使用例**
* Cachéにすでにデータモデルがあり、REST API形式で情報の一部(またはすべて)を公開したい
* 新しいCachéアプリケーションを開発しており、REST APIを提供したい
**クライアントサイド**
このプロジェクトはWebアプリケーションのバックエンドとして開発されているため、JSだけで事足ります。 形式の変換は必要ありません。
**補足:CRUD**
オブジェクトまたはコレクションに対し、次の4つの操作を実行できます。
* Create(作成)
* Read(読み込み)
* Update(更新)
* Delete(削除)
**機能**
RESTFormsを使用して以下を実行できます。
* 公開されたクラスに対するCRUD - クラスのメタデータを取得し、クラスのプロパティを作成 / 更新 / 削除できます。
* オブジェクトに対するCRUD - オブジェクトを取得 / 作成 / 更新 / 削除できます。
* オブジェクトコレクションに対するRead(SQL経由) - SQLインジェクションから保護します。
* 自己検出 – 最初に使用可能なクラスのリストを取得し、その後でクラスのメタデータを取得し、そのメタデータを基にしてオブジェクトに対するCRUDを実行できます。
**パス**
以下の表には、主なパスとRESTFormsを使用して実行できる操作を掲載しています。
URL
説明
info
利用可能なすべてのクラスを一覧表示します
info/all
すべてのクラスのメタデータを取得します
info/:class
クラスのメタデータ
field/:class
プロパティをクラスに追加します
field/:class
クラスのプロパティを変更します
field/:class/:property
クラスのプロパティを削除します
object/:class/:id
オブジェクトを取得します
object/:class/:id/:property
オブジェクトの1つのプロパティを取得します
object/:class
オブジェクトを作成します
object/:class/:id
動的オブジェクトからオブジェクトを更新します
object/:class
オブジェクトからオブジェクトを更新します
object/:class/:id
オブジェクトを削除します
objects/:class/:query
(SQL)クエリでクラスのオブジェクトを取得します
objects/:class/custom/:query
(SQL)カスタムクエリでクラスのオブジェクトを取得します
**RESTFormsを使い始めるには?**
1. GitHubからプロジェクトをインポートします(お勧めの方法は独自リポジトリにサブモジュールとして追加する方法ですが、単にリリースをダウンロードしても良いです)。
2. RESTFormsを介して公開したい各クラスについて以下を実施します。
* アダプタクラスから継承する
* 権限を指定します(一部のクラスを読み取り専用として公開する場合などに実施)。
* オブジェクトの表示値として使用されるプロパティを指定します。
* 表示したいプロパティの表示名を指定します。
**セットアップ**
1. [リリースページ](https://github.com/intersystems-ru/RESTForms/releases/tag/v1.0)で最新リリースである20161.xml( Caché 2016.1用)または201162.xml(Caché 2016.2以降用)をダウンロードして任意のネームスペースにインポートします。
2. 新しいWebアプリケーション /forms をDispatchクラス Form.REST.Main を使用して作成します。
3. http://localhost:57772/forms/test?Debug をブラウザで開き、インストールを検証します({"Status": "OK"} が出力され、場合によってはパスワードの入力が求められます)。
4. テストデータが必要な場合は、次を呼び出します:
```do ##class(Form.Util.Init).populateTestForms()```
**例**
最初に、利用可能なクラスを知る必要があります。 この情報を取得するには、次を呼び出します。
http://localhost:57772/forms/form/info
次のような応答が返されます。
[
{ "name":"Company", "class":"Form.Test.Company" },
{ "name":"Person", "class":"Form.Test.Person" },
{ "name":"Simple form", "class":"Form.Test.Simple" }
]
現在3つのサンプルクラス(RESTFormで提供)があります。Person(Form.Test.Personクラス)のメタデータを見てみましょう。 この情報を取得するには、次を呼び出します。
http://localhost:57772/forms/form/info/Form.Test.Person
次のように、クラスのメタデータが応答として返されます。
{
"name":"Person",
"class":"Form.Test.Person",
"displayProperty":"name",
"objpermissions":"CRUD",
"fields":[
{ "name":"name", "type":"%Library.String", "collection":"", "displayName":"Name", "required":0, "category":"datatype" },
{ "name":"dob", "type":"%Library.Date", "collection":"", "displayName":"Date of Birth", "required":0, "category":"datatype" },
{ "name":"ts", "type":"%Library.TimeStamp", "collection":"", "displayName":"Timestamp", "required":0, "category":"datatype" },
{ "name":"num", "type":"%Library.Numeric", "collection":"", "displayName":"Number", "required":0, "category":"datatype" },
{ "name":"аge", "type":"%Library.Integer", "collection":"", "displayName":"Age", "required":0, "category":"datatype" },
{ "name":"relative", "type":"Form.Test.Person", "collection":"", "displayName":"Relative", "required":0, "category":"form" },
{ "name":"Home", "type":"Form.Test.Address", "collection":"", "displayName":"House", "required":0, "category":"serial" },
{ "name":"company", "type":"Form.Test.Company", "collection":"", "displayName":"Company", "required":0, "category":"form" }
]
}
これらの情報は次のような意味を持ちます。
クラスのメタデータ:
* name - クラスの表示名。
* class - 基本となる永続クラス。
* displayProperty - オブジェクトを表示するときに使用するオブジェクトのプロパティ。
* objpermissions - ユーザーがオブジェクトを使用して実行できる操作。 この例では、ユーザーは新しいオブジェクトを作成し、既存のオブジェクトを変更し、既存のオブジェクトを削除し、次を取得できます。
プロパティのメタデータ:
* name - プロパティ名 - クラスの定義と同じです。
type - プロパティのクラス。
* コレクション - リスト/配列のコレクションです。
* displayName - 表示プロパティ名。
* required - このプロパティが必須であるかどうか。
* category - プロパティのタイプクラスのカテゴリ。 RESTForms対応のすべてのクラスが「form」として表示されることを除き、通常のCachéクラスのカテゴリに従います。
クラス定義では次のようになります。
/// テストフォーム: Person
Class Form.Test.Person Extends (%Persistent, Form.Adaptor, %Populate)
{
/// フォーム名。グローバルキーではないため、何でもかまいません。
/// クラスをフォームとして持たないようにするには(ここのように)空の文字列に設定します。
Parameter FORMNAME = "Person";
/// デフォルトの権限
/// このフォームのオブジェクトは、作成、読み取り、更新、削除できます。
/// すべてのユーザーの権限を変更するには、このパラメーターを再定義します。
/// このクラスのcheckPermissionメソッドを再定義します(Form.Securityを参照してください)。
/// ユーザーやロールなどに基づいて独自のセキュリティを追加します。
Parameter OBJPERMISSIONS As %String = "CRUD";
/// オブジェクトの基本情報に使用されるプロパティ
/// デフォルトでは、getObjectDisplayNameメソッドはここから値を取得します。
Parameter DISPLAYPROPERTY As %String = "name";
/// このパラメーターの値をSQLでORDER BY句の値として使用します。
Parameter FORMORDERBY As %String = "dob";
/// Personの名前。
Property name As %String(COLLATION = "TRUNCATE(250)", DISPLAYNAME = "Name", MAXLEN = 2000);
/// Personの生年月日。
Property dob As %Date(DISPLAYNAME = "Date of Birth", POPSPEC = "Date()");
Property ts As %TimeStamp(DISPLAYNAME = "Timestamp") [ InitialExpression = {$ZDATETIME($ZTIMESTAMP, 3, 1, 3)} ];
Property num As %Numeric(DISPLAYNAME = "Number") [ InitialExpression = "2.15" ];
/// Personの年齢。<br>
/// これは、 <property>DOB</property> から派生した値を持つ計算されたフィールドです。
Property аge As %Integer(DISPLAYNAME = "Age") [ Calculated, SqlComputeCode = { set {*}=##class(Form.Test.Person).currentAge({dob})}, SqlComputed, SqlComputeOnChange = dob ];
/// このクラスメソッドは、誕生日 <var>date</var> が与えられた場合に現在の年齢を計算します。
ClassMethod currentAge(date As %Date = "") As %Integer [ CodeMode = expression ]
{
$Select(date="":"",1:($ZD($H,8)-$ZD(date,8)\10000))
}
/// Personの配偶者。
/// これは別の永続オブジェクトへの参照です。
Property relative As Form.Test.Person(DISPLAYNAME = "Relative");
/// Personの自宅住所。 埋め込みオブジェクトを使用します。
Property Home As Form.Test.Address(DISPLAYNAME = "House");
/// このPersonが働いている会社。
Relationship company As Form.Test.Company(DISPLAYNAME = "Company") [ Cardinality = one, Inverse = employees ];
}
**クラスでRESTFormsを有効にする**
そして、このクラスでRESTFormsを有効にするため、通常の永続クラスから始めて次のことを行いました。
1. Form.Adaptor から拡張しました。
2. 値を含むパラメーター FORMNAME(クラス名)を追加しました。
3. OBJPERMISSIONS パラメーター(すべての権限のCRUD)を追加しました。
4. DISPLAYPROPERTY パラメーター(オブジェクト名の表示に使用されるプロパティ名)を追加しました。
5. FORMORDERBY パラメーター(RESTFormsを使用するクエリでソートするデフォルトのプロパティ)を追加しました。
6. メタデータで確認したいプロパティごとに DISPLAYNAME プロパティのパラメーターを追加しました。
以上です。 コンパイル後、RESTFormsを含むクラスを使用できるようになります。
いくつかのテストデータを生成しましたので(インストールのステップ4を参照)、IDが1のPersonを取得してみましょう。 オブジェクトを取得するには、次を呼び出します。
http://localhost:57772/forms/form/object/Form.Test.Person/1
その応答は以下のとおりです(生成されるデータは異なる場合があります)。
{
"_class":"Form.Test.Person",
"_id":1,
"name":"Klingman,Rhonda H.",
"dob":"1996-10-18",
"ts":"2016-09-20T10:51:31.375Z",
"num":2.15,
"аge":20,
"relative":null,
"Home":{
"_class":"Form.Test.Address",
"House":430,
"Street":"5337 Second Place",
"City":"Jackson"
},
"company":{
"_class":"Form.Test.Company",
"_id":60,
"name":"XenaSys.com",
"employees":[
null
]
}
}
オブジェクト(具体的にはnumプロパティ)を変更するには、次を呼び出します。
PUT http://localhost:57772/forms/form/object/Form.Test.Person
このボディを使用します。
{
"_class":"Form.Test.Person",
"_id":1,
"num":3.15
}
速度を上げるには、_class、_id、および変更対象のプロパティのみをリクエストのボディに含める必要があります。
では、新しいオブジェクトを作成しましょう。 以下を呼び出します。
POST http://localhost:57772/forms/form/object/Form.Test.Person
このボディを使用します。
{
"_class":"Form.Test.Person",
"name":"Test person",
"dob":"2000-01-18",
"ts":"2016-09-20T10:51:31.375Z",
"num":2.15,
"company":{ "_class":"Form.Test.Company", "_id":1 }
}
オブジェクトの作成が成功した場合、RESTFormsは以下のようにIDを返します。
{"Id": "101"}
成功しなかった場合、エラーがJSON形式で返されます。 すべての永続オブジェクトのプロパティは、 _class および _id プロパティによってのみ参照する必要があります。
そして最後に、新しいオブジェクトを削除しましょう。 以下を呼び出します。
DELETE http://localhost:57772/forms/form/object/Form.Test.Person/101
これがForm.Test.Personクラスに対する完全なCRUDです。
**デモ**
[現在デモ環境はお試しいただくことができません。]
こちらでRESTFormsをオンラインで試すことができます(ユーザー名:Demo、パスワード:Demo)。
また、RESTFormsUIアプリケーション(RESTFormsデータエディタ)もあります。こちらをご確認ください(ユーザー名:Demo、パスワード:Demo)。 クラスリストのスクリーンショットを以下に掲載しています。

**まとめ**
RESTFormsは永続クラスに関する、REST APIから要求されるほとんどの機能を提供します。
**次の内容**
この記事では、RESTFormsの機能について説明しました。 次回の記事では、いくつかの高度な機能(クライアントからSQLインジェクションのリスクを冒さずにデータの一部を安全に取得できるクエリなど)についてお話ししたいと思います。 [この記事のパート2でクエリに関する情報をお読みください](https://community.intersystems.com/post/restforms-rest-api-your-classes-part-2-queries)。
RESTFormsUI(RESTFormsデータエディタ)もあります。
**リンク**
* [RESTForms GitHubリポジトリ](https://github.com/intersystems-ru/RESTForms/)
* [RESTForms UI GitHubリポジトリ](https://github.com/intersystems-ru/RESTFormsUI/)
* [パート2:クエリ](https://community.intersystems.com/post/restforms-rest-api-your-classes-part-2-queries)