Find

Announcement
· 5 hr ago

InterSystems 开发者社区中文版:每月摘要(2025年11月)

您好,欢迎了解InterSystems 开发者社区中文版2025年11月摘要信息。
统计信息
✓ 十一月共发布了 17 篇新帖子:
 10篇新文章
 7个新公告
✓ 十一月有 14 位新成员加入
✓ 截至目前共发布了 2,441 篇帖子
✓ 截至目前共有 2,305 位成员加入
热点文章
文章
#InterSystems IRIS
 
#InterSystems IRIS for Health
 
公告
十一月, 2025Month at a GlanceInterSystems Developer Community
Discussion (0)1
Log in or sign up to continue
Article
· 5 hr ago 4m read

使用IRIS互操作生产环境创建FHIR响应

当我们在 IRIS 中创建 FHIR 资源库时,我们有一个端点来访问信息、创建新资源等。但 FHIR 中有些资源可能不会出现在我们的资源库中,例如二进制资源(该资源返回文档,如 PDF)。

我创建了一个例子,当请求二进制资源时,FHIR 端点会返回一个响应,就像它存在于资源库中一样。

首先,我们需要一个命名空间和一个 FHIR 端点。然后,我们需要配置一个将连接到 FHIR 端点的互操作生产环境。该生产环境必须包含以下项目:

  • 业务操作:
    • HS.Util.Trace.Operations(事实上这是可选项,但非常有用)
    • HS.FHIRServer.Interop. OperationTraceOperations属性设置为 *FULL*
  • 业务服务:
    • HS.FHIRServer.Interop.ServiceTraceOperations属性设置为 *FULL*,目标配置名称设置为 HS.FHIRServer.Interop.Operation名称

生产环境如下所示:

创建此生产环境后,我们需要将其与FHIR端点连接。因此,编辑FHIR端点并将Service Config Name参数设置为业务服务(Business Process的名称:

现在,如果我们开始向 FHIR 资源库发送请求,就会在消息查看器(Message Viewer中看到所有跟踪信息:

现在,我们可以通过业务流程来控制如何处理特定路径。

在这个例子中,我们有一个业务流程来接收每个请求(现在业务服务连接到了这个业务流程,而不是业务操作),还有 2 个新的业务操作来执行稍后将解释的其他操作:

让我们来看看名为FHIRRouter 的业务流程:

如果我们查看一下,就会发现如果RequestPath包含 "Binary/",我们就会对该请求进行处理:生成我们自定义的二进制响应。否则,我们将直接把请求发送到 FHIR 资源库。

让我们来看看名为 "生成二进制 "的序列:

首先,我们创建一个HS.FHIRServer.Interop.Response 的新实例。然后从请求路径中获取文档 ID。如何获取?每次有人需要二进制资源时,都必须在 URL 路径中请求文档的 ID,比如:..../fhir/r4/Binary/XXXXX。因此,我们使用以下表达式从请求路径中提取文档 ID:

$Replace(request.Request.RequestPath,"Binary/","")

(虽然不是很优雅,但还是可以用的)。

如果有了文档 ID,我们就会调用名为 "查找(Find)" 的业务操作来查找与该文档 ID 相关的文件名:

事实上,"查找(Find)"业务操作总是返回相同的文件名:

这是我们能做什么的一个例子。

如果我们有一个文件名,那么就可以调用另一个名为File业务操作来获取以 base64 编码的文件内容:

最后,我们可以返回两种响应:

  • 如果没有文件内容(因为没有文件 ID 或找不到相关的文件名或内容),我们会返回404 响应,并给出自定义响应:
 set json = {
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "not-found",
            "diagnostics": "<HSFHIRErr>ResourceNotFound",
            "details": {
                "text": "No resource with type 'Binary'"
            }
        }
    ]
 }
 set json.issue.%Get(0).details.text = json.issue.%Get(0).details.text_" and id '"_context.docId_"'"
 set qs = ##class(HS.SDA3.QuickStream).%New()
 do qs.Write(json.%ToJSON())
 set response.QuickStreamId = qs.%Id()
 set response.ContentType = "application/fhir+json"
 set response.CharSet = "UTF-8"
  • 如果有文件内容,则返回200 响应,并附带以下自定义响应:
 set json = {
  "resourceType": "Binary",
  "id": "",
  "contentType": "application/pdf",
  "securityContext": {
    "reference": "DocumentReference/"
  },
  "data": ""
 }
 set json.id = context.docId
 set json.securityContext.reference = json.securityContext.reference_json.id
 set json.data = context.content.Read(context.content.Size)
 
 set qs = ##class(HS.SDA3.QuickStream).%New()
 do qs.Write(json.%ToJSON())
 set response.QuickStreamId = qs.%Id()
 set response.ContentType = "application/fhir+json"
 set response.CharSet = "UTF-8"

这里的关键是创建一个包含 JSON 对象的HS.SDA3.QuickStream。并将此 QuickStream 添加到响应中。

现在,如果我们测试我们的端点,如果我们请求二进制文档,我们将看到响应:

如果我们请求一个不存在的二进制文档(可以通过不输入文档 ID 进行测试),我们将看到 404 响应:

总之,将我们的 FHIR 端点与互操作性连接起来,我们就可以利用 InterSystems IRIS 的所有功能做任何我们想做的事情。

Discussion (0)1
Log in or sign up to continue
Article
· 5 hr ago 5m read

OMOP Odyssey - Databricks AI/BI Genie を使ってノーコードでCDM検索(アイオロス島編)

Databricks Genie と InterSystems OMOP によるノーコード Text-to-SQL

Discussion (0)0
Log in or sign up to continue
Announcement
· 5 hr ago

ご参加ありがとうございました!:第3回 InterSystems Japan 開発者コミュニティ・ミートアップ

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

3回目の開催となったミートアップですが、12月3日(水)に無事、開催を終えることができました。ご参加いただきましたメンバーの皆様、ありがとうございました!

今年は初の試みとして、ゲストスピーカーをお招きしご講演いただきました。その後から17時頃まで、各自のパソコンでワークショップの内容をお試しいただいたり、メンバー同士で会話されたりで、あっという間に時間が過ぎたように感じます。

ミートアップのワークショップで使用した内容は、全て以下リポジトリに公開しております。

https://github.com/Intersystems-jp/meetup2025Workshop

IRIS の環境は 12 月中ご利用いただけます。

ワークショップ中モデルのダウンロードのところで Notebook がなかなか進まなかったりでお試しいただけなかった部分があるかと思います。もしよろしければ、再度お試しいただければと思います。

 


以下、当日の写真を添えながらワークショップとネットワーキングの様子をご紹介いたします。

第1部最初は、加川さんからのご講演で

「AI駆動開発の実践──自社サービスと個人開発での活用事例」

のテーマでお話いただきました。

AI を開発の中に取り入れる際、どのような考えをもって開発を進めて行けばよいのか、どのように AI を使うと良いか、プロジェクトの中で誰が書いても同じ品質のプロンプトが書けるようにどのような工夫ができるかなど、沢山のノウハウを加川さんから教えていただき、これから始めてみようと検討されているメンバーの皆さんに向けて、非常にためになるお話を伺うことができました。

加川さん、ありがとうございました!

続いて、ワークショップの時間です。

夏から 3 シリーズで開催していたウェビナーの内容を試すワークショップをご用意していました。

今年は、ブラウザがあれば体験できる Google Colaboratory を利用してベクトル検索や、ベクトルの見える化やちょっと変なデータ(アノマリー)を見つけてみるなど、ベクトルにまつわる各種実験を行ってみたり、IRIS に登録された情報を利用して RAG +生成 AI の動作を確認するワークショップや、🎣釣り人ビギナーサポート AI  エージェント風 を作るとしたらどうなるか?の例をご覧いただきました。

ワークショップでは、一斉に同じ場所から Colab にアクセスしたのが原因か、モデルのロードに時間がかかりなかなか進まない状況の方もいらっしゃいました。申し訳ありませんでした。

次回開催に向け、何か良い方法がないか模索していきたいと思います!

昨年のミートアップ開催後アンケートの中に、「もっと参加者の方とお話したかった!」という回答が多くありましたので、今年はワークショップ最初に自己紹介タイムを設け、テーブル毎に自己紹介を行っていただきました。

第1部を終了する前に、各テーブルの代表の方に感想を伺いました。

個人的に Gemini や ChatGPT、Claude を使用しているけれどまだ開発の場面で加川さんからのお話にあったような「AI を取り入れた開発」までは行っていない、でも、これから使う上での注意事項、考え方などを聞けてよかった

ワークショップは最後まで動かせなかったけど、また持ち帰ってやってみたい。 

などの感想をいただきました。ありがとうございました!

ワークショップを最後までできない環境も含まれていましたが、「持ち帰って試したい」の感想もあり、非常にうれしい気持ちになりました。ありがとうございます。

 

続きまして、第2部についてご紹介します。

第2部はネットワーキングを中心に、技術文書ライティングコンテスト表彰式、クイズ大会を行いました!
(ライティングコンテストの全作品はこちらのページでご覧いただけます👉https://jp.community.intersystems.com/contests/3

今年は、3名の方による素晴らしい作品の投稿がありました🔥!

初めて投稿いただいた方、毎回投稿くださる方🔥 コンテストにご応募いただきありがとうございました!

いつも使っているあの方法、これは便利だ!と思える方法、またよく見るエラーだけどこんな意味があるんだ!などなど、コミュニティメンバーに共有したい内容はコンテストに限らずいつでも投稿いただけますので、ぜひお気軽に投稿してみてください。

コンテスト表彰式の次はクイズ大会でした。練習問題含めて14問の出題で、今年は🎣魚🐟や AI にちなんだ問題を出題しました。ヒラメはどっち?から始まり、生成AIが作った画像と本物比較、IRIS に格納できるベクトル要素数など様々な種類の出題がありました。

今年は全て早押し問題+最後3問はポイント3倍!!順位が沢山入れ替わる中、見事1位に輝いた方に Amazon ギフト券を贈呈いたしました。🎁

さて、今年の参加記念グッズですが、ガジェットポーチにしてみました。ぜひ、通勤のお供に使っていただければと思います。

 

また、もしよろしければ、ミートアップの感想記事を投稿いただいたり、この記事の返信欄でコメントいただいたり、コミュニティに投稿いただけるとうれしいです!

ミートアップへご参加いただいた皆様、ありがとうございました。

今年参加されなかった皆様も、ぜひ来年、ミートアップでお会いしましょう!

Discussion (0)1
Log in or sign up to continue
Article
· 8 hr ago 6m read

Sub-Table Security

InterSystems IRIS provides extensive configurable security options, yet many developers primarily use roles and resources to secure entire tables or routines. Today, we will delve deeper. We can also secure individual columns and rows separately, but these two mechanisms operate very differently. Let's begin with the columns.

Column Security

For testing and demonstration, we will keep our table structure concise and straightforward. We have a table called "Person" in the USER namespace that contains an ID column, a date of birth column (DOB), first name, and last name. 

Class User.Person Extends %Persistent
{
    Property FirstName As %String;
    Property LastName As %String;
    Property DOB As %Date;
    Property User As %String;
}

We will create a role called limited_access which will implement some column security, but the first thing we must remember to do is make sure to add the %DB_User resource to this role so that the user has access to the database. Once we’ve done that, we can begin to think about columns. We will go to the SQL Tables tab in the role setup and ensure that the USER namespace is selected. Then we will click the Add Columns button, which is to the right of the Add Tables button. This will open the dialog where we will control column permissions.

This interface closely resembles the screen used for adding permissions for tables. The notable exclusion is the DELETE option, which cannot be controlled at the column level. It makes sense since we cannot delete individual columns from a record in a table. However, we retain control over the SELECT, INSERT, UPDATE, and REFERENCES privileges. We can also use the Grant Admin checkboxes to permit users with this role to delegate the same privilege to other users or roles. For today's example, we will grant the role all permissions for the ID, FirstName, and LastName columns. Yet, we will assign only the SELECT privilege for the DOB column. After making these changes, we will save the role. You will then observe that the entry for this table in the role configuration displays a hyphen (-) under the privileges column. Yet, it includes an Edit Column option.

If we click the Edit Columns link on the right, we can review the exact permissions defined for each column individually.

This is where we can modify or revoke specific column permissions. If we check the Add Columns box, the initial configuration form for adding columns will reappear below, allowing us to make further additions. If you ever encounter a table listed in a role that appears to lack defined privileges, you should click the Edit Columns link to check for column-specific permissions.

Io test this configuration, we need to set up a user with this role. We will name this user testuser. It will possess our limited_access role, and we will also grant it the %Developer role to access the SQL portion of the Management Portal and execute some queries. For example, consider the following SQL query.

INSERT INTO Person(DOB,FirstName,LastName) VALUES(%ODBCIN('1900-09-03'),'David','Hockenbroch')

If we execute this query while logged in as a superuser with %All privileges, the query will be successful. However, if we log out of the Management Portal and sign back in as our test user, an error will occur.

The query has failed because the user lacks permission to insert into the DOB column. If we adjust the query to omit the restricted column, it will succeed. The following query will still work for this user:

INSERT INTO Person(FirstName,LastName) VALUES('David','Hockenbroch')

Similarly, if the user did not have permission to update or select a column, any query violating those restrictions would fail. For instance, if I removed the DOB column entirely from the column privileges, I would be unable to execute the SELECT * FROM Person command. Instead, I would be required to use SELECT ID, FirstName, LastName FROM Person. Note that if there are computed columns that a user lacks access to, the calculations will still be executed appropriately.

If we slightly modify our class definition, we can introduce a whole new issue. Suppose we decided to change our class definition to include the Required keyword in the DOB property. If we then attempt to run the query stated above, it will cause an error instead of succeeding.

You must keep this in mind when establishing column privileges: if you deny a user INSERT permission for a certain column that is not automatically assigned via compute code, an initial expression, or a similar method, the user will be unable to insert any rows at all!

Row-Level Security

Now we will explore row-level security. Our objective will be to ensure that only the user who created a row can access it.

Row-level security functions very differently from column security. We cannot configure it through the Management Portal. Instead, we must modify our class definition. First, we should add a property:

Property Creator As %String [ SqlComputeCode = {set {*} = $USERNAME}, SqlComputed, SqlComputeOnChange = %%INSERT];

This is an SQL computed property that automatically sets its value to the current username when a row is inserted. We will insert one row per user. Then we should observe the following records:

Next, we will need to override the ROWLEVELSECURITY parameter in the class definition. Setting it to 1 will automatically direct IRIS to store the reader list in a property named %READERLIST. However, in our case, since we created a property to store the username that should have access to the row, we will override this parameter with the name of that column (Creator). Remember that since row-level security can be handled by role or username, we could use a column containing a role name instead if desired.

If we attempt to select any data from this table at this point, the query will return empty. This happens because we have added row-level security to an existing table, and row-level security relies on building an index on the field being used for security. We must now rebuild the table’s indices. We will accomplish this through the Management Portal. In the SQL area, we will select the table on the left, then click Actions, and finally click Rebuild Table’s Indices.

Now that the appropriate index is present, when users select from the table, they will see only their own rows. It is essential to recognize that this restriction applies even to superusers! In most security contexts within IRIS, having the %All role grants access to virtually everything, but row-level security is a notable exception. Even if we run a DELETE * FROM Person query as a superuser, it will only eliminate the rows that the superuser is authorized to access.

We could achieve the same outcome in an alternative way. This time, let’s set the ROWLEVELSECURITY parameter to 1, but add a %SecurityPolicy method to our class.

ClassMethod %SecurityPolicy(Creator) As %String [ SqlProc ]
{
    return Creator
}

This method is defined as a class method that returns a string and uses the SqlProc keyword. It can accept any number of arguments, but they must be column names from the class itself, and the names of the arguments must precisely match the column names. In this case, since we are working with a column called "Creator", the method argument must also be named "Creator". We simply return that column's value to fulfill our goal here. This method can be as intricate as your needs demand, provided it ultimately returns a username or role name. It can also return a comma-separated list of names if necessary.

When the ROWLEVELSECURITY parameter is set to 1, the property %READERLIST is utilized to store who is authorized to access the row. If you wish to view this list in a query, you can execute something similar to the following.

SELECT %READERLIST, * FROM Person

Row-level security is enforced in addition to table security. A user cannot access, update, or delete a row unless they have permission to do so for both the table and the row. Importantly, row-level security is only applied when using SQL, not when employing object access or directly manipulating globals. Be extremely cautious if you access your data in a way that bypasses this security layer!

With the careful implementation of these two powerful tools, you can substantially elevate your data security!

Discussion (0)1
Log in or sign up to continue