検索

クリアフィルター
記事
Toshihiko Minamoto · 2021年8月11日

OAuth 認証と InterSystes IRIS: トラストプロトコルを使いこなす

### 不在時に、セキュリティとプライバシーを維持しながら、コンピューターを相互に信頼させるにはどうすればよいでしょうか? ![](/sites/default/files/inline/images/images/c07270055f2e7600834b6fde7c64fcda.jpg) 「ドライマルティーニを」と彼は言った。 「1 杯。 深いシャンパングラスで。」 「承知いたしました。」 「気が変わった。 ゴードンを 3、ヴォッカを 1、キナリレを半量。 キンキンに冷えるまでよくシェイクしてから、大きめの薄いレモンピールを 1 つ加えてくれ。 わかったかい?」 「お承りいたしました。」 バーテンダーはその考えが気に入ったようだった。 イアン・フレミング著『カジノ・ロワイヤル』(1953 年)より OAuth は、ユーザーログイン情報を伴うサービスを「運用中」のデータベースから、物理的にも地理的にも分離する上で役立ちます。 このように分離すると、ID データの保護が強化され、必要であれば、諸国のデータ保護法の要件に準拠しやすくしてくれます。 OAuth を使用すると、ユーザーは、最小限の個人データをさまざまなサービスやアプリケーションに「公開」しながら、一度に複数のデバイスから安全に作業することができるようになります。 また、サービスのユーザーに関する「過剰な」データを操作しなくてよくなります(データはパーソナル化されていない形態で処理することができます)。 InterSystems IRIS を使用する場合、OAuth と OIDC サービスを自律的かつサードパーティのソフトウェア製品と連携してテストし、デプロイするための既成の完全なツールセットを利用できます。 ### OAuth 2.0 と Open ID Connect OAuth と Open ID Connect(OIDC または OpenID)は、アクセスと識別をデリゲートするためにオープンプロトコルを汎用的に組み合わせたもので、21 世紀現在、人気を得ているようです。 大規模な使用において、これより優れたオプションはまだ誰も思いついていません。 HTTP(S) プロトコル上にとどまり、[JWT(JSON Web Token)コンテナ](https://en.wikipedia.org/wiki/JSON_Web_Token)を使用するため、特にフロントエンドのエンジニアに人気があります。 OpenID は OAuth を使用して機能しています。実際、OpenID は OAuth のラッパーです。 OpenID を電子識別システムの認証と作成に使用するオープンスタンダードとして使用することは、開発者にとって目新しい事ではありません。 2019 年には、公開から 14 周年を迎えました(バージョン 3)。 Webとモバイル開発、そしてエンタープライズシステムで人気があります。 そのパートナーである OAuth オープンスタンダードはアクセスをデリゲートする役割を担っており、12 年目を迎えています。関連する RFC 5849 標準が登場してからは 9 年です。 この記事の目的により、プロトコルの最新バージョンである OAuth 2.0 と最新の [RFC 6749](https://tools.ietf.org/html/rfc6749) を使用することにしましょう。 (OAuth 2.0 は、その前身の OAuth 1.0 とは互換していません。) 厳密に言えば、OAuth はプロトコルではなく、ソフトウェアシステムにアクセス権制限アーキテクチャを実装する際に、ユーザー識別操作を分離して別のトラステッドサーバーに転送するための一連のルール(スキーム)です。 OAuth は特定のユーザーについて何も言及できないことに注意してください! ユーザーが誰であるか、ユーザーがどこにいるのか、またユーザーが現在コンピューターを使用しているかどうかさえも、知ることはできません。 ただし、OAuth を使用すれば、事前に発行されたアクセストークンを使用して、ユーザーが参加することなくシステムと対話することが可能であり、 これは重要なポイントです(詳細は、OAuth サイトにある「[User Authentication with OAuth 2.0](https://oauth.net/articles/authentication/)」をご覧ください)。 [User-Managed Access(UMA)](https://tools.ietf.org/html/draft-hardjono-oauth-umacore-14)プロトコルも OAuth に基づくプロトコルです。 OAuth、OIDC、および UMA を合わせて使用することで、次のような分野で保護された ID とアクセス管理(IdM、IAM)システムを実装することができます。 * 医療分野における患者の [HEART(Health Relationship Trust)](https://openid.net/wg/heart/)個人データプロファイルの使用。 * 製造会社および貿易会社向けの顧客 ID&アクセス管理(CIAM)プラットフォーム。 * [OAuth 2.0 Internet of Things (IoT) Client Credentials Grant](https://tools.ietf.org/html/draft-tschofenig-ace-oauth-iot-00) による、IoT(モノのインターネット)システムにおけるスマートデバイス向けデジタル証明書のパーソナル化。 API エコノミーの新しいアクセス制御ベン図 何よりも、個人データをシステムのほかの部分と同じ場所に保存してはいけません。 認証と認可は物理的に分離する必要があります。 そして、ID と認証を各個人に与えることが理想と言えます。 自分で保管せずに、 所有者のデバイスを信頼するのです。 ### 信頼と認証 ユーザーの個人データを自分のアプリや作業データベースと組み合わさったストレージ場所に保存するのはベストプラクティスではありません。 言い換えれば、このサービスを提供できる信頼のある人を選ぶようにする必要があります。 このサービスは、次の項目で構成されます。 * ユーザー * クライアントアプリ * 識別サービス * リソースサーバー アクションは、ユーザーのコンピューターの Web ブラウザで実行されます。 ユーザーには識別サービスが備わったアカウントがあり、 クライアントアプリは、識別サービスと相互インターフェースとの契約に署名済みです。 リソースサーバーは、識別サービスを信頼して、識別できた人にアクセスキーを発行します。 ユーザーはクライアント Web アプリを実行して、リソースを要求します。 クライアントアプリは、アクセス権が必要なそのリソースへのキーを提示する必要があります。 ユーザーにキーがない場合、クライアントアプリはリソースサーバーへのキーを発行するために契約している識別サービスに接続します(ユーザーを識別サービスに転送します)。 識別サービスは、どのようなキーが必要かを問い合わせます。 ユーザーは、リソースにアクセスするためのパスワードを入力します。 この時点でユーザー認証が行われ、ユーザーの身元が確認されると、リソースへのキーが提供され(ユーザーをクライアントアプリに戻します)、ユーザーがリソースを利用できるようになります。 ### 認可サービスの実装 InterSystems IRIS プラットフォームでは、必要に応じてさまざまなプラットフォームからのサービスをアセンブルできます。 次はその例です。 1. デモクライアントが登録された OAuth サーバーを構成して起動します。 2. デモ OAuth クライアントを OAuth サーバーと Web リソースに関連付けて構成します。 3. OAuth を使用できるクライアントアプリを開発します。 Java、Python、C#、または Node JS を使用できます。 以下の方に、ObjectScript でのアプリケーションコードの例を示しています。 OAuth にはさまざまな設定があるため、チェックリストが役立ちます。 例を見ていきましょう。 IRIS 管理ポータルに移動し、[システム管理]>[セキュリティ]>[OAuth 2.0]>[サーバー]の順に選択します。 各項目には設定行の名前とコロン、そして必要であればその後に例または説明が含まれます。 別の方法として、Daniel Kutac の 3 部構成になっている「[InterSystems IRIS Open Authorization Framework (OAuth 2.0)の実装 - パート1](https://jp.community.intersystems.com/node/478821)」、[パート2](https://jp.community.intersystems.com/node/480201)、そして[パート3](https://jp.community.intersystems.com/node/480196) に記載されているスクリーンショットのヒントを参考にしてください。 次のスクリーンショットはすべて、例として提示されています。 独自のアプリケーションを作成する際は、別のオプションを選択する必要があるでしょう。 ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_12_54.png) [一般設定]タブで、次のように設定してください。 * 説明: 構成の説明を入力します。「認証サーバー」など。 * ジェネレーターのエンドポイント(以降「EPG」)のホスト名: サーバーの DNS 名。 * サポートされている許可の種類(少なくとも 1 つを選択): * 認可コード * 暗黙 * アカウントの詳細: リソース、所有者、パスワード * クライアントアカウントの詳細 * SSL/TLS 構成: oauthserver [スコープ]タブで、次を設定します。 * サポートされているスコープを追加: この例では「scope1」です。 [間隔]タブで、次を設定します。 * アクセスキー間隔: 3600 * 認可コードの間隔: 60 * キー更新の間隔: 86400 * セッション中断間隔: 86400 * クライアントキー(クライアントシークレット)の有効期間: 0 [JWT 設定]タブで、次を設定します。 * 入力アルゴリズム: RS512 * キー管理アルゴリズム: RSA-OAEP * コンテンツ暗号化アルゴリズム: A256CBC-HS512 [カスタマイズ]タブで、次を設定します。 * 識別クラス: %OAuth2.Server.Authenticate * ユーザークラスの確認: %OAuth2.Server.Validate * セッションサービスクラス: OAuth2.Server.Session * キーの生成クラス: %OAuth2.Server.JWT * カスタムネームスペース: %SYS * カスタマイズロール(少なくとも 1 つ選択): %DB_IRISSYS および %Manager では、変更内容を保存します。   次のステップでは、OAuth サーバーにクライアントを登録します。 [顧客の説明]ボタンをクリックして、[顧客の説明を作成]をクリックします。 ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_13_15.png) [一般設定]タブで、次の情報を入力します。 * 名前: OAuthClient * 説明: 簡単な説明を入力します。 * クライアントタイプ: 機密 * リダイレクト URL: oauthclient から識別した後に、アプリに戻るポイントのアドレス。 * サポートされている付与の種類: * 認可コード: はい * 暗黙 * アカウントの詳細: リソース、所有者、パスワード * クライアントアカウントの詳細 * JWT 認可 * サポートされているレスポンスタイプ: 次のすべてを選択してください。 * コード * id_token * id_token キー * トークン * 認可タイプ: シンプル [クライアントアカウントの詳細]タブは自動的に入力されますが、クライアントの正しい情報であるかを確認してください。 [クライアント情報] タブには次の項目があります。 * 認可画面: * クライアント名 * ロゴの URL * クライアントのホームページ URL * ポリシーの URL * 利用規約の URL   では、[システム管理]>[セキュリティ]>[OAuth 2.0]>[クライアント]の順に移動して、OAuth サーバークライアントにバインディングを構成します。 ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_13_52.png) サーバーの説明の作成: * ジェネレーターのエンドポイント: 一般的なサーバーのパラメーターから取得されます(上記を参照)。 * SSL/TLS 構成: 事前構成済みのリストから選択します。 * 認可サーバー: * 認可エンドポイント: EPG + /authorize * キーエンドポイント: EPG + /token * ユーザーエンドポイント: EPG + /userinfo * キーのセルフテストエンドポイント: EPG + /revocation * キーの終了エンドポイント: EPG + /introspection * JSON Web Token(JWT)設定: * 動的登録以外のほかのソース: URL から JWKS を選択します。 * URL: EPG + /jwks ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_14_00.png) このリストから、たとえばサーバーが OAuth-client にユーザーに関するさまざまな情報を提供できることがわかります(scopes\_supported および claims\_supported)。 また、アプリケーションを実装するときは、共有する準備ができているデータが何であるかをユーザーに尋ねても何の価値もありません。 以下の例では、scope1 の許可のみを要求します。 では、構成を保存しましょう。   SSL 構成に関するエラーがある場合は、[設定]>[システム管理]>[セキュリティ]>[SSL/TSL 構成]に移動して、構成を削除してください。 ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_15_30.png) これで OAuth クライアントをセットアップする準備が整いました。 [システム管理]>[セキュリティ]>[OAuth 2.0]>[クライアント]>[クライアント構成]>[クライアント構成を作成]に移動します。 [一般]タブで、次を設定します。 * アプリケーション名: OAuthClient * クライアント名: OAuthClient * 説明: 説明を入力します。 * 有効: はい * クライアントタイプ: 機密 * SSL/TCL 構成: oauthclient を選択します。 * クライアントリダイレクト URL: サーバーの DNS 名 * 必要な許可の種類: * 認可コード: はい * 暗黙 * アカウントの詳細: リソース、所有者、パスワード * クライアントアカウントの詳細 * JWT 認可 * 認可タイプ: シンプル [クライアント情報]タブで、次を設定します。 * 認可画面: * ロゴの URL * クライアントのホームページ URL * ポリシーの URL * 利用規約の URL * デフォルトのボリューム: サーバーに以前に指定したものが取得されます(scope1 など)。 * 連絡先メールアドレス: カンマ区切りでアドレスを入力します。 * デフォルトの最大経過時間(分): 最大認可経過時間または省略できます。 [JWT 設定]タブで、次を設定します。 * JSON Web Token(JWT)設定 * X509 アカウントの詳細から JWT 設定を作成する * IDToken アルゴリズム: * 署名: RS256 * 暗号化: A256CBC * キー: RSA-OAEP * Userinfo アルゴリズム * アクセストークンアルゴリズム * クエリアルゴリズム [クライアントログイン情報]タブで、次を設定します。 * クライアント ID: クライアントがサーバーに登録された際に発行された ID(上記を参照)。 * 発効されたクライアント ID: 入力されません * クライアントシークレット: クライアントがサーバーに登録された際に発行されたシークレット(上記を参照)。 * クライアントシークレットの有効期限: 入力されません * クライアント登録 URI: 入力されません 構成を保存しましょう。 ### OAuth 認可を使用した Web アプリ OAuth は、インタラクション参加体(サーバー、クライアント、Web アプリケーション、ユーザーのブラウザ、リソースサーバー)間の通信チャネルが何らかの形で保護されていることに依存しています。 この役割は SSL/TLS プロトコルが果たしているのがほとんどですが、 OAuth は、保護されていないチャネルでも機能します。 そのため、たとえばサーバー Keycloak はデフォルトで HTTP プロトコルを使用して、保護なしで実行します。 調整と調整時のデバッグが単純化されます。 サービスを実際に使用する際、OAuth のチャネル保護は、厳重な要件に含まれるべきであり、Keycloak ドキュメントに記述されている必要があります。 InterSystems IRIS の開発者は、OAuth に関するより厳密なアプローチに従っており、SSL/TSL の使用を要件としています。 単純化できる唯一の方法は、自己署名証明書を使用するか、組み込みの IRIS サービス PKI([システム管理]>>[セキュリティ]>>[公開鍵システム]を利用することです。 ユーザーの認可の検証は、UAuth サーバーに登録されているアプリケーションの名前と OAuth クライアントスコープの 2 つのパラメータを明示的に示すことで行えます。 Parameter OAUTH2APPNAME = "OAuthClient"; set isAuthorized = ##class(%SYS.OAuth2.AccessToken).IsAuthorized( ..#OAUTH2APPNAME, .sessionId, "scope1", .accessToken, .idtoken, .responseProperties, .error) 認可がない場合に備え、ユーザー ID をリクエストして、アプリケーションを操作する許可を取得するためのリンクを準備しておきます。 ここでは、OAuth サーバーに登録されているアプリケーションの名前を指定して、OAuth クライアントと要求されるボリューム(スコープ)を入力するだけでなく、ユーザーを返す Web アプリケーションのポイントへのバックリンクも指定する必要があります。 Parameter OAUTH2CLIENTREDIRECTURI = "https://52773b-76230063.labs.learning.intersystems.com/oauthclient/" set url = ##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint( ..#OAUTH2APPNAME, "scope1", ..#OAUTH2CLIENTREDIRECTURI, .properties, .isAuthorized, .sc)   IRIS を使用して、ユーザーを IRIS OAuth サーバーに登録しましょう。 たとえば、ユーザーに名前とパスワードを設定するだけで十分です。 受信した参照の下でユーザーを転送すると、サーバーはユーザーを識別する手続きを実行し、Web アプリケーションのアカウントデータによって、操作許可が照会されます。また、%SYS フィールドのグローバル OAuth2.Server.Session で自身に結果を保持します。 ![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_08_47.png)![](/sites/default/files/inline/images/images/snimok_e'krana_2019-09-06_v_23_10_02.png)   3. 認可されたユーザーのデータを示します。 手続きが正常に完了したら、アクセストークンなどがあります。 それを取得しましょう。 set valid = ##class(%SYS.OAuth2.Validation).ValidateJWT( .#OAUTH2APPNAME, accessToken, "scope1", .aud, .JWTJsonObject, .securityParameters, .sc )   以下に、完全に動作する OAuth の例のコードを示します。 Class OAuthClient.REST Extends %CSP.REST { Parameter OAUTH2APPNAME = "OAuthClient"; Parameter OAUTH2CLIENTREDIRECTURI = "https://52773b-76230063.labs.learning.intersystems.com/oauthclient/"; // to keep sessionId Parameter UseSession As Integer = 1; XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] { <Routes> <Route Method="GET" Url = "/" Call = "Do" /> </Routes> } ClassMethod Do() As %Status { // Check for accessToken set isAuthorized = ##class(%SYS.OAuth2.AccessToken).IsAuthorized( ..#OAUTH2APPNAME, .sessionId, "scope1", .accessToken, .idtoken, .responseProperties, .error) // to show accessToken if isAuthorized { set valid = ##class(%SYS.OAuth2.Validation).ValidateJWT( ..#OAUTH2APPNAME, accessToken, "scope1", .aud, .JWTJsonObject, .securityParameters, .sc ) &html< Hello!<br> > w "You access token = ", JWTJsonObject.%ToJSON() &html< </html> > quit $$$OK } // perform the process of user and client identification and get accessToken set url = ##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint( ..#OAUTH2APPNAME, "scope1", ..#OAUTH2CLIENTREDIRECTURI, .properties, .isAuthorized, .sc) if $$$ISERR(sc) { w "error handling here" quit $$$OK } // url magic correction: change slashes in the query parameter to its code set urlBase = $PIECE(url, "?") set urlQuery = $PIECE(url, "?", 2) set urlQuery = $REPLACE(urlQuery, "/", "%2F") set url = urlBase _ "?" _ urlQuery &html< <html> <h1>Authorization in IRIS via OAuth2</h1> <a href = "#(url)#">Authorization in <b>IRIS</b></a> </html> > quit $$$OK } } コードの作業コピーは、InterSystems GitHub リポジトリ()にもあります。 必要に応じて、OAuth サーバーと OAuth クライアントに高度なデバッグメッセージモードを有効にしてください。これらは、%SYS エリアの ISCLOG グローバルに記述されます。 set ^%ISCLOG = 5 set ^%ISCLOG("Category", "OAuth2") = 5 set ^%ISCLOG("Category", "OAuth2Server") = 5 詳細については、「[IRIS、OAuth 2.0 と OpenID Connect の使用](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GOAUTH)」ドキュメントをご覧ください。 ### まとめ これまで見てきたように、すべての OAuth 機能には簡単にアクセスでき、完全に使用できる状態になっています。 必要に応じて、ハンドラークラスとユーザーインターフェースを独自のものに置き換えることができます。 OAuth サーバーとクライアントの設定は、管理ポータルを使う代わりに、構成ファイルで構成することも可能です。
記事
Mihoko Iijima · 2021年11月4日

【GettingStarted with IRIS】MQTT を使った遠隔モニタリング(IRIS の MQTT アダプタを試してみよう!)

開発者の皆さん、こんにちは! この記事では、【GettingStarted with IRIS】シリーズの MQTT アダプタを簡単に試せるサンプルの利用方法についてご紹介します! (MQTTブローカーはインターネット上に公開されているテスト用ブローカーを利用しています)​​ サンプルは、こちら👉https://github.com/Intersystems-jp/Samples-MQTT-EKG-Devices (コンテナで動作します) IRIS/IRIS for Health のバージョン2020.1から、IoT の世界でよく利用される MQTT プロトコルに対応できる MQTT アダプタが追加されました。 MQTTインバウンドアダプタでは、メッセージの Subscribe が行え、MQTTアウトバンドアダプタでは、メッセージの Publish が行えます。 サンプルでは、MQTT を使った遠隔モニタリングをテーマに、患者さんに装着した心電図から心拍数(BPM)をリアルタイムに近い状態で取得し、モニタ画面に患者さん毎の心拍数を表示します(IRIS の MQTT インバウンドアダプタを利用したメッセージの Subscribe をご体験いただけます)。 Publish されるトピックについて サンプルでは、演習環境毎にユニークになるようにコンテナ開始時に以下の形式でトピックを作成しています(末尾の # はワイルドカードの指定です)。 /Student_4629/acmeHospital/EKG/# 実際に Publish されるトピックは患者さんに装着した心電図のデータになるので、# の部分は、Patient-1 や Patient-2 などのように患者さんを特定できる文字列が入ります。 サンプルのシナリオは、1つの医療機関の患者情報を取得する流れにしています(本来であれば複数の医療機関の患者情報をモニタできるようにしたほうが良いのですがシンプルに試すため、1つの医療機関の患者情報を取得する流れにしています)。 トピックの流れ サンプルには1つHTMLファイルが用意されています。このファイルをブラウザで開くと MQTT ブローカーに接続し、データ(心拍数)を1秒ごとにブローカーへ Publish します。 IRIS は、MQTTブローカーから指定のトピックを Subscribe します。 ​​​ MQTT ブローカーを Subscribe する設定を行った IRIS のサービスは、ブローカーからトピックを取得します。 実際の設定は以下の通りです。 受信したトピックは IRIS の中では​​​メッセージ(EnsLib.MQTT.Message)として扱われ、次のコンポーネントであるプロセス(図では Process_MQTT_Request)に渡します。 プロセスでは、受信した MQTT 用メッセージからモニタ表示に利用するデータ(Solution.HeartRate)に変換するため、データ変換を呼び出します。 プロセスエディタの開き方と、中で行われているデータ変換の呼び出しの設定を確認する方法は以下の通りです。 患者ごとの測定値を参照する流れ MQTT ブローカーから Subscribe した心拍数をリアルタイムに近い状態で画面表示するため、データ変換で作成された Solution.HeartRate から1秒ごとに患者ごとの心拍数を収集し、画面に表示しています。 この表示を行うため、1秒間隔で Solution.HeartRate に対するSELECT文が実行されています。 このクエリを実行しているのが、メトリックと呼ぶクラスです。プロダクションでは以下の場所に設定されています。 メトリックでは、指定の呼び出し間隔で Solution.HeartRate から患者ごとの BPM を収集しています。詳細はソースコードをご参照ください。 ということで、実際にサンプルを動かして動作を確認してみましょう!手順は以下の通りです。 (1) git clone (2) コンテナビルド&開始 (3) 演習環境毎のトピック作成 (4) プロダクション開始 (5) サンプルHTMLをブラウザで開いて Publish 開始! (6) モニタ画面で状況確認 (1) git clone git clone https://github.com/intersystems/Samples-MQTT-EKG-Devices (2) コンテナの開始 git clone で作成されるディレクトリに移動します。 cd Samples-MQTT-EKG-Devices Windows 以外でお試しいただいている場合は、setup.sh を実行します。 ./setup.sh コンテナを開始します。 docker-compose up -d (3) 演習環境毎のトピック作成 docker-compose exec iris iris session iris -U %SYS "##class(App.Installer).InitializeDocker()" この実行で演習環境で使用するトピックを指定しています。 注意:appp.htmlで使用するJavaScripとプロダクション設定に演習環境用のトピックを追記しています。この実行を行わないとサンプルは動作しません。 IRISの起動が完了していないと、上記メソッド実行後、以下のメッセージが出力されます。 Sign-on inhibited: Startup or Installation in progress このメッセージが表示される場合は、しばらく待ってから再度実行してください。 正常に実行できると、以下のように演習環境用のトピックが表示されます。 You have successfully initiated the MQTT exercise Please take note of your topic top-level string: /Student_4908/acmeHospital/EKG/# press enter to continue Enterで元の画面に戻ります。 (4) プロダクション開始 ​​​​​​管理ポータルを開きます。👉 http://localhost:52773/csp/sys/UtilHome.csp ユーザ名: SuperUser パスワード(大文字で設定されています): SYS Interoperability > INTEROPネームスペース選択 > 一覧 > プロダクション (5) サンプルHTMLをブラウザで開いて Publish 開始! app.html を開きます👉 http://localhost/app.html サーバ名はご利用の環境に合わせてご変更ください。 IRIS が​ MQTT ブローカーから Subscribe したトピックは、メッセージを利用して確認できます。 開いたプロダクション画面で、サービス:From_EKG_MQTT をクリックし、画面右の「メッセージ」タブを選択します。ヘッダの列にある番号をクリックするとトレース画面が開き、受信したトピックとその値が確認できます。 ​​​​​(6) モニタ画面で状況確認 モニタ画面を開き、患者ごとの心拍数を確認します。 管理ポータル > Analytics > ユーザポータル > SolutionEKG ※管理ポータル 👉 http://localhost:52773/csp/sys/UtilHome.csp 初期状態では3名の患者データが表示されます。 app.html にある 「追加」ボタンで心電図を付けた患者を増やすことができます。 app.html で患者を増やすと、モニタ用画面にも表示が増えます。 また、各患者のバーをスライドさせ、心拍数を変化させると、グラフもそれに合わせて変化し、MQTT ブローカーから Subscribe できていることがわかります。 以上でサンプルの動作確認は終了です。 app.html を閉じると MQTT ブローカーへの Publish が終了します。 最後に、コンテナを停止します。 docker-compose stop コンテナを破棄する場合は、以下のコマンドを実行してください。 docker-compose down サンプルには、完成形の Solution パッケージの他に、Demo パッケージが用意されいてプロダクションの定義やプロセスの作成を試すこともできます。 作成方法については、次の記事でご紹介する予定です!
記事
Mihoko Iijima · 2021年6月17日

【GettingStarted with IRIS】チュートリアルを始めよう!その1:Full Stack チュートリアル

開発者のみなさん、こんにちは! 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/ には、まだまだ他のチュートリアルをご用意しています。ぜひご体験ください!
記事
Tomohiro Iwamoto · 2023年12月19日

Debezium ご存じでしょうか

Debeziumをご存じでしょうか? グローバルサミット2023にて、Debeziumを題材としたセッション「Near Real Time Analytics with InterSystems IRIS & Debezium Change Data Capture」がありましたので、ご覧になられた方もおられるかと思います。 ご興味がありましたら、グローバルサミット2023の[録画アーカイブ](https://www.intersystems.com/near-real-time-analytics-with-intersystems-iris-debezium-change-data-capture-intersystems/)をご覧ください。 > [FAQ](https://debezium.io/documentation/faq/)によると、"dee-BEE-zee-uhm"(ディビジウム..ですかね)と読むそうです。元素周期表のように複数のDB(s)を束ねる、というニュアンスみたいです。 CDC(Change data capture)という分野のソフトウェアです。 外部データベースでの変更を追跡して、IRISに反映したいという要望は、インターオペラビリティ機能導入の動機のひとつになっています。一般的には、定期的にSELECT文のポーリングをおこなって、変更対象となるレコード群(差分。対象が少なければ全件)を外部システムから取得する方法が、お手軽で汎用性も高いですが、タイムスタンプや更新の都度に増加するようなバージョンフィールドが元テーブルに存在しない場合、どうしても、各ポーリング間で重複や見落としがでないように、受信側で工夫する必要があります。また、この方法ではデータの削除を反映することはできませんので、代替案として削除フラグを採用するといったアプリケーションでの対応が必要になります。 CDCは、DBMSのトランザクションログをキャプチャすることで、この課題への解決策を提供しています。[Debezium](https://github.com/debezium/debezium/blob/main/README_JA.md)はRedHatが中心となっているCDCのオープンソースプロジェクトです。 # CDCの何が良いのか CDCにはいくつかの利点があります。 - ポーリングではないので、更新が瞬時に伝わる - DELETEも反映できる - SourceになるDBMSに対して非侵襲的 テーブル定義を変更したり専用のテーブルを作成しなくて済む。パフォーマンスへの影響が軽微。 > 先進医療っぽい表現ですね。対象に与える影響が軽微というニュアンスだと思います。 - 受信側(アプリケーション側)の設計が楽 下記は受信側の仕組みに依存する話ですが、例えばIRISのRESTサービスで受信する場合 - ひとつのハンドラ(Restのディスパッチクラス)で、複数のテーブルを処理できる このことはSQLインバウンドサービスがテーブル単位であることと対照的です。 一方、トランザクションログのメカニズムは各DBMS固有なので、DBMSやそのバージョン毎にセットアップ手順、振る舞い、特性が異なる可能性があるというマイナス面があります。 > セットアップ作業は、SQLインバウンドアダプタほど簡単ではありません。 # Kafkaのコネクタとしての用法 DebeziumはKafkaのSourceコネクタとして使用する用法が一般的です。 ![](https://debezium.io/documentation/reference/stable/_images/debezium-architecture.png) 引用元: https://debezium.io/documentation/reference/stable/architecture.html > Kafkaのコネクタとしての用法は本稿では扱いません。 今回のメインテーマはKafkaではありませんが、関連するいくつかのKafka用語を確認をしておきたいと思います。 ## ProducerとConsumer Kakfaにメッセージを送信するデータの発生元のことをProducer、メッセージを消費する送信先のことをConsumerと呼びます。 ![](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/images/1.png?raw=true) ## SourceとSink 外部システムとの連携用のフレームワークをKafkaコネクトと呼びます。Kafkaコネクトにおいて、外部システムと接続する部分をコネクタと呼び、Producer 側の コネクタ は Sourceコネクタ、Consumer 側の コネクタ は Sinkコネクタと、それぞれ呼びます。 ![](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/images/2.png?raw=true) > DebeziumはKafkaのSourceコネクタです。 # Debeziumのスタンドアロン環境 Kafkaが提供するエンタープライズ級の機能を使いたければ、Kafkaの構成・運用を含めて検討する価値があります。一方、そうでない場合、Debeziumを[単体のサーバ](https://debezium.io/documentation/reference/stable/operations/debezium-server.html)で動作させることが出来ます。 > Debezium Serverと言います。その他の選択肢として、自作のJavaアプリケーションに組み込む方法もあります。 ![](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/images/3.png?raw=true) 随分とシンプルな構成になります。 KafkaのSinkコネクタを経由しなくても、Debezium自身が様々な[送信先](https://debezium.io/documentation/reference/stable/operations/debezium-server.html#_sink_configuration)に対応しています。Debeziumから見ると、Kafkaは送信先のひとつという位置づけです。 例えば、「POSTGRES上でのデータ更新をCDCして、その内容をhttp serverに送信」したい場合、 [POSTGRES用のSourceコネクタ](https://debezium.io/documentation/reference/stable/connectors/postgresql.html)と、[http Client](https://debezium.io/documentation/reference/stable/operations/debezium-server.html#_http_client)を使うことになります。 Debeziumは、Sourceとして[これら](https://debezium.io/documentation/reference/stable/connectors/index.html)のDBMSに対応しています。 > 残念ながらIRISはSourceになれません。IRISからIRISへのデータの同期であれば非同期ミラリングがお勧めです。 # Debezium Serverの起動 今回使用するソースコード一式は[こちら](https://github.com/IRISMeister/DebeziumServer-IRIS)にあります。 IRIS環境はコミュニティエディションにネームスペースMYAPPの作成と、3個の空のテーブル作成([01_createtable.sql](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/build/sql/01_createtable.sql)を使用)を行ったものになります。 ``` $ git clone https://github.com/IRISMeister/DebeziumServer-IRIS $ cd DebeziumServer-IRIS $ cd postgres (POSTGRESを試す場合。以降POSTGRESを使用します) あるいは $ cd mysql (MYSQLを試す場合) $ ./up.sh ``` 正常に起動した場合、3個のサービスが稼働中になります。 ``` $ docker composeps ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS iris postgres-iris "/tini -- /iris-main --ISCAgent false --monitorCPF false" iris 12 minutes ago Up 12 minutes (healthy) 2188/tcp, 53773/tcp, 0.0.0.0:1972->1972/tcp, :::1972->1972/tcp, 54773/tcp, 0.0.0.0:52873->52773/tcp, :::52873->52773/tcp postgres-debezium-server-1 debezium/server:2.4 "/debezium/run.sh" debezium-server 12 minutes ago Up 12 minutes 8080/tcp, 8443/tcp, 8778/tcp postgres-postgres-1 debezium/example-postgres "docker-entrypoint.sh postgres" postgres 12 minutes ago Up 12 minutes 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp ``` # 動作確認 初期状態を確認します。起動直後に、POSTGRES上の既存のレコード群がIRISに送信されますのでそれを確認します。端末を2個ひらいておくと便利です。以下(端末1)をPOSTGRESの, (端末2)をIRISのSQL実行に使用します。 (端末1 PG) ``` $ docker compose exec -u postgres postgres psql psql (15.2 (Debian 15.2-1.pgdg110+1)) Type "help" for help. postgres=# select * from inventory.orders; id | order_date | purchaser | quantity | product_id -------+------------+-----------+----------+------------ 10001 | 2016-01-16 | 1001 | 1 | 102 10002 | 2016-01-17 | 1002 | 2 | 105 10003 | 2016-02-19 | 1002 | 2 | 106 10004 | 2016-02-21 | 1003 | 1 | 107 (4 rows) postgres=# select * from inventory.products; id | name | description | weight -----+--------------------+---------------------------------------------------------+-------- 101 | scooter | Small 2-wheel scooter | 3.14 102 | car battery | 12V car battery | 8.1 103 | 12-pack drill bits | 12-pack of drill bits with sizes ranging from #40 to #3 | 0.8 104 | hammer | 12oz carpenter's hammer | 0.75 105 | hammer | 14oz carpenter's hammer | 0.875 106 | hammer | 16oz carpenter's hammer | 1 107 | rocks | box of assorted rocks | 5.3 108 | jacket | water resistent black wind breaker | 0.1 109 | spare tire | 24 inch spare tire | 22.2 (9 rows) postgres=# select * from inventory.customers; id | first_name | last_name | email ------+------------+-----------+----------------------- 1001 | Sally | Thomas | sally.thomas@acme.com 1002 | George | Bailey | gbailey@foobar.com 1003 | Edward | Walker | ed@walker.com 1004 | Anne | Kretchmar | annek@noanswer.org (4 rows) postgres=# \q $ ``` IRIS上のレコードは下記のコマンドで確認できます。POSTGRES上のレコードと同じになっているはずです。 (端末2 IRIS) ``` $ docker compose exec iris iris sql iris -Umyapp [SQL]MYAPP>>set selectmode=odbc [SQL]MYAPP>>select * from inventory.orders 出力は省略 [SQL]MYAPP>>select * from inventory.products [SQL]MYAPP>>select * from inventory.customers ``` 次に、POSTGRESで各種DMLを実行します。 (端末1 PG) ``` update inventory.orders set quantity=200 where id=10001; UPDATE 1 postgres=# delete from inventory.orders where id=10002; DELETE 1 insert into inventory.orders (order_date,purchaser,quantity,product_id) values ('2023-01-01',1003,10,105); INSERT 0 1 update inventory.products set description='商品説明' where id=101; UPDATE 1 ``` その結果がIRISに伝わり反映されます。 (端末2 IRIS) ``` [SQL]MYAPP>>select * from inventory.orders 3. select * from inventory.orders id order_date purchaser quantity product_id 10001 2016-01-16 1001 300 102 10003 2016-02-19 1002 2 106 10004 2016-02-21 1003 1 107 10005 2023-01-01 1003 10 105 4 Rows(s) Affected [SQL]MYAPP>>select * from inventory.products where id=101 4. select * from inventory.products where id=101 id name description weight 101 scooter 商品説明 3.14 1 Rows(s) Affected ``` # IRIS側の仕組み Debezium Serverのhttp clientは、指定したエンドポイントにREST+JSON形式で内容を送信してくれます。エンドポイントにIRISのRESTサービスを指定することで、IRISでその内容をパースし、必要な処理を実行(今回は単純にSQLの実行)しています。 INSERT時には、[こちら](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/examples/sink-insert-request-example.json)、UPDATE時には、[こちら](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/examples/sink-update-request-example.json)のようなJSONがPOSTされます。 payload.opにPOSTGRESへの操作の値であるc:Create, u:Update, d:Delete, r:Readが伝わりますので、その内容に基づいて、IRISのRESTディスパッチャークラス([Dispatcher.cls](https://github.com/IRISMeister/DebeziumServer-IRIS/blob/main/build/src/MyApp/Dispatcher.cls))にて、SQL文を組み立てて実行しています。 r:Readは、初回接続時に実行されるスナップショット取得作業の際に既存のレコード群を読み込み(READ)、それらが送信される場合に使用されます。詳細は[こちら](https://debezium.io/documentation/reference/stable/connectors/postgresql.html#postgresql-snapshots)をご覧ください。 # Debezium Serverについて Debezium Serverの詳細は[公式ドキュメント](https://debezium.io/documentation/reference/stable/operations/debezium-server.html)をご覧ください。 ドキュメントを見ると大量のコーディング例(Java)と構成例が載っており、これ全部理解してプログラムを書かないと使えないのかと思ってしまいますが、幸いコンテナイメージとして[公開](https://hub.docker.com/r/debezium/server)されていますので、今回はそれを利用しています。ソースコードも[公開](https://github.com/debezium/debezium-server)されています。 > 明言はされていませんでしたが、グローバルサミット2023のデモは、JavaベースのカスタムアプリケーションサーバからJava APIを使用してDebeziumの機能を使用するスタイルかもしれません # その他 Debezium Serverの欠点といいますか特徴として、接続先が未達になると直ぐ落ちるというのがあります。例えばIRISが停止すると、Debezium Serverが停止(今回の構成では、コンテナが停止)してしまいます。ただ、どこまで処理したかをO/Sファイル(本例ではdata/offsets.dat)に保存していますので、IRIS起動後に、Debezium Serverのコンテナを再開すれば、停止中に発生した更新をキャプチャしてくれます。 停止したコンテナの再開は下記コマンドで行います。 ``` docker compose start debezium-server ``` >「あれ、落ちるんだ」と思いましたが、フェールセーフ思想なのだと思います。 > 対障害性はKafka Connectに管理してもらう前提になっているためだと思います。 MYSQLもほぼ同じ操作で動作確認が出来ます。./mysqlに必要なファイルがあります。mysql.txtを参照ください。 また、今回は、レコードを同期しているだけですが、GS2023のように組み込みBIのキューブを作成して分析用途にしたり、何某かのビジネスロジックを実行したり、インターオペラビリティ機能に連動させたりといった応用が考えられます。
記事
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")
記事
Mihoko Iijima · 2020年12月28日

データベースの暗号化手順について

これは InterSystems FAQ サイトの記事です。 データベース暗号化は、ディスクヘの書き込みまたはディスクからの読み取りで暗号化と復号が実行されるため、アプリケーションのロジックに手を加える必要はありません。 この機能のドキュメントについては、以下ご参照ください。 マネージド・キー暗号化【IRIS】 マネージド・キー暗号化 暗号化データベース作成までの流れは、以下の通りです。 (1) 暗号化キーの作成 (a) 管理者 ユーザ名/パスワード (b) 暗号化キーファイル (2) 暗号化キーの有効化 (3) 暗号化されたデータベースの作成 暗号化データベース作成後の運用のための設定は以下の通りです。 〇 データベース暗号化の起動設定(暗号化キーの有効化をどのように行うか) 暗号化されたデータベースは、"暗号化キーの有効" が行われてアクセスできるようになります。既定の設定では、"暗号化キーの有効"を行いませんので、以下3種類の方法から選択します。 ① キーを有効化しない起動の構成 既定の設定のまま、インスタンス起動時に "暗号化キーの有効" が行われません。暗号化されたデータベースをマウントする前に管理ポータルなどから "暗号化キーの有効" を行う必要があります。 以下の場合、この運用は適応できません。 起動時に暗号化データベースのマウントが必要な場合 暗号化されたジャーナル・ファイルを利用している場合 監査ログが暗号化されている場合 ② インタラクティブ(対話式)にキーを有効化する起動の構成 インスタンス起動時に、インタラクティブに "暗号化キーの有効" を行います。 ③ 無人でキーを有効化する起動の構成 インスタンス起動時に、自動的に "暗号化キーの有効" を行います。 セキュリティの強度については、①および②の運用の方が、③よりも強度が高くなります。詳細は、下記ドキュメントページをご確認ください。 データベース暗号化の起動設定の構成【IRIS】データベース暗号化の起動設定の構成 ○暗号化キーファイル および 管理者とパスワードの管理方法(管理をどうするか) 暗号化キーの有効化するには以下の 2 つの情報が必要です。  (a) 管理者 ユーザ名/パスワード (b) 暗号化キーファイル これらに関して、ファイルの損失、管理者のユーザ名/パスワードの失念や漏えい等から防ぐ方法については、以下のドキュメントページをご確認ください。  データ損失に対する保護【IRIS】 暗号化データのアクセスにおける偶発的な損失からの保護 ○ 緊急事態(緊急事態の対処方法) 緊急事態として以下の場合の対処については下記ページをご確認ください。  緊急事態への対処【IRIS】  有効なキーが保存されているファイルが損傷したり紛失した場合【IRIS】  起動時に必要なデータベース暗号化キー・ファイルが存在しない場合【IRIS】  緊急事態  有効なキーが保存されているファイルが損傷したり紛失した場合  起動時に必要なデータベース暗号化キー・ファイルが存在しない場合
記事
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 · 2024年1月18日

CPU のマイクロアーキテクチャファミリと命令セットの判定方法

はじめに InterSystems は、最新の CPU 命令セット拡張機能を活用するために、IRIS を最適化したいと考えています。製品のパフォーマンスに対しては素晴らしいことですが、CPU が新しい IRIS ビルドにサポートされるかを知るにはどうすればよいでしょうか。ここでは、CPU のマイクロアーキテクチャファミリと CPU の特定の命令セット拡張機能を知る方法について説明します。 CPU のマイクロアーキテクチャを調べる ステップ 1 – CPU モデルを知る 最初のステップは、IRIS サーバーの特定の CPU モデルを調べることです。調べるには、オペレーティングシステムに応じて様々な方法がありますが、IRIS そのものからこの情報を取得するには、次のようにします。 IRIS ターミナルセッションで、do $system.CPU.Dump() を実行します。 すると、以下のような結果が出力されます。 Architecture: x86_64 Model: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz Vendor: Intel # of threads: 8 # of cores: 4 # of chips: 1 # of threads per core: 2 # of cores per chip: 4 MT supported: 1 MT enabled: 1 MHz: 2300 必要な CPU モデル情報は上記の Model フィールドにあります。 ステップ 2 – 普段使用している生成 AI エンジンにマイクロアーキテクチャファミリを尋ねる 調べたモデル番号は、別のプラットフォームやプロセッサの世代によって非常に異なりますが、生成 AI であればその違いをうまく埋められます。 最近は、生成AI として Bing の GTP-4 インターフェースをを使用しています。それを使用して、 <ここに CPU モデルを挿入> CPU はどのマイクロアーキテクチャファミリに属しますか? たとえば、次のようにします。 “Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz” CPU はどのマイクロアーキテクチャに属しますか? 次のような結果が返されます。 「Intel® Core™ i7-1068NG7 CPU @ 2.30GHz」は、Ice Lake マイクロアーキテクチャに基づく第 10 世代 Intel® Core™ i7 プロセッサに属します。 この情報は適宜、Intel または AMD で確認可能ですが、同じマイクロアーキテクチャファミリに使用されるマーケティング名が複数使用されていることがあるため、調べるには少々時間がかかることがあります。たとえば、AMD の EPYC ラインのプロセッサには、Milan や Rome などのサブラインが 2 つあります。 CPU はどの命令セット拡張機能をサポートしていますか? CPU のマイクロアーキテクチャファミリを調べて、サポートされている CPU ファミリのリストと比較するのではなく、必要となる特定の拡張機能が CPU に備わっていることを確認する場合があります。 Linux Linux で、シェルを開いて lscpu コマンドを実行します。結果の Flags セクションに、CPU がサポートする拡張機能のリストが含まれています。 macOS Mac では、sysctl コマンドを使ってサポートされている拡張機能を確認できます。シェルを開いて sysctl -a を実行すると、machdep.cpu.features と machdep.cpu.leaf7_features の行で CPU がサポートされている拡張機能を調べられます。 Windows coreinfo ユーティリティを使用すると、CPU の命令セット拡張機能のリストが読みやすく表示されます。
記事
Megumi Kakechi · 2024年4月2日

クエリパフォーマンスが出ない場合の対処方法(凍結プランが関係している場合)

これは InterSystems FAQ サイトの記事です。 Caché 2016.2以降(IRISはすべてのバージョン)で、クエリプランの凍結機能 が実装されました。この機能により、メジャーバージョンのアップグレードを行った場合、既存のクエリプランは自動的に凍結(※)されます。※2023.1以降のバージョンより、アダプティブモードが無効の場合のみ、クエリプランが自動的に凍結されます。有効の場合は、既存のクエリプランは無効になり、新しいシステムでクエリの最初の実行時に新しい最適化されたクエリプランを生成します。既定は有効です。 こちらのトピックでは、「新しいバージョンにしたのに、一部のクエリで思うようなパフォーマンスが出ない」「凍結プランが使用されている場合、新しいプランでパフォーマンスがどのくらいでるのかを知りたい」という場合の確認手順について、ご説明します。 %NOFPLANキーワードで新しいプランを試してみる Frozen Plan (古いバージョンと同じプラン)を使用していて思ったようなパフォーマンスが出ない場合、凍結を解除して新しいプランを試すことが可能です。新しいプランを試したい場合は、%NOFPLANキーワードをつけてクエリを実行します。%NOFPLANを付けた方がパフォーマンスが良ければ、プラン凍結を解除して新しいプランで実行するようにします。 検証手順は以下のようになります。 1.現在のプランが、凍結プラン(Frozen Plan)と新しいプランのどちらを使用しているかを確認します。  プランの状態は管理ポータルより確認できます。  [システムエクスプローラ] > [SQL] :  確認したいクエリのネームスペースで、テキストボックスに実行したいクエリを書いて「プラン表示」をクリックします。   凍結したプランを使用している場合、上記イメージのように「Frozen Plan」と表示されます。  これはつまり、アップグレード前の凍結されたプランを使用していることを意味します。  Frozen Plan の表記がない場合は、現バージョンの新プランを使用していることを意味します。   プランの状態が「Frozen Plan」の場合、新プランではパフォーマンスがどう変わるかを確認します。 2.%NOFPLAN キーワードをクエリに追加して実行し、パフォーマンスを監視します。 実行例: SELECT %NOFPLAN Name , Age FROM Sample.Person .... 3.新プランの方のパフォーマンスが良ければ、プランの凍結解除を行います。  プラン凍結の解除方法については、以下になります。 // すべてのプランを凍結解除する場合: set st=$SYSTEM.SQL.Statement.UnfreezeAll() // 個別に凍結解除する場合: set st=$SYSTEM.SQL.Statement.UnfreezeSchema("Sample") // または set st=$SYSTEM.SQL.Statement.UnfreezeRelation("Sample.Person") // または set st=$SYSTEM.SQL.Statement.UnfreezeStatement("3DgIqc72NS+Np6nybddb719NKb8=") // Statement単位はHash指定 /// Hashは、以下のクエリで確認できます /// SELECT Hash, Statement FROM INFORMATION_SCHEMA.STATEMENTS WHERE Frozen=1 OR Frozen=2 // 解除後、クエリキャッシュの削除を行う do $SYSTEM.SQL.PurgeAllNamespaces() // ネームスペース内の全キャッシュ または do $SYSTEM.SQL.PurgeForTable("Sample.Person") // テーブル指定  【ご参考】テーブル統計情報をエクスポートして別環境にインポートする方法
記事
Toshihiko Minamoto · 2024年5月16日

FHIR アダプターを使ってレガシーシステムに FHIR サービスを提供する - 概要

FHIR がシステム間の相互運用性と互換性に関するあらゆる問題に対する万能薬であり、ソリューションであることはご存知のことでしょう。 これは、FHIR リソースを手に掲げてそれに興じる戦士の画像です。 ですが、戦士ではない私たちのために、少しだけ紹介したいと思います。 FHIR とは? 早速定義を述べると、FHIR(Fast Healthcare Interoperability Resource; 高速ヘルスケア相互運用性リソース)とは、ヘルスケア産業において医療データを様々なシステム間で電子的にやり取りできるようにするために、HL7(Health Level 7) 規格化組織が作成した相互運用性の規格です。 FHIR の基盤テクノロジー REST API や JSON 形式による HTTP 呼び出しの組み合わせを主としています(使用方法に応じて XML やその他の通信も可能)。 FHIR の操作方法 一般に、GET (サーバーからデータを取得)、PUT (データの更新)、POST (データの保存)、および DELETE (削除)などの HTTP 呼び出しを使用して通信する FHIR サーバーを使用するのが最も簡単です。 . FHIR はサーバーとクライアント間でデータの送受信に使用されるリソースの概念を処理します。 これらのリソースはシステム間の 80% の相互通信のニーズに対応することを目指しています。 以下は、デフォルトで使用できるリソースの画像です。 ご覧のように、各リソースにはリソースの成熟度を示す数字か文字が備わっています(N は標準を表します)。 FHIR の公式ドキュメントには多数の例が記載されています。 Resource の発展形が Bundle です。これは大まかに言うと、同一の JSON 内にパッケージされたリソースのセットで、サーバーにクエリしたり、バッチやトランザクションで CRUD 操作を実行したりするために使用されます。 さて、FHIR が素晴らしいことはわかりますが、FHIR が定義する基準に従って動作するように設計されていないレガシーシステムでは、これをどのように応用できるのでしょうか? FHIR アダプター InterSystems はお客様に FHIR アダプター機能を提供しています。これを使用することで、既存のシステム上にビジネスレイヤーをセットアップし、FHIR ファサードとして知られるものを作成することができます。 以降の記事では、FHIR オブジェクトの操作方法と、PostgreSQL データベースを使用する HIS(健康情報サービス)システムがどのようなものかを示す簡単なシミュレーションの操作方法を説明します。 説明を理解しやすくするために、今後使用するサンプルを自動的にセットアップする OpenExchange アプリケーションを提供しています。 ワークショップの展開 今後の記事では、以下のポイントについて説明します。 IRIS インスタンスにおける FHIR アダプターのアーキテクチャ 患者タイプリソースを HIS に登録する REST API 呼び出しを使って ID で患者をクエリする 患者と医療センターデータの Bundle を HIS に登録する ご興味があれば、 コミュニティで近日公開される記事にご期待ください!
記事
Megumi Kakechi · 2023年9月4日

Webアプリケーションのトラブルシュート方法(ログの取得方法)

こちらの記事では、RESTやCSPなどの「Webアプリケーションのトラブルシューティング」のヒントをご紹介します。 何かしらのトラブルと思われる事象が発生した場合、確認したいのがログファイルになります。各コンポーネント間のやり取りで、どこでどのようなトラブルが発生しているかを、それぞれログを取得して確認することができます。 ① クライアント ⇔ Webサーバ間では、「Webサーバログ(IISやApacheのアクセスログなど)」、② Webサーバ ⇔ Webゲートウェイ間では、「イベントログ」・「HTTPトレース」、③ Webゲートウェイ ⇔ IRISサーバ間では、「ISCLOG」・「監査ログ」・「messages.log」などがあります。 こちらの記事では、IRISで取得できるログとして と で取得可能なログの取得方法をご紹介します。 ② Web サーバと Webゲートウェイ間のアクセスに関連するログ情報 ◆ イベントログ 1) Webゲートウェイ管理ページ(http://<IPアドレス>:<ポート>/csp/bin/Systems/Module.cxw)に接続します。 2) イベントログを削除します。 [イベントログを参照] > ログをクリア をクリック 3) イベントログレベルを設定します。 [デフォルトパラメータ(Default Parameters)] > イベントログレベル(Event Log Level)に イベントログレベル を設定し保存します(例:ev7) 4) エラーやトラブルとなっている事象を発生させます。 5) イベントログレベルを解除します。 ※ログの解除は忘れずに行うようにしてください。 [デフォルトパラメータ(Default Parameters)] > Event Log Level を消して保存します ◆ HTTPトレースログ 1) Webゲートウェイ管理ページ(http://<IPアドレス>:<ポート>/csp/bin/Systems/Module.cxw)に接続します。 2) HTTP トレースを表示(View HTTP Trace) をクリックします。 3) トレース ON をクリックします(HTTPトレースを開始します) 4) エラーやトラブルとなっている事象を発生させます。 5) トレース OFF をクリックします(HTTPトレースを終了します)   ※トレースの解除は忘れずに行うようにしてください。 ③ Webゲートウェイ と IRIS サーバ間のアクセスに関連するログ情報 ◆ ISCLOG ISCLOGの使用方法については、以下のFAQトピックをご覧ください。CSP(REST)に関するトラブルシューティングに使用できるツールはありますか。 ◆ 監査ログ 監査ログの使用方法については、以下のFAQトピックをご覧ください。CSP/RESTアプリケーションに接続できません。どのように調査すれば良いですか? 管理ポータルに接続できる場合は、以下の方法で確認できます。いつも使用しているユーザで IRIS や Caché にアクセスできなくなった時の原因の探り方(監査の使い方) ◆ messages.log messages.log は、InterSystems IRIS のシステム管理者のディレクトリ (install-dir/mgr) にあります。詳細は以下のドキュメントをご覧ください。messages.log 【注意】調査後、ログの解除を忘れずに行うようにしてください。また、必要がない場合は収集したログのクリアも行うようにしてください。ログの解除を忘れると、そのままログ情報を収集し続け、ディスク容量を圧迫することになりますのでご注意ください。 おまけ:FHIRの場合は、別途取得できるログ情報があります。詳細は以下のドキュメントをご覧ください。FHIR サーバのデバッグ
記事
Megumi Kakechi · 2022年10月6日

メッセージログ(messages.log) のログ深刻度が 2 以上でメールを送るようにする方法

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で使用できるユーティリティ一覧
記事
Megumi Kakechi · 2023年4月11日

TIMESTAMP型の項目に対して、TO_CHAR() や TO_DATE() を用いた SELECT を実行するとエラーになります

これは 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つの項目
記事
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:ストリームプロパティのデータが格納される変数です。 ストレージ定義に表示される情報について詳細は、ドキュメント「グローバル命名方法:USEEXTENTSET=1 の場合」をご参照ください。 2023.1以前のドキュメントは「ハッシュ化したグローバル名」をご参照ください。 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で指定したテーブルのオプションについては詳しくは、ドキュメント「テーブルのオプション」をご参照ください。 関連記事:永続クラス定義のデータが格納されるグローバル変数名について
記事
Toshihiko Minamoto · 2022年11月8日

Django 入門 パート 2

パート 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 管理のログインフォームが表示されます。 ![](/sites/default/files/inline/images/images/image(4235).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