Nova postagem

Pesquisar

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· jan 22 1min de leitura

Probando la función FOREIGN SERVER y FOREIGN TABLE

¡Hola! He ampliado mi repositorio de demostración, andreas5588/demo-dbs-iris, para facilitar las pruebas de las funciones FOREIGN SERVER y FOREIGN TABLE en IRIS.

Para lograrlo, creé un espacio de nombres llamado FEDERATION. La idea es la siguiente:

  1. Configurad conexiones JDBC para cada espacio de nombres.
  2. Cread un FOREIGN SERVER dentro del espacio de nombres FEDERATION para cada conexión.
  3. Definid al menos una FOREIGN TABLE basada en cada servidor externo.

El Script:  demo-dbs-iris/src/sql/02_create_foreign_server.sql

IRIS no permite ejecutar sentencias SQL que combinen tablas de diferentes NAMESPACES. Para abordar esta limitación, este NAMESPACE federado aprovecha el concepto de crear foreign servers para incluir otros NAMESPACES. Al definir foreign tables, se hace posible combinar tablas de diferentes NAMESPACES de forma fluida, permitiendo que escribáis sentencias SQL que unifiquen datos en una sola consulta.

Este NAMESPACE se utiliza para explorar esta función y sirve como una demostración práctica de esta capacidad, mostrando cómo explorarla y utilizarla.

Ejecutad este contenedor de demostración directamente mediante:

docker pull andreasschneiderixdbde/demo-dbs-iris:latest

Después de eso, podéis hacer consultas como esta:

¡Divertíos probando y mejorando la demostración!

 

Traducción del post original de Andreas

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· jan 22 2min de leitura

如何查询某张数据表占用的磁盘空间?

近期有些小伙伴需要查询某张特定的表所占用的磁盘大小,可能其他小伙伴也有类似的需求。

给大家一个例子供参考。

应当考虑到IRIS的表底层使用global存储数据,包括表数据、索引数据和流数据(如果表中有流属性的话),因此一张表的完整占用应当包含至少上述三种global的求和,如下所示:

Class GlbUtil.GlobalSearch Extends %RegisteredObject
{



ClassMethod GetTableSize(databaseName As %String, tableName As %String) As %Integer [ SqlProc ]

{

set currentNS = $namespace
//在%SYS命名空间中用API获得数据库的文件所在的路径
zn "%SYS"
set bdDirectory = $replace(##Class(Config.Databases).DatabaseByName(databaseName),"^","")

//回到表所在的命名空间,通过API获得表存储数据所用的global名称
zn currentNS

set totalSize = 0
set dataSize = 0
set idxSize = 0
set streamSize = 0
//Data location
set dataGlbName = $replace(##class(%Dictionary.ClassDefinition).%OpenId(tableName).Storages.GetAt(1).DataLocation,"^","")

//计算data global占用的磁盘大小,这里计算的是已经分配给这个global的大小(但不一定占完了),也可以计算实际占用了的大小,可以查询该API获得详情
set sc=##class(%Library.GlobalEdit).GetGlobalSize(bdDirectory,dataGlbName,.dataSize,,1)

//Index location
set idxGlbName = $replace(##class(%Dictionary.ClassDefinition).%OpenId(tableName).Storages.GetAt(1).IndexLocation,"^","")

set sc=##class(%Library.GlobalEdit).GetGlobalSize(bdDirectory,idxGlbName,.idxSize,,1)

//Stream location
set streamGlbName = $replace(##class(%Dictionary.ClassDefinition).%OpenId(tableName).Storages.GetAt(1).StreamLocation,"^","")

set sc=##class(%Library.GlobalEdit).GetGlobalSize(bdDirectory,streamGlbName,.streamSize,,1)

//求和返回
set totalSize = dataSize + idxSize + streamSize

Quit totalSize

}



}

上述代码定义了一个SQL函数,可以通过SQL直接查询,效果如下:

其中,HCC为表所在的数据库,Test.Test是测试用的数据表。返回的结果统计单位是MB。

读者可以在这个demo基础上添加些自己需要的其他特性和异常处理。现在这个函数返回的是系统分配给表的占用(不一定真用完了),读者可以参考在线文档中的API说明,获得更多详细的信息,例如要获取实际占用的空间而不是已分配的空间,应该如何调用API等。

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· jan 21 16min de leitura

Teams チャネルにメッセージを IRIS から送信してみる

開発者の皆さん、こんにちは。

Teams ワークフロー Webhook を用意すると、curl コマンドや REST クライアントを利用して Teams チャネルに任意メッセージを簡単に送信できるので、IRIS や IRIS の Interoperability を使って自動的に何か情報を入手+必要なときだけ Teams チャネル通知ができたら面白いな、と思い試してみた内容をご紹介します。

以下、Teamsワークフローの作成例です。

Teams ワークフローの仕様に合わせたメッセージ用 JSON が用意できれば、こんなメッセージを出すことができます。

Teams チャネルにメッセージを通知するには「Teams ワークフローの Webhook」の用意が必要です。(この用意によってアクセスするために必要なURLが生成されます)詳しくは、「Microsoft Teamsのワークフローを使用して受信 Webhook を作成する」をご参照ください。

通知までの設定などについては、こちらのページを参考にさせていただきました:Teams チャネルへメッセージ送信する方法

 

以下、試した順でご紹介します。

1. curl コマンドでまずは実行してみる

2. シンプルにターミナルから試す

3. 通知メッセージのJSONを変えてみる

4. メッセージのJSONをJSONテンプレートエンジンで作ってみる

5. Web ページを定期的にチェックし、新着情報のみ通知してみる

6. 試し方

 

1. curl コマンドでまずは実行してみる

例文の「URL」にTeamsワークフローで生成されたURLが設定されているとします。

POSTで送信するボディの中身は simple.json を指定しています。

 
 simple.json
curl -X POST -H "Content-Type: application/json" --data-binary @/home/isjedu/container/TeamsWorkFlow/data/simple.json $U
RL

この結果として、以下のメッセージが通知されます。

イメージ

 

2. シンプルにターミナルから試す

%Net.HttpRequest クラスを利用してターミナルから実行することもできます。

注意点としては、Teams ワークフローで作成されるURLはリクエストするサーバ、パス、クエリ文字列を含んだ URL で生成されます。

クエリ文字列にエスケープ文字(例:%2F など)が含まれる場合がありますのでターミナル送信時はエスケープ文字を元の文字に戻して送付する必要がありました。

コード詳細は以下のページをご参照ください。

ObjectScriptクックブックに記載の「HTTPのPOST要求を実行したい」の2つ目の例文

 

3. 通知メッセージのJSONを変えてみる

Teamsに送信するメッセージをもっと見栄え良いものに加工することもでき、Adaptive Card デザイナーを使って簡単に作成できるようでした。

ということで、以下のイメージとなるようなJSONを組み立ててみました。

「あいうえお」の下にある太字部分はリンクになっていて、対象のニュースページを開くように作られています

 
上記メッセージの元になるJSON

新着情報が増えた場合、リンク表示の部分が繰り返されるだけなので作成は簡単ですが、JSONの階層を辿り、値を設定していくのは少し面倒な気がします(特にカードのデザインを変えたい場合など修正が面倒そうです)。

 

4. メッセージのJSONをJSONテンプレートエンジンで作ってみる

ということで、JSONテンプレートエンジンを使ってJSONを生成してみます。

JSONテンプレートエンジンは、階層が深い複雑なJSON文字列の生成を簡単に行えるクラスで、作成したいJSON文字列のテンプレートの指定と、動的に値が変わる部分への値の挿入がとても簡単にできるクラスです。

JSONテンプレートエンジンについて詳しくは、ウェビナービデオか、利用例を含めた記事をご参照ください。

✅ JSONテンプレートエンジンのご紹介

ウェビナーでは複雑なJSONの例として、医療情報交換標準規格の HL7 FHIR の例でご紹介していますが、一般的なJSON文字にも対応しています。(例として以下の記事を掲載しています。併せてご参照ください。)

✅ 複雑なJSONの生成に便利な「JSONテンプレートエンジン」の使い方ご紹介

 

Teamsメッセージに使用するJSONで値を繰り返し設定したい場所は、以下の title と urlです。

"actions":[
    {
        "type":"Action.OpenUrl",
        "title":"地震メカニズムなど研究へ 国内2位のスパコン東大に設置 千葉",
        "url":"http://www3.nhk.or.jp/news/html/20250115/k10014694041000.html"
    },
    {
        "type":"Action.OpenUrl",
        "title":"月面着陸へ再挑戦 打ち上げ成功 都内ベンチャー企業",
        "url":"http://www3.nhk.or.jp/news/html/20250115/k10014693981000.html"
    }
]

 

それ以外のJSONは、だいたい固定値でよさそうなので、titleとurlを動的に置き換えできるよう、JSONTemplate.Baseを継承するクラスを定義します。

Test.AdaptiveCardActionsクラスでは、上記 JSON の actions 配列に含まれる JSON オブジェクトの部分のみを定義しています。

Class Test.AdaptiveCardActions Extends JSONTemplate.Base
{

Property ActionTitle As %String(MAXLEN = 100);
Property ActionUrl As %String(MAXLEN = 500);
XData Template [ MimeType = application/json ]
{
{
        "type": "Action.OpenUrl",
        "title": "#(..ActionTitle)#",
        "url": "#(..ActionUrl)#"
    }
}

}

 

Adaptive Card全体のJSONも作成する必要があるので、Test.AdaptiveCardActionsクラス で生成されるJSONを複数埋め込むためのクラス:Test.AdaptiveCardクラスを以下のように用意します。(このクラスもJSONTemplate.Baseを継承する必要があります)

Class Test.AdaptveCard Extends JSONTemplate.Base
{

Property Message As %String(MAXLEN = 500);
Property Actions As list Of Test.AdaptiveCardActions;
XData Template [ MimeType = application/json ]
{
{
    "type": "application/json",
    "attachments": [
        {
            "contentType": "object",
            "content": {
                "type": "AdaptiveCard",
                "version": "1.4",
                "msTeams": {
                    "width": "full"
                },
                "body": [
                    {
                        "type": "Image",
                        "url": "https://avatars.githubusercontent.com/u/67250170?s=200&v=4",
                        "altText": "コミュニティロゴ",
                        "width": "-7px",
                        "size": "Medium"
                    },
                    {
                        "type": "TextBlock",
                        "text": "RSS News!",
                        "wrap": true,
                        "fontType": "Default",
                        "size": "Large",
                        "weight": "Bolder",
                        "color": "Attention",
                        "isSubtle": true
                    },
                    {
                        "type": "TextBlock",
                        "text": "#(..Message)#",
                        "wrap": true
                    },
                    {
                        "type": "ActionSet",
                        "actions":["#(..Actions)#"]
                    }
                ]
            }
        }
    ]
}
}

}

 

JSONの actions に注目すると以下のように定義されています。

"actions":["#(..Actions)#"]

 

#(..プロパティ名)# の定義は、プロパティに設定した値がこの場所に当てはめられることを意味しています。

Actionsプロパティ の定義は以下の通りです(リストコレクションで複数の情報を登録できるように定義しています)。

Property Actions As list Of Test.AdaptiveCardActions;

 

まずはターミナルでJSON文字列の生成をテストします。

// actions:[] に含めるJSON文字列用の設定
set actions1=##class(Test.AdaptiveCardActions).%New()
set actions1.ActionTitle="テストタイトル"
set actions1.ActionUrl="http://localhost/csp/sys/UtilHome.csp"
set actions2=##class(Test.AdaptiveCardActions).%New()
set actions2.ActionTitle="開発者コミュニティ"
set actions2.ActionUrl="https://jp.community.intersystems.com/"
// AdaptiveCardのJSON文字列用設定
set card=##class(Test.AdaptiveCard).%New()
set card.Message="これはテストです"
do card.Actions.Insert(actions1)
do card.Actions.Insert(actions2)
do card.OutputToDevice() // JSON文字をカレントデバイスに出力

これで目的のJSON(例:test.json)を簡単に作成できそうです。

 

5. Web ページを定期的にチェックし、新着情報のみ通知してみる

IRIS Interoperability のプロダクションを利用して、Web ページを定期的にチェック(GET)しようと思ったとき、実はすぐに使えるインバウンドアダプタがありません。

特定のWebページの情報を定期的にGETしたい場合は、%Net.HttpRequest クラスを利用して、カスタムインバウンドアダプタを作ることになります。

ブラウザで試せるチュートリアルの中の「IRIS の Interoperability(相互運用性)を試せるチュートリアル」の中で実は使用しています。サンプルコードはこちら👉dc.Reddit.InboundAdapter

今回は定期的にNHKの最新ニュースを入手してみようと思い NHK の RSSを利用することにしました。

RSS はちょっと古いですが、GET 後の処理がしやすいページでしたので選択しました。

%Net.HttpRequest クラスを利用する方法でも定期的な GET はできますが、Python の ライブラリ:feedparser 利用することで、より簡単に必要な情報が入手できましたので、インバウンドアダプタの処理を Python で記述してみました。

NHK RSS の主要ニュースfeedparserで読み取ると、<items> の情報が Python listで受け取れます(list["entries"]に設定されます)。

受け取った list の中身をそのままプロダクションで利用したいので、IRIS 内にプロダクションで使用するメッセージクラスを用意し、feedparserで得られた list の中身を直接インバウンドアダプタの処理内でメッセージクラスにセットし、作成したメッセージをアダプタからビジネス・サービスに渡す方法で作ってみました。

RSSで取り出せる情報(左)と作成したメッセージクラス(右)のイメージは以下の通りです。

feedparserでパースし、メッセージクラスに格納するコードは以下メソッドで定義しています。

ClassMethod RSSParse(url As %String(MAXLEN=200)) As Test.RSSMessageBatch [ Language = python ]
{
import iris
import feedparser
import json
from datetime import datetime, timedelta, timezone
tz = timezone(timedelta(hours=+9), 'Asia/Tokyo')

rssfeed=feedparser.parse(url)

#サービスに送るメッセージクラスのインスタンス生成
batch=iris.cls("Test.RSSMessageBatch")._New()
#entries 以下にRSSの<channel>以下の<items>の情報がlistで取得できる。
#published_parsedを使ってYYYY-MM-DD HH:MM:SSの形式に変換しておく(JSTで)
for data in rssfeed["entries"]:
    pubparsedate=data["published_parsed"]
    pubparsedateLocal=datetime(*pubparsedate[:6],tzinfo=timezone.utc).astimezone(tz)
    dispdate=pubparsedateLocal.strftime('%Y-%m-%d %H:%M:%S')

    #バッチクラスに含めるメッセージクラスのインスタンス生成
    msg=iris.cls("Test.RSSMessage")._New()
    msg.Title=data["title"]
    msg.PublishedDate=dispdate
    msg.URL=data["link"]
    #バッチクラスに登録
    batch.Messages.Insert(msg)
return batch
}

カスタムアダプタクラス全体:Test.InboundAdapter

 

プロダクション全体図は以下の通りです。

 のマークがあるところは、feedparserでパースした情報が含まれる IRIS のメッセージクラスを利用しています。

インバウンドアダプタ用クラスの OnTask() では一定間隔ごとに実行したい処理を記載できますので、上記メソッド(RSSParse())を呼び出し、入手した情報(=IRISのメッセージクラスのインスタンス)をビジネス・サービスのProcessInput()に渡しています。

/// default InboundAdapter behavior: always call ProcessInput on CallInterval
Method OnTask() As %Status
{
    set status=$$$OK
    try {
        #dim batchmessage As Test.RSSMessageBatch
        set batchmessage=..RSSParse(..RSS)
        $$$ThrowOnError(..BusinessHost.ProcessInput(batchmessage))
    }
    catch ex {
        set status=ex.AsStatus()
    }
    Set ..BusinessHost.%WaitForNextCallInterval=1
    return status
}

 

残りは、通常のプロダクションの開発と一緒です。

サービスの次に呼び出すプロセスでは、既に通知した情報であるかどうかをチェックし、オペレーションには、未通知の情報のみが渡るように調整しています。

Teamsの通知に使うオペレーションは、HTTPアウトバウンドアダプタを利用しています。

オペレーション内では、Teamsに送信するJSON文字列を JSONテンプレートエンジンを利用して作成し、POST要求送信しています。

Teamsへの通知ですが、ボディの情報とクエリパラメータの両方を送付する必要があります。

HTTPアウトバウンドアダプタが提供してくれるメソッドではこの両方を渡せるメソッドが無かったので、SendFormDataArray()メソッドを使用しています。

使用方法について詳しくは、記事:「HTTPアウトバウンドアダプタを使用して、クエリパラメータとボディを両方送付する方法」をご参照ください。

コード例はこちら👉ビジネス・オペレーション:Test.TeamsWorkflowOp

実際にプロダクションを開始すると、60秒ごとに https://www.nhk.or.jp/rss/news/cat0.xml をチェックしはじめ、新しい情報があると以下右図のように新着情報のみを送信します。

 

6. 試し方

サンプルリポジトリはこちら👉https://github.com/iijimam/TeamsWorkFlow

コンテナを利用する場合

リポジトリクローン後、以下実行することでIRISが開始します。

docker compose up -d

開始後、プロダクション構成ページにアクセスし「開始」ボタンをクリックします。

60秒間隔でRSSを読み取りますので、不要な場合はプロダクション構成画面の「停止」ボタンで処理を停止してください。

 

ソースコードをインポートして試す場合

IRISのインストール環境を用意し、最初に Embedded Python が動作するように設定します。

1、%Service_Callinサービスを有効にする

※インストール時の初期セキュリティを「最小」とした場合は予め設定されています。

 

2、Pythonのバージョン確認と設定

2025/1/17現在、3.13はサポートしていないため、3.12.7をインストールしてください。

設定詳細はこちら👉管理ポータルでの設定(Windowsでの例)

※ WindowsにインストールしたIRIS 2024.1以前では、「2.」 の設定は必要ありません。

 

3、feedparserのインストール

pip install feedparser

 

4、SSL構成(クライアント)の作成

HTTP アウトバウンドアダプタを使用するビジネス・オペレーションで https 通信が必要となるため、プロダクションの構成設定の中で、SSL構成名「webapi」を設定しています(別名に変更することもできます)。

SSL 構成名は 管理ポータルでも作成できますし、IRIS ログイン後、専用 API を利用して作成することもできます。

管理ポータルの場合は、管理ポータル > システム管理 > セキュリティ > SSL/TLS 構成 で構成名に webapi を設定し保存ボタンをクリックするだけです。

API を利用する場合は、IRIS にログインし以下実行してください。

set $namespace="%SYS"
//SSLクライアント webapi作成
set status=##class(Security.SSLConfigs).Create("webapi")

 

5、ソースコードのインポート

コミュニティエディションをご利用の場合は、USERネームスペースにインポートします。製品版をご利用の場合は、Interoperabilityが利用できるネームスペースにインポートしてください。

JSONTemplate 以下クラスをインポートしコンパイルします。

続いてTest以下クラスをインポートし、コンパイルします。

最後にTestパッケージ以下クラスを再度一括コンパイルしてください。

 

6、テスト

プロダクション構成画面を開き「開始」ボタンをクリックします。

60秒間隔でRSSを読み取りますので、不要な場合はプロダクション構成画面の「停止」ボタンで処理を停止してください。

コミュニティエディションをご利用の場合

http://管理ポータルのアドレス/csp/user/EnsPortal.ProductionConfig.zen?PRODUCTION=Test.Prod

他の環境をご利用の場合(IRIS)

http://管理ポータルのアドレス/csp/ネームスペース名/EnsPortal.ProductionConfig.zen?PRODUCTION=Test.Prod

他の環境をご利用の場合(IRIS)

http://管理ポータルのアドレス/csp/healthshare/ネームスペース名/EnsPortal.ProductionConfig.zen?PRODUCTION=Test.Prod

Discussão (0)1
Entre ou crie uma conta para continuar
Pergunta
· jan 21

Iris is frozen - discover why

The question I have is if I run an External backup this library rotuine is called:
##Class(Backup.General).ExternalFreeze()

Is there a command I can run that shows me the Iris system is frozen due to the call to ##Class(Backup.General).ExternalFreeze()?

If the system is frozen I cannot sign into Iris terminal session.

I backup the IRIS server using Veeam. Veeam calls the "freeze" script, snapshots the server in VMWare, then calls the "thaw" script.
Veeam then backs up the VMWare snapshot.

I have had cases where Iris was frozen and I'm guessing this could be caused by a call to ##Class(Backup.General).ExternalFreeze() where no "thaw" command was called.

4 Comments
Discussão (4)2
Entre ou crie uma conta para continuar