0 フォロワー · 156 投稿

SQLは、リレーショナルデータベースにデータを格納、操作、および取得するための標準言語です。

記事 So Ochi · 10月 13, 2024 10m read

はじめに

生成AIを活用したアプリケーション開発は、Python、JavaScriptなどのメジャー言語による体験記事がよく見られます。一方、IRISのObjectScriptの開発に言及された記事は比較的少ないのが現状です。そこで、本記事では生成AIがObjectScriptの開発にどこまで活用できるのかを検証しました。

特にDevOpsのプロセスにおいて、生成AIは様々なシーンでの活用が期待できます。今回は開発工程に注目し、以下の観点から生成AIの有効性を調査しました。

  • 開発
    • コードの自動生成
    • 環境構築のアシスタント(テーブルの作成)
  • 検証
    • テストデータ生成のサポート

環境

本記事の検証は以下の環境で行いました。

開発環境

  • OS: macOS Sonoma
  • IRIS: 2023.4 (linux)

開発ツール IRISの開発にはStudioやVSCodeなどが利用可能ですが、今回は生成AIの活用に特化したエディタ「Cursor」を使用しました。

Cursorを選定した理由 Cursorは、生成AIによる支援機能に特化したコードエディタで、以下の特徴があります:

  • 生成AIの支援:コードの自動生成や提案、バグの検出、修正提案を行います。また、外部のドキュメントや複数のソースを指定し、生成内容に反映させる簡易なRAG機能も搭載されています。

  • VSCodeとの互換性:VSCodeをフォークして作られており、VSCodeユーザーはスムーズに移行できます。拡張機能もそのまま利用可能です。

IRISではv2024よりStudioは廃止となり、VSCodeが標準ツールとなります。そこで、VSCodeと互換性があり、生成AIとの親和性が高いCursorを選定しました。

選択した生成AIモデル GPT-4を使用しましたが、Claudeでも検証を行ったところ、どのモデルも大差ない結果となりました。 利用しやすいモデルを選んで試してみてください。

検証内容

今回は以下の内容を検証しました。

  • 簡単なプログラムの生成とターミナルでの実行
  • IRISのREST通信機能を使った商品情報検索APIの作成

サンプルプログラムの作成

まず、ユーザーに名前を入力させ、挨拶を返す簡単なルーチンを生成します。CursorでCommand+Lを押してチャットウィンドウを開き、以下のプロンプトを入力します。

あなたはObjectScriptの開発者です。
{仕様}をもとにコードを作成してください。
#仕様
- 以下の処理を実行するRoutineを作成する。
- macファイル名は"TEST.mac"とする。
1. ユーザーに名前の入力を促します。
2. 入力された名前が空であればエラーメッセージを表示します。
3. 名前が入力された場合、その名前を使って挨拶メッセージを表示します。

image

生成されたルーチンをTEST.macにコピーし、ターミナルで実行して動作を確認します。

image

REST APIの作成

簡易なプログラムの生成が確認できたので、次はより複雑なアプリケーションを作成してみます。

アプリケーションの仕様 IRISのREST通信機能を利用したAPIを作成します。ユーザーからのリクエストに基づき、サーバー上のデータベースから該当する商品情報をJSON形式で返します。

テーブルの作成 まずは、テーブルを作成しましょう。DDLの作成をAIに依頼します。

InterSystemsのIRISで{テーブル}を作成するためのDDLを出力してください
#テーブル
##名前
- Sample.Product
##列
- JanCd VARCHAR(13)
- ProductName VARCHAR(100)
- Price INT
## プライマリキー
- JanCd

image

生成されたDDLをターミナルから実行し、テーブルが正常に作成されたことを確認します。

image

テストデータの作成 テストデータの作成もAIにアシストしてもらいましょう。

image

テストデータが正常に登録されたことを確認します。

image

APIの作成 準備が整ったので、APIクラスを生成します。以下のプロンプトを使ってコードを作成します。

あなたはObjectScriptの開発者です。
{仕様}をもとに"Api.Product"クラスを作成してください。
#仕様
- REST通信でJSON形式で商品情報を返す。
- apiのURLは/products/:jancd
- %CSP.RESTクラスを継承する。
- Jsonデータの生成は%DynamicObjectクラスを利用する。
- レスポンスコードは、%responseを利用する。
1. jancdが指定されなかった場合、404を返す。指定された場合、以降の処理を続行する。 
2. "Sample.Product"テーブルをSQLで検索する。
- 取得項目: JanCd,ProductName,Price
- 検索条件: :jancdが指定された場合、テーブルをJanCdが一致するレコードを検索する。
3. 検索結果をJSON形式でREST通信結果として出力する。

image

生成されたコードを確認し、必要に応じて修正を加えます。クエリ結果の取得箇所で%Next()が実行されていなかったため、以下の修正を行いました。

Set tResult = tStatement.%Execute(jancd)
// -*-*-*-*- 処理を追加しました -*-*-*-*-
Do tResult.%Next()

If tResult.%SQLCODE = 100 {

curlコマンドを使用してAPIの動作を確認し、正常にJSONデータが返却されることを確認します。

image

最終的なソースは以下の通りです。今回は一部修正が必要でしたが、基本的な部分は生成AIが正しく対応していました。

  Class Api.Product Extends %CSP.REST
  {

  /// URLマッピング
  XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
  {
  <Routes>
      <Route Url="/products/:jancd" Method="GET" Call="GetProductInfo"/>
  </Routes>
  }

  /// 商品情報を取得するメソッド
  ClassMethod GetProductInfo(jancd As %String) As %Status
  {
      // jancdが指定されていない場合、404を返す
      If jancd = "" {
          Set %response.Status = 404
          Quit $$$OK
      }

      // "Sample.Product"テーブルをSQLで検索する
      Set tStatement = ##class(%SQL.Statement).%New()
      Set tSQL = "SELECT JanCd, ProductName, Price FROM Sample.Product WHERE JanCd = ?"
      Set tStatus = tStatement.%Prepare(tSQL)
      
      If $$$ISERR(tStatus) {
          Set %response.Status = 500
          Quit tStatus
      }
      
      Set tResult = tStatement.%Execute(jancd)
      Do tResult.%Next()
      
      // 検索結果がない場合、404を返す
      If tResult.%SQLCODE = 100 {
          Set %response.Status = 404
          Quit $$$OK
      }
      
      // 検索結果をJSON形式で出力する
      Set tProduct = ##class(%DynamicObject).%New()
      Do tProduct.%Set("JanCd", tResult.%Get("JanCd"))
      Do tProduct.%Set("ProductName", tResult.%Get("ProductName"))
      Do tProduct.%Set("Price", tResult.%Get("Price"))
      
      Write tProduct.%ToJSON(),!
      
      Quit $$$OK
  }

  }

既存コードの活用

次に、生成したAPIに商品名を部分一致で検索するメソッドを追加します。Cursorの外部ファイル参照機能を使い、先ほど生成したクラスを参考にしながら新しいメソッドを作成します。プロンプトは以下の通りです。

@Api.Product.cls 
以下の{仕様}で、"Api.Product"クラスにメソッドを追加してください。
#仕様
- GetProductInfo()の処理を参考にすること。
- apiのURLは/products/name/:productname
- Sample.ProductテーブルからAPIで指定された値が、ProductNameと部分一致するレコードを検索し、検索した結果をJson形式で返す。
- 検索結果は配列にして返す。

image

生成したコードは以下になります。(追加部分のみ抜粋)

  Class Api.Product Extends %CSP.REST
  {
      // ... 既存のコード ...

      /// URLマッピング
      XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
      {
      <Routes>
          // ... 既存のルート ...
          <Route Url="/products/name/:productname" Method="GET" Call="GetProductInfoByName"/>
      </Routes>
      }

      // ... 既存のコード ...

      /// 商品名で商品情報を取得するメソッド
      ClassMethod GetProductInfoByName(productname As %String) As %Status
      {
          // productnameが指定されていない場合、404を返す
          If productname = "" {
              Set %response.Status = 404
              Quit $$$OK
          }

          // "Sample.Product"テーブルをSQLで検索する
          Set tStatement = ##class(%SQL.Statement).%New()
          Set tSQL = "SELECT JanCd, ProductName, Price FROM Sample.Product WHERE ProductName LIKE ?"
          Set tStatus = tStatement.%Prepare(tSQL)
          
          If $$$ISERR(tStatus) {
              Set %response.Status = 500
              Quit tStatus
          }
          
          Set tResult = tStatement.%Execute("%" _ productname _ "%")
          
          // 検索結果がない場合、404を返す
          If tResult.%SQLCODE = 100 {
              Set %response.Status = 404
              Quit $$$OK
          }
          
          // 検索結果をJSON形式で出力する
          Set tProducts = ##class(%DynamicArray).%New()
          While tResult.%Next() {
              Set tProduct = ##class(%DynamicObject).%New()
              Do tProduct.%Set("JanCd", tResult.%Get("JanCd"))
              Do tProduct.%Set("ProductName", tResult.%Get("ProductName"))
              Do tProduct.%Set("Price", tResult.%Get("Price"))
              Do tProducts.%Push(tProduct)
          }
          
          Write tProducts.%ToJSON(),!
          
          Quit $$$OK
      }

      // ... 既存のコード ...
  }

生成されたコードを確認し、curlコマンドで動作を確認します。正常に実行されました。外部ファイル参照機能の利用により、自動生成の精度が向上していることがうかがえます。 image

開発上の課題と解決策

自動生成の精度向上 基本コマンドを用いたプログラムは高い精度を発揮しますが、クラスを利用した複雑な処理では精度が低下する印象を受けました。プロンプトの指示を工夫することで、精度を高めることができそうです。 また、Cursorの外部ドキュメント、ファイル参照機能には大きな可能性を感じました。この機能を使えば、既存のリソースや、AIが学習していないライブラリの活用が期待できます。

セキュリティとプライバシー Cursorはプライバシーモードを備えており、データをサーバーに保持しない設定が可能です。しかし、Cursorに限らず生成AIの業務利用には慎重な調査が必要です。

所感

今回の検証を通じて、生成AIのコード生成能力が向上していることを実感しました。特に、テストデータやDDLの生成は、開発の効率を大幅に向上させる可能性があります。アジャイル開発で迅速なモックアップの作成が求められる場面では、生成AIの効果的な活用が期待できそうです。一方で、既存システムの小規模な改修には、効果が限定的であるという印象を受けました。

この記事を作成したきっかけは、ObjectScriptの初学者向け演習問題を生成AIで作成した際、その問題と解答の品質が非常に高かったことです。業務での活用も十分可能であると思い、今回の検証を行いました。生成AIは、工夫次第でさらなる幅広い活用が期待できるツールだと感じています。

参考資料

0
0 249
記事 Mihoko Iijima · 8月 9, 2024 36m read

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

この記事は、2024年7月に開催された「InterSystems Pythonプログラミングコンテスト2024」でエキスパート投票、コミュニティ投票の両方で1位を獲得された @Henry Pereira Pereira さん @José Pereira さん @Henrique Dias Dias さんが開発された sqlzilla について、アプリを動かしてみた感想と、中の構造について @José Pereira さんが投稿された「Text to IRIS with LangChain」の翻訳をご紹介します。

第2回 InterSystems Japan 技術文書ライティングコンテスト 開催! では、生成AIに関連する記事を投稿いただくと、ボーナスポイントを4点獲得できます📢 @José Pereira さんの記事を💡ヒント💡に皆様の操作体験談、アイデアなどを共有いただければと思います。

開発されたアプリSQLzilla についての概要ですが、Open Exchangesqlzilla のREADMEに以下のように紹介されています。

「SQLzilla は、Python と AI のパワーを活用して、自然言語の SQL クエリ生成を通じてデータ アクセスを簡素化し、複雑なデータ クエリとプログラミング経験の少ないユーザーとの間のギャップを埋めます。」

「SQLクエリ生成」とありますので、アプリには Aviationスキーマ以下3つのテーブルとサンプルデータが用意されています。

  • Aviation.Aircraft
  • Aviation.Crew
  • Aviation.Event

3つのテーブルには、米国国家運輸安全委員会に報告された航空事故の選択されたサブセットのデータが含まれています。

メモ: サンプルリポジトリ で提供されるデータセットは、http://www.ntsb.gov から入手できる完全な NTSB データセットの小さなサブセットであるためデモ目的のみで提供されており、正確であることを意図または保証するものではありません。(提供元:National Transportation Safety Board

例えば、Aviation.Aircraftには、AircraftCategoryカラムがあり、航空機の種別が登録されています。

[SQL]IRISAPP>>SELECT AircraftCategory FROM Aviation.Aircraft GROUP BY AircraftCategory
1.      SELECT AircraftCategory FROM Aviation.Aircraft GROUP BY AircraftCategory

| AircraftCategory |
| -- |
| AIRPLANE |
| HELICOPTER |
| GYROCRAFT |
| GLIDER |
| BALLOON |
| POWERED PARACHUTE |
| WEIGHT SHIFT |

また、DepartureCity には、出発都市名が登録されています。

SELECT top 10 DepartureCity FROM Aviation.Aircraft WHERE AircraftCategory='AIRPLANE' GROUP BY DepartureCity

| DepartureCity |
| -- |
| WILBUR |
| IRONWOOD |
| STANIEL CAY |
| OAK ISLAND |
| CLEVELAND |
| DECATUR |
| MARSHALLTOWN |
| MARANA |
| TONOPAH |
| MURRIETA/TEMECU |

また、Aviation.Eventテーブルには発生した事故の情報が含まれていて、InjuriesHighestには負傷者数の状況を文字で表現した情報が含まれています。

SELECT InjuriesHighest FROM Aviation.Event GROUP BY InjuriesHighest

| InjuriesHighest |
| -- |
| NONE |
| FATAL |
| SERIOUS |
| MINOR |

さて、これらのテーブルを使って具体的にどのようなことをしてくれるアプリなのか?ですが(説明文より以下抜粋)

「SQLzilla は、ユーザーがデータベースを操作する方法を変革する革新的なプロジェクトです。InterSystems IRIS と統合することで、SQL に詳しくないユーザーでもさまざまなテーブルからデータを簡単に抽出して分析できるツールを作成しました。」

つまり、

SQLに詳しくないユーザでも、自分の欲しい情報に対して質問するとSQLを組み立てて返してきてくれる便利アプリということになります。

以下、アプリケーションを動作させてみたときの図です。(日本語で質問してもしっかりSQLを組み立ててくれています!)

image

入力した質問によって生成されたSQLは以下の通りです。

  • ヘリコプターによる事故の件数を教えてください。
SELECT COUNT(*) FROM Aviation.Aircraft WHERE AircraftCategory = 'Helicopter'
  • 2002年に発生したヘリコプターによる事故の件数を教えてください。
SELECT COUNT(*) FROM Aviation.Event WHERE YEAR(EventDate) = 2002 AND Type = 'Helicopter Accident'

image

  • ヘリコプターによる事故でInjuriesHighestがFATALの事故数を年別で表示してください。
SELECT YEAR(e.EventDate) AS IncidentYear, COUNT(*) AS FatalIncidentCount FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE a.AircraftCategory = 'Helicopter' AND e.InjuriesHighest = 'FATAL' GROUP BY YEAR(e.EventDate)

アプリ詳細は、ぜひ Open Exchangesqlzilla をご参照ください。

素晴らしいです!!

※ このサンプルを動作させるためには、OpenAIのAPIキーが必要となりますので、お試しになる場合は事前にご準備ください。

Open Exchangesqlzilla のREADMEにも記載がありますが、コンテナを使う場合は以下3コマンドでサンプルを動作させることができます。

まずはソースコードをclone して

git clone https://github.com/musketeers-br/sqlzilla.git

コンテナをビルドし

docker-compose build --no-cache --progress=plain

コンテナを開始するだけ

docker-compose up -d

後は、アプリ画面を起動するだけ!

コンテナ以外でも操作する方法が提供されています。詳しくは、 sqlzilla のREADMEご参照ください。(ぜひREADMEの一番下までご覧ください!)


記事の紹介

アプリの中でどのようにSQLを生成させているか、については、 @José Pereira さんが投稿された「Text to IRIS with LangChain」の翻訳記事でご紹介します。


LangChainフレームワーク、IRIS Vector Search、LLMを使って、ユーザープロンプトからIRIS互換のSQLを生成する方法についての実験をご紹介します。

この記事は このノートブック を元にしています。 OpenExchange の このアプリケーション を使えば、すぐに使える環境で実行できます。

セットアップ

最初に必要なライブラリをインストールします。

!pip install --upgrade --quiet langchain langchain-openai langchain-iris pandas

次に、必要なモジュールをインポートし、環境をセットアップします。

import os
import datetime
import hashlib
from copy import deepcopy
from sqlalchemy import create_engine
import getpass
import pandas as pd
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.docstore.document import Document
from langchain_community.document_loaders import DataFrameLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_core.output_parsers import StrOutputParser
from langchain.globals import set_llm_cache
from langchain.cache import SQLiteCache
from langchain_iris import IRISVector

SQLiteCacheを使ってLLMコールをキャッシュします。

# Cache for LLM calls
set_llm_cache(SQLiteCache(database_path=".langchain.db"))

IRISデータベースへ接続するためのパラメータをセットします。

# IRIS database connection parameters
os.environ["ISC_LOCAL_SQL_HOSTNAME"] = "localhost"
os.environ["ISC_LOCAL_SQL_PORT"] = "1972"
os.environ["ISC_LOCAL_SQL_NAMESPACE"] = "IRISAPP"
os.environ["ISC_LOCAL_SQL_USER"] = "_system"
os.environ["ISC_LOCAL_SQL_PWD"] = "SYS"

OpenAI APIキーが環境変数に設定されていない場合は、ユーザ入力が求められます。

if not "OPENAI_API_KEY" in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass.getpass()

IRISデータベースの接続文字列を作成します。

# IRIS database connection string
args = {
    'hostname': os.getenv("ISC_LOCAL_SQL_HOSTNAME"), 
    'port': os.getenv("ISC_LOCAL_SQL_PORT"), 
    'namespace': os.getenv("ISC_LOCAL_SQL_NAMESPACE"), 
    'username': os.getenv("ISC_LOCAL_SQL_USER"), 
    'password': os.getenv("ISC_LOCAL_SQL_PWD")
}
iris_conn_str = f"iris://{args['username']}:{args['password']}@{args['hostname']}:{args['port']}/{args['namespace']}"

IRISデータベースとの接続を確立します。

# Connection to IRIS database
engine = create_engine(iris_conn_str)
cnx = engine.connect().connection

システムプロンプトのコンテキスト情報を保持するdictionaryを用意します。

# Dict for context information for system prompt
context = {}
context["top_k"] = 3

プロンプトの作成

ユーザー入力をIRISデータベースと互換性のあるSQLクエリに変換するために、言語モデル用の効果的なプロンプトを作成する必要があります。

SQLクエリを生成するための基本的な指示を提供する初期プロンプトから始めます。

このテンプレートはLangChain's default prompts for MSSQL から派生し、IRISデータベース用にカスタマイズされています。

# Basic prompt template with IRIS database SQL instructions
iris_sql_template = """
You are an InterSystems IRIS expert. Given an input question, first create a syntactically correct InterSystems IRIS query to run and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the TOP clause as per InterSystems IRIS. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in single quotes ('') to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Pay attention to use CAST(CURRENT_DATE as date) function to get the current date, if the question involves "today".
Use double quotes to delimit columns identifiers.
Return just plain SQL; don't apply any kind of formatting.
"""

次のような文章をテンプレートに設定しています: あなたは InterSystems IRIS のエキスパートです。 入力された質問に対して、まず、構文的に正しい InterSystems IRIS クエリを作成し、そのクエリを実行し て、入力された質問に対する回答を返します。 ユーザが質問で特定の数の例を取得するように指定しない限り、InterSystems IRIS に従って、TOP 節を使用して最大 {top_k} の結果をクエリします。 テーブルのすべての列に対してクエリを実行してはなりません。 質問に答えるために必要なカラムのみを問い合わせなければなりません。 各カラム名をシングルクォート('')で囲み、区切り識別子にします。 以下の表で確認できるカラム名のみを使用するように注意してください。 存在しないカラムを問い合わせないように注意してください。 また、どのカラムがどのテーブルにあるかに注意すること。 質問内容が "今日 "を含む場合は、CAST(CURRENT_DATE as date)関数を使用して現在の日付を取得することに注意すること。 カラムの識別子を区切るには二重引用符を使用すること。 単なるSQLを返すこと。いかなるフォーマットも適用しないこと。

この基本プロンプトは、言語モデル(LLM)がIRISデータベースに対する特定のガイダンスを持つSQLエキスパートとして機能するように設定しています。

次に、ハルシネーション(幻覚)を避けるために、データベーススキーマに関する情報を補助プロンプトとして提供します。

# SQL template extension for including tables context information
tables_prompt_template = """
Only use the following tables:
{table_info}
"""

LLMの回答の精度を高めるために、私たちはfew-shot プロンプトと呼ばれるテクニックを使いました。 これはLLMにいくつかの例を提示するものです。

# SQL template extension for including few shots
prompt_sql_few_shots_template = """
Below are a number of examples of questions and their corresponding SQL queries.

{examples_value}
"""

私たちは few-shot の例のためにテンプレートを以下のように定義しています。

# Few shots prompt template
example_prompt_template = "User input: {input}\nSQL query: {query}"
example_prompt = PromptTemplate.from_template(example_prompt_template)

私たちは、 few-shot テンプレートを使ってユーザー・プロンプトを作っています。

# User prompt template
user_prompt = "\n" + example_prompt.invoke({"input": "{input}", "query": ""}).to_string()

最後に、すべてのプロンプトを組み合わせて最終的なプロンプトを作成します。

# Complete prompt template
prompt = (
    ChatPromptTemplate.from_messages([("system", iris_sql_template)])
    + ChatPromptTemplate.from_messages([("system", tables_prompt_template)])
    + ChatPromptTemplate.from_messages([("system", prompt_sql_few_shots_template)])
    + ChatPromptTemplate.from_messages([("human", user_prompt)])
)
prompt

このプロンプトは、変数 examples_value, input, table_info, and top_k を想定しています。

プロンプトの構成は以下の通りです。

ChatPromptTemplate(
    input_variables=['examples_value', 'input', 'table_info', 'top_k'], 
    messages=[
        SystemMessagePromptTemplate(
            prompt=PromptTemplate(
                input_variables=['top_k'], 
                template=iris_sql_template
            )
        ), 
        SystemMessagePromptTemplate(
            prompt=PromptTemplate(
                input_variables=['table_info'], 
                template=tables_prompt_template
            )
        ), 
        SystemMessagePromptTemplate(
            prompt=PromptTemplate(
                input_variables=['examples_value'], 
                template=prompt_sql_few_shots_template
            )
        ), 
        HumanMessagePromptTemplate(
            prompt=PromptTemplate(
                input_variables=['input'], 
                template=user_prompt
            )
        )
    ]
)

プロンプトがどのようにLLMに送られるかを視覚化するために、必要な変数にプレースホルダーの値を使うことができます。

prompt_value = prompt.invoke({
    "top_k": "<top_k>",
    "table_info": "<table_info>",
    "examples_value": "<examples_value>",
    "input": "<input>"
})
print(prompt_value.to_string())
System: 
You are an InterSystems IRIS expert. Given an input question, first create a syntactically correct InterSystems IRIS query to run and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most <top_k> results using the TOP clause as per InterSystems IRIS. You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question. Wrap each column name in single quotes ('') to denote them as delimited identifiers.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Pay attention to use CAST(CURRENT_DATE as date) function to get the current date, if the question involves "today".
Use double quotes to delimit columns identifiers.
Return just plain SQL; don't apply any kind of formatting.

System: 
Only use the following tables:
<table_info>

System: 
Below are a number of examples of questions and their corresponding SQL queries.

<examples_value>

Human: 
User input: <input>
SQL query: 

これで、必要な変数を与えることで、このプロンプトをLLMに送る準備ができました。 準備ができたら次のステップに進みましょう。

テーブル情報の提供

正確なSQLクエリを作成するためには、言語モデル(LLM)にデータベース・テーブルに関する詳細な情報を提供する必要があります。

この情報がないと、LLMは一見もっともらしく見えますが、ハルシネーション(幻覚)により正しくないクエリを生成する可能性があります。 そこで、最初のステップとして、IRISデータベースからテーブル定義を取得する関数を作成します。

テーブル定義情報を取得する関数

以下の関数はINFORMATION_SCHEMAに問い合わせ、指定されたスキーマのテーブル定義を取得します。

特定のテーブルが指定された場合は、そのテーブルの定義を取得します。そうでない場合は、スキーマ内の全てのテーブルの定義を取得します。

def get_table_definitions_array(cnx, schema, table=None):
    cursor = cnx.cursor()

    # Base query to get columns information
    query = """
    SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, PRIMARY_KEY, null EXTRA
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_SCHEMA = %s
    """
    
    # Parameters for the query
    params = [schema]

    # Adding optional filters
    if table:
        query += " AND TABLE_NAME = %s"
        params.append(table)
    
    # Execute the query
    cursor.execute(query, params)

    # Fetch the results
    rows = cursor.fetchall()
    
    # Process the results to generate the table definition(s)
    table_definitions = {}
    for row in rows:
        table_schema, table_name, column_name, column_type, is_nullable, column_default, column_key, extra = row
        if table_name not in table_definitions:
            table_definitions[table_name] = []
        table_definitions[table_name].append({
            "column_name": column_name,
            "column_type": column_type,
            "is_nullable": is_nullable,
            "column_default": column_default,
            "column_key": column_key,
            "extra": extra
        })

    primary_keys = {}
    
    # Build the output string
    result = []
    for table_name, columns in table_definitions.items():
        table_def = f"CREATE TABLE {schema}.{table_name} (\n"
        column_definitions = []
        for column in columns:
            column_def = f"  {column['column_name']} {column['column_type']}"
            if column['is_nullable'] == "NO":
                column_def += " NOT NULL"
            if column['column_default'] is not None:
                column_def += f" DEFAULT {column['column_default']}"
            if column['extra']:
                column_def += f" {column['extra']}"
            column_definitions.append(column_def)
        if table_name in primary_keys:
            pk_def = f"  PRIMARY KEY ({', '.join(primary_keys[table_name])})"
            column_definitions.append(pk_def)
        table_def += ",\n".join(column_definitions)
        table_def += "\n);"
        result.append(table_def)

    return result

スキーマのテーブル定義を取得する

この例では、Aviationスキーマを使用しています。Aviationスキーマ情報一式については こちら から入手できます。

# Retrieve table definitions for the Aviation schema
tables = get_table_definitions_array(cnx, "Aviation")
print(tables)

この関数は、Aviation スキーマ内のすべてのテーブルの CREATE TABLE ステートメントを返します。

[
    'CREATE TABLE Aviation.Aircraft (\n  Event bigint NOT NULL,\n  ID varchar NOT NULL,\n  AccidentExplosion varchar,\n  AccidentFire varchar,\n  AirFrameHours varchar,\n  AirFrameHoursSince varchar,\n  AirFrameHoursSinceLastInspection varchar,\n  AircraftCategory varchar,\n  AircraftCertMaxGrossWeight integer,\n  AircraftHomeBuilt varchar,\n  AircraftKey integer NOT NULL,\n  AircraftManufacturer varchar,\n  AircraftModel varchar,\n  AircraftRegistrationClass varchar,\n  AircraftSerialNo varchar,\n  AircraftSeries varchar,\n  Damage varchar,\n  DepartureAirportId varchar,\n  DepartureCity varchar,\n  DepartureCountry varchar,\n  DepartureSameAsEvent varchar,\n  DepartureState varchar,\n  DepartureTime integer,\n  DepartureTimeZone varchar,\n  DestinationAirportId varchar,\n  DestinationCity varchar,\n  DestinationCountry varchar,\n  DestinationSameAsLocal varchar,\n  DestinationState varchar,\n  EngineCount integer,\n  EvacuationOccurred varchar,\n  EventId varchar NOT NULL,\n  FlightMedical varchar,\n  FlightMedicalType varchar,\n  FlightPhase integer,\n  FlightPlan varchar,\n  FlightPlanActivated varchar,\n  FlightSiteSeeing varchar,\n  FlightType varchar,\n  GearType varchar,\n  LastInspectionDate timestamp,\n  LastInspectionType varchar,\n  Missing varchar,\n  OperationDomestic varchar,\n  OperationScheduled varchar,\n  OperationType varchar,\n  OperatorCertificate varchar,\n  OperatorCertificateNum varchar,\n  OperatorCode varchar,\n  OperatorCountry varchar,\n  OperatorIndividual varchar,\n  OperatorName varchar,\n  OperatorState varchar,\n  Owner varchar,\n  OwnerCertified varchar,\n  OwnerCountry varchar,\n  OwnerState varchar,\n  RegistrationNumber varchar,\n  ReportedToICAO varchar,\n  SeatsCabinCrew integer,\n  SeatsFlightCrew integer,\n  SeatsPassengers integer,\n  SeatsTotal integer,\n  SecondPilot varchar,\n  childsub bigint NOT NULL DEFAULT $i(^Aviation.EventC("Aircraft"))\n);',
    'CREATE TABLE Aviation.Crew (\n  Aircraft varchar NOT NULL,\n  ID varchar NOT NULL,\n  Age integer,\n  AircraftKey integer NOT NULL,\n  Category varchar,\n  CrewNumber integer NOT NULL,\n  EventId varchar NOT NULL,\n  Injury varchar,\n  MedicalCertification varchar,\n  MedicalCertificationDate timestamp,\n  MedicalCertificationValid varchar,\n  Seat varchar,\n  SeatbeltUsed varchar,\n  Sex varchar,\n  ShoulderHarnessUsed varchar,\n  ToxicologyTestPerformed varchar,\n  childsub bigint NOT NULL DEFAULT $i(^Aviation.AircraftC("Crew"))\n);',
    'CREATE TABLE Aviation.Event (\n  ID bigint NOT NULL DEFAULT $i(^Aviation.EventD),\n  AirportDirection integer,\n  AirportDistance varchar,\n  AirportElevation integer,\n  AirportLocation varchar,\n  AirportName varchar,\n  Altimeter varchar,\n  EventDate timestamp,\n  EventId varchar NOT NULL,\n  EventTime integer,\n  FAADistrictOffice varchar,\n  InjuriesGroundFatal integer,\n  InjuriesGroundMinor integer,\n  InjuriesGroundSerious integer,\n  InjuriesHighest varchar,\n  InjuriesTotal integer,\n  InjuriesTotalFatal integer,\n  InjuriesTotalMinor integer,\n  InjuriesTotalNone integer,\n  InjuriesTotalSerious integer,\n  InvestigatingAgency varchar,\n  LightConditions varchar,\n  LocationCity varchar,\n  LocationCoordsLatitude double,\n  LocationCoordsLongitude double,\n  LocationCountry varchar,\n  LocationSiteZipCode varchar,\n  LocationState varchar,\n  MidAir varchar,\n  NTSBId varchar,\n  NarrativeCause varchar,\n  NarrativeFull varchar,\n  NarrativeSummary varchar,\n  OnGroundCollision varchar,\n  SkyConditionCeiling varchar,\n  SkyConditionCeilingHeight integer,\n  SkyConditionNonCeiling varchar,\n  SkyConditionNonCeilingHeight integer,\n  TimeZone varchar,\n  Type varchar,\n  Visibility varchar,\n  WeatherAirTemperature integer,\n  WeatherPrecipitation varchar,\n  WindDirection integer,\n  WindDirectionIndicator varchar,\n  WindGust integer,\n  WindGustIndicator varchar,\n  WindVelocity integer,\n  WindVelocityIndicator varchar\n);'
]

これらのテーブル定義ができたので、次のステップに進むことができます。

これにより、LLMがSQLクエリを生成する際に、データベース・スキーマに関する正確で包括的な情報が得られるようになります。

最も関連性の高いテーブルを選ぶ

データベース、特に大規模なデータベースを扱う場合、プロンプト内のすべてのテーブルのデータ定義言語(DDL)を送信することは非現実的です。

このアプローチは小規模なデータベースでは有効かもしれませんが、現実のデータベースには数百から数千のテーブルが含まれていることが多く、すべてのテーブルを処理するのは非効率的です。

さらに、SQLクエリを効率的に生成するために、言語モデルがデータベース内のすべてのテーブルを認識する必要があるとは考えにくいです。 この課題に対処するため、セマンティック検索機能を活用し、ユーザーのクエリに基づいて最も関連性の高いテーブルのみを選択することができます。

アプローチ

IRIS Vector Searchでセマンティック検索を使用することでこれを実現します。

この方法は、SQL要素の識別子(テーブル、フィールド、キーなど)に意味のある名前がある場合に最も効果的です。識別子が任意のコードである場合は、代わりにデータ dictionaryの使用を検討してください。

手順

  1. テーブル情報の取得

まず、テーブル定義をpandas DataFrameに取り出します。

# Retrieve table definitions into a pandas DataFrame
table_def = get_table_definitions_array(cnx=cnx, schema='Aviation')
table_df = pd.DataFrame(data=table_def, columns=["col_def"])
table_df["id"] = table_df.index + 1
table_df

DataFrame(table_df)は以下のようになります。

col_defid
0CREATE TABLE Aviation.Aircraft (\n Event bigi...1
1CREATE TABLE Aviation.Crew (\n Aircraft varch...2
2CREATE TABLE Aviation.Event (\n ID bigint NOT...3
  1. 定義をDocumentsに分割する

次に、テーブル定義をLangchain Documentsに分割します。 このステップは、大きなテキストの塊を扱い、テキスト埋め込みを抽出するために非常に重要です。

loader = DataFrameLoader(table_df, page_content_column="col_def")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=400, chunk_overlap=20, separator="\n")
tables_docs = text_splitter.split_documents(documents)
tables_docs

その結果、tables_docsリストには、次のようにメタデータ付きの分割ドキュメントが含まれます。

[Document(metadata={'id': 1}, page_content='CREATE TABLE Aviation.Aircraft (\n  Event bigint NOT NULL,\n  ID varchar NOT NULL,\n  ...'),
 Document(metadata={'id': 2}, page_content='CREATE TABLE Aviation.Crew (\n  Aircraft varchar NOT NULL,\n  ID varchar NOT NULL,\n  ...'),
 Document(metadata={'id': 3}, page_content='CREATE TABLE Aviation.Event (\n  ID bigint NOT NULL DEFAULT $i(^Aviation.EventD),\n  ...')]
  1. 埋め込み(Embedding)の抽出とIRISへの保存

次に,langchain-irisのIRISVectorクラスを使って埋め込みベクトルを抽出し、それをIRISに格納します。

tables_vector_store = IRISVector.from_documents(
    embedding=OpenAIEmbeddings(), 
    documents=tables_docs,
    connection_string=iris_conn_str,
    collection_name="sql_tables",
    pre_delete_collection=True
)

注意: pre_delete_collection フラグは、各テスト実行で新鮮なコレクションを確保するために、デモ用に True に設定されています。 本番環境では、このフラグは通常 False に設定します。

  1. 関連文書の検索

テーブルに埋め込み(Embedding)が保存されたことで、ユーザー入力に基づいて関連するテーブルを検索できるようになりました。

input_query = "List the first 2 manufacturers"
relevant_tables_docs = tables_vector_store.similarity_search(input_query, k=3)
relevant_tables_docs

例えば、manufacturers を検索すると、次のような結果が返ってきます。

[Document(metadata={'id': 1}, page_content='GearType varchar,\n  LastInspectionDate timestamp,\n  ...'),
 Document(metadata={'id': 1}, page_content='AircraftModel varchar,\n  AircraftRegistrationClass varchar,\n  ...'),
 Document(metadata={'id': 3}, page_content='LocationSiteZipCode varchar,\n  LocationState varchar,\n  ...')]

メタデータから、テーブルID 1 (Aviation.Aircraft)だけが関連性があり、クエリと一致していることがわかります。

  1. エッジケースへの対応

このアプローチは一般的に効果的ではありますが、常に完璧とは限りません。 たとえば、事故現場のクエリを実行すると、関連性の低いテーブルが返されることもあります。

input_query = "List the top 10 most crash sites"
relevant_tables_docs = tables_vector_store.similarity_search(input_query, k=3)
relevant_tables_docs

結果は以下の通りです。

[Document(metadata={'id': 3}, page_content='LocationSiteZipCode varchar,\n  LocationState varchar,\n  ...'),
 Document(metadata={'id': 3}, page_content='InjuriesGroundSerious integer,\n  InjuriesHighest varchar,\n  ...'),
 Document(metadata={'id': 1}, page_content='CREATE TABLE Aviation.Aircraft (\n  Event bigint NOT NULL,\n  ID varchar NOT NULL,\n  ...')]

正しいAviation.Eventテーブルを2回取得したにもかかわらず、Aviation.Aircraftテーブルも表示されることがあります。これは、この例の範囲を超えているため、将来の実装に委ねられます。

  1. 関連テーブルを取得する関数を定義する

このプロセスを自動化するため、ユーザー入力に基づいて関連するテーブルをフィルタリングして返す関数を定義します。

def get_relevant_tables(user_input, tables_vector_store, table_df):
    relevant_tables_docs = tables_vector_store.similarity_search(user_input)
    relevant_tables_docs_indices = [x.metadata["id"] for x in relevant_tables_docs]
    indices = table_df["id"].isin(relevant_tables_docs_indices)
    relevant_tables_array = [x for x in table_df[indices]["col_def"]]
    return relevant_tables_array

この機能は、LLMに送信する関連テーブルのみを効率的に検索し、プロンプトの長さを短縮し、クエリ全体のパフォーマンスを向上させるのに役立ちます。

最も適切な例を選ぶ(Few-Shotプロンプティング)

言語モデル(LLM)を扱うとき、適切な例を提供することは、正確で文脈的に適切な応答を保証するのに役立ちます。

これらの例は "Few-Shot" 例と呼ばれ、LLMが処理すべきクエリの構造とコンテキストを理解するためのガイドとなります。今回のケースでは、IRISのSQL構文とデータベースで使用可能なテーブルを幅広くカバーする多様なSQLクエリを examples_value 変数に入力する必要があります。これは、LLMが正しくないクエリーや無関係なクエリーを生成するのを防ぐのに役立ちます。

クエリ例の定義

以下は、様々なSQL操作を説明するために作られたクエリ例のリストです。

examples = [
    {"input": "List all aircrafts.", "query": "SELECT * FROM Aviation.Aircraft"},
    {"input": "Find all incidents for the aircraft with ID 'N12345'.", "query": "SELECT * FROM Aviation.Event WHERE EventId IN (SELECT EventId FROM Aviation.Aircraft WHERE ID = 'N12345')"},
    {"input": "List all incidents in the 'Commercial' operation type.", "query": "SELECT * FROM Aviation.Event WHERE EventId IN (SELECT EventId FROM Aviation.Aircraft WHERE OperationType = 'Commercial')"},
    {"input": "Find the total number of incidents.", "query": "SELECT COUNT(*) FROM Aviation.Event"},
    {"input": "List all incidents that occurred in 'Canada'.", "query": "SELECT * FROM Aviation.Event WHERE LocationCountry = 'Canada'"},
    {"input": "How many incidents are associated with the aircraft with AircraftKey 5?", "query": "SELECT COUNT(*) FROM Aviation.Aircraft WHERE AircraftKey = 5"},
    {"input": "Find the total number of distinct aircrafts involved in incidents.", "query": "SELECT COUNT(DISTINCT AircraftKey) FROM Aviation.Aircraft"},
    {"input": "List all incidents that occurred after 5 PM.", "query": "SELECT * FROM Aviation.Event WHERE EventTime > 1700"},
    {"input": "Who are the top 5 operators by the number of incidents?", "query": "SELECT TOP 5 OperatorName, COUNT(*) AS IncidentCount FROM Aviation.Aircraft GROUP BY OperatorName ORDER BY IncidentCount DESC"},
    {"input": "Which incidents occurred in the year 2020?", "query": "SELECT * FROM Aviation.Event WHERE YEAR(EventDate) = '2020'"},
    {"input": "What was the month with most events in the year 2020?", "query": "SELECT TOP 1 MONTH(EventDate) EventMonth, COUNT(*) EventCount FROM Aviation.Event WHERE YEAR(EventDate) = '2020' GROUP BY MONTH(EventDate) ORDER BY EventCount DESC"},
    {"input": "How many crew members were involved in incidents?", "query": "SELECT COUNT(*) FROM Aviation.Crew"},
    {"input": "List all incidents with detailed aircraft information for incidents that occurred in the year 2012.", "query": "SELECT e.EventId, e.EventDate, a.AircraftManufacturer, a.AircraftModel, a.AircraftCategory FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE Year(e.EventDate) = 2012"},
    {"input": "Find all incidents where there were more than 5 injuries and include the aircraft manufacturer and model.", "query": "SELECT e.EventId, e.InjuriesTotal, a.AircraftManufacturer, a.AircraftModel FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE e.InjuriesTotal > 5"},
    {"input": "List all crew members involved in incidents with serious injuries, along with the incident date and location.", "query": "SELECT c.CrewNumber AS 'Crew Number', c.Age, c.Sex AS Gender, e.EventDate AS 'Event Date', e.LocationCity AS 'Location City', e.LocationState AS 'Location State' FROM Aviation.Crew c JOIN Aviation.Event e ON c.EventId = e.EventId WHERE c.Injury = 'Serious'"}
]

関連する事例の選択

例のリストが増え続けることを考えると、LLMにすべての例を提供することは現実的ではありません。代わりに、IRIS Vector SearchとSemanticSimilarityExampleSelectorクラスを使用して、ユーザーのプロンプトに基づいて最も関連性の高い例を特定します。

Example Selector を定義する

example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,
    OpenAIEmbeddings(),
    IRISVector,
    k=5,
    input_keys=["input"],
    connection_string=iris_conn_str,
    collection_name="sql_samples",
    pre_delete_collection=True
)

注意: pre_delete_collection フラグは、各テスト実行で新鮮なコレクションを確保するためのデモンストレーション目的で使用されています。本番環境では、不要な削除を避けるためにこのフラグを False に設定する必要があります。

Selectorに問い合わせる

与えられた入力に最も関連する例を見つけるには、次のようにSelector を使用します。

input_query = "Find all events in 2010 informing the Event Id and date, location city and state, aircraft manufacturer and model."
relevant_examples = example_selector.select_examples({"input": input_query})

結果は以下のようになります。

[{'input': 'List all incidents with detailed aircraft information for incidents that occurred in the year 2012.', 'query': 'SELECT e.EventId, e.EventDate, a.AircraftManufacturer, a.AircraftModel, a.AircraftCategory FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE Year(e.EventDate) = 2012'},
 {'input': "Find all incidents for the aircraft with ID 'N12345'.", 'query': "SELECT * FROM Aviation.Event WHERE EventId IN (SELECT EventId FROM Aviation.Aircraft WHERE ID = 'N12345')"},
 {'input': 'Find all incidents where there were more than 5 injuries and include the aircraft manufacturer and model.', 'query': 'SELECT e.EventId, e.InjuriesTotal, a.AircraftManufacturer, a.AircraftModel FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE e.InjuriesTotal > 5'},
 {'input': 'List all aircrafts.', 'query': 'SELECT * FROM Aviation.Aircraft'},
 {'input': 'Find the total number of distinct aircrafts involved in incidents.', 'query': 'SELECT COUNT(DISTINCT AircraftKey) FROM Aviation.Aircraft'}]

数量に関連した例が特に必要な場合は、それに応じてSelectorに問い合わせることができます。

input_query = "What is the number of incidents involving Boeing aircraft."
quantity_examples = example_selector.select_examples({"input": input_query})

出力は以下の通りです。

[{'input': 'How many incidents are associated with the aircraft with AircraftKey 5?', 'query': 'SELECT COUNT(*) FROM Aviation.Aircraft WHERE AircraftKey = 5'},
 {'input': 'Find the total number of distinct aircrafts involved in incidents.', 'query': 'SELECT COUNT(DISTINCT AircraftKey) FROM Aviation.Aircraft'},
 {'input': 'How many crew members were involved in incidents?', 'query': 'SELECT COUNT(*) FROM Aviation.Crew'},
 {'input': 'Find all incidents where there were more than 5 injuries and include the aircraft manufacturer and model.', 'query': 'SELECT e.EventId, e.InjuriesTotal, a.AircraftManufacturer, a.AircraftModel FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE e.InjuriesTotal > 5'},
 {'input': 'List all incidents with detailed aircraft information for incidents that occurred in the year 2012.', 'query': 'SELECT e.EventId, e.EventDate, a.AircraftManufacturer, a.AircraftModel, a.AircraftCategory FROM Aviation.Event e JOIN Aviation.Aircraft a ON e.EventId = a.EventId WHERE Year(e.EventDate) = 2012'}]

この出力には、特にカウントと量を扱った例が含まれています。

今後の検討事項

SemanticSimilarityExampleSelectorは強力ですが、選択された例がすべて完璧であるとは限らないことに注意することが重要です。

将来的な改良には、フィルターやしきい値を追加して関連性の低い結果を除外し、最も適切な例だけがLLMに提供されるようにすることが含まれるかもしれません。

精度テスト

プロンプトとSQLクエリ生成のパフォーマンスを評価するために、一連のテストを設定し実行する必要があります。その目的は、LLMがユーザーの入力に基づいてSQLクエリを生成する際に、例題に基づいたfew shotを使用する場合と使用しない場合の、その精度を評価することである。

SQLクエリを生成する関数

まず、LLMを使って、提供されたコンテキスト、プロンプト、ユーザー入力、その他のパラメーターに基づいてSQLクエリーを生成する関数を定義します。

def get_sql_from_text(context, prompt, user_input, use_few_shots, tables_vector_store, table_df, example_selector=None, example_prompt=None):
    relevant_tables = get_relevant_tables(user_input, tables_vector_store, table_df)
    context["table_info"] = "\n\n".join(relevant_tables)

    examples = example_selector.select_examples({"input": user_input}) if example_selector else []
    context["examples_value"] = "\n\n".join([
        example_prompt.invoke(x).to_string() for x in examples
    ])
    
    model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
    output_parser = StrOutputParser()
    chain_model = prompt | model | output_parser
    
    response = chain_model.invoke({
        "top_k": context["top_k"],
        "table_info": context["table_info"],
        "examples_value": context["examples_value"],
        "input": user_input
    })
    return response

プロンプトの実行

例文がある場合とない場合のプロンプトをテストします。

# Prompt execution **with** few shots
input = "Find all events in 2010 informing the Event Id and date, location city and state, aircraft manufacturer and model."
response_with_few_shots = get_sql_from_text(
    context, 
    prompt, 
    user_input=input, 
    use_few_shots=True, 
    tables_vector_store=tables_vector_store, 
    table_df=table_df,
    example_selector=example_selector, 
    example_prompt=example_prompt,
)
print(response_with_few_shots)
SELECT e.EventId, e.EventDate, e.LocationCity, e.LocationState, a.AircraftManufacturer, a.AircraftModel
FROM Aviation.Event e
JOIN Aviation.Aircraft a ON e.EventId = a.EventId
WHERE Year(e.EventDate) = 2010
# Prompt execution **without** few shots
input = "Find all events in 2010 informing the Event Id and date, location city and state, aircraft manufacturer and model."
response_with_no_few_shots = get_sql_from_text(
    context, 
    prompt, 
    user_input=input, 
    use_few_shots=False, 
    tables_vector_store=tables_vector_store, 
    table_df=table_df,
)
print(response_with_no_few_shots)
SELECT TOP 3 "EventId", "EventDate", "LocationCity", "LocationState", "AircraftManufacturer", "AircraftModel"
FROM Aviation.Event e
JOIN Aviation.Aircraft a ON e.ID = a.Event
WHERE e.EventDate >= '2010-01-01' AND e.EventDate < '2011-01-01'
Utility Functions for Testing

生成されたSQLクエリをテストするために、いくつかのユーティリティ関数を定義します。

def execute_sql_query(cnx, query):
    try:
        cursor = cnx.cursor()
        cursor.execute(query)
        rows = cursor.fetchall()
        return rows
    except:
        print('Error running query:')
        print(query)
        print('-'*80)
    return None

def sql_result_equals(cnx, query, expected):
    rows = execute_sql_query(cnx, query)
    result = [set(row._asdict().values()) for row in rows or []]
    if result != expected and rows is not None:
        print('Result not as expected for query:')
        print(query)
        print('-'*80)
    return result == expected
# SQL test for prompt **with** few shots
print("SQL is OK" if not execute_sql_query(cnx, response_with_few_shots) is None else "SQL is not OK")
    SQL is OK
# SQL test for prompt **without** few shots
print("SQL is OK" if not execute_sql_query(cnx, response_with_no_few_shots) is None else "SQL is not OK")
    error on running query: 
    SELECT TOP 3 "EventId", "EventDate", "LocationCity", "LocationState", "AircraftManufacturer", "AircraftModel"
    FROM Aviation.Event e
    JOIN Aviation.Aircraft a ON e.ID = a.Event
    WHERE e.EventDate >= '2010-01-01' AND e.EventDate < '2011-01-01'
    --------------------------------------------------------------------------------
    SQL is not OK

テストの定義と実行

一連のテストケースを定義し、実行します。

tests = [{
    "input": "What were the top 3 years with the most recorded events?",
    "expected": [{128, 2003}, {122, 2007}, {117, 2005}]
},{
    "input": "How many incidents involving Boeing aircraft.",
    "expected": [{5}]
},{
    "input": "How many incidents that resulted in fatalities.",
    "expected": [{237}]
},{
    "input": "List event Id and date and, crew number, age and gender for incidents that occurred in 2013.",
    "expected": [{1, datetime.datetime(2013, 3, 4, 11, 6), '20130305X71252', 59, 'M'},
                 {1, datetime.datetime(2013, 1, 1, 15, 0), '20130101X94035', 32, 'M'},
                 {2, datetime.datetime(2013, 1, 1, 15, 0), '20130101X94035', 35, 'M'},
                 {1, datetime.datetime(2013, 1, 12, 15, 0), '20130113X42535', 25, 'M'},
                 {2, datetime.datetime(2013, 1, 12, 15, 0), '20130113X42535', 34, 'M'},
                 {1, datetime.datetime(2013, 2, 1, 15, 0), '20130203X53401', 29, 'M'},
                 {1, datetime.datetime(2013, 2, 15, 15, 0), '20130218X70747', 27, 'M'},
                 {1, datetime.datetime(2013, 3, 2, 15, 0), '20130303X21011', 49, 'M'},
                 {1, datetime.datetime(2013, 3, 23, 13, 52), '20130326X85150', 'M', None}]
},{
    "input": "Find the total number of incidents that occurred in the United States.",
    "expected": [{1178}]
},{
    "input": "List all incidents latitude and longitude coordinates with more than 5 injuries that occurred in 2010.",
    "expected": [{-78.76833333333333, 43.25277777777778}]
},{
    "input": "Find all incidents in 2010 informing the Event Id and date, location city and state, aircraft manufacturer and model.",
    "expected": [
        {datetime.datetime(2010, 5, 20, 13, 43), '20100520X60222', 'CIRRUS DESIGN CORP', 'Farmingdale', 'New York', 'SR22'},
        {datetime.datetime(2010, 4, 11, 15, 0), '20100411X73253', 'CZECH AIRCRAFT WORKS SPOL SRO', 'Millbrook', 'New York', 'SPORTCRUISER'},
        {'108', datetime.datetime(2010, 1, 9, 12, 55), '20100111X41106', 'Bayport', 'New York', 'STINSON'},
        {datetime.datetime(2010, 8, 1, 14, 20), '20100801X85218', 'A185F', 'CESSNA', 'New York', 'Newfane'}
    ]
}]

精度評価

テストを実施し、精度を計算します。

def execute_tests(cnx, context, prompt, use_few_shots, tables_vector_store, table_df, example_selector, example_prompt):
    tests_generated_sql = [(x, get_sql_from_text(
            context, 
            prompt, 
            user_input=x['input'], 
            use_few_shots=use_few_shots, 
            tables_vector_store=tables_vector_store, 
            table_df=table_df,
            example_selector=example_selector if use_few_shots else None, 
            example_prompt=example_prompt if use_few_shots else None,
        )) for x in deepcopy(tests)]
    
    tests_sql_executions = [(x[0], sql_result_equals(cnx, x[1], x[0]['expected'])) 
                            for x in tests_generated_sql]
    
    accuracy = sum(1 for i in tests_sql_executions if i[1] == True) / len(tests_sql_executions)
    print(f'Accuracy: {accuracy}')
    print('-'*80)

結果

# Accuracy tests for prompts executed **without** few shots
use_few_shots = False
execute_tests(
    cnx,
    context, 
    prompt, 
    use_few_shots, 
    tables_vector_store, 
    table_df, 
    example_selector, 
    example_prompt
)
    error on running query: 
    SELECT "EventDate", COUNT("EventId") as "TotalEvents"
    FROM Aviation.Event
    GROUP BY "EventDate"
    ORDER BY "TotalEvents" DESC
    TOP 3;
    --------------------------------------------------------------------------------
    error on running query: 
    SELECT "EventId", "EventDate", "C"."CrewNumber", "C"."Age", "C"."Sex"
    FROM "Aviation.Event" AS "E"
    JOIN "Aviation.Crew" AS "C" ON "E"."ID" = "C"."EventId"
    WHERE "E"."EventDate" >= '2013-01-01' AND "E"."EventDate" < '2014-01-01'
    --------------------------------------------------------------------------------
    result not expected for query: 
    SELECT TOP 3 "e"."EventId", "e"."EventDate", "e"."LocationCity", "e"."LocationState", "a"."AircraftManufacturer", "a"."AircraftModel"
    FROM "Aviation"."Event" AS "e"
    JOIN "Aviation"."Aircraft" AS "a" ON "e"."ID" = "a"."Event"
    WHERE "e"."EventDate" >= '2010-01-01' AND "e"."EventDate" < '2011-01-01'
    --------------------------------------------------------------------------------
    accuracy: 0.5714285714285714
    --------------------------------------------------------------------------------
# Accuracy tests for prompts executed **with** few shots
use_few_shots = True
execute_tests(
    cnx,
    context, 
    prompt, 
    use_few_shots, 
    tables_vector_store, 
    table_df, 
    example_selector, 
    example_prompt
)
    error on running query: 
    SELECT e.EventId, e.EventDate, e.LocationCity, e.LocationState, a.AircraftManufacturer, a.AircraftModel
    FROM Aviation.Event e
    JOIN Aviation.Aircraft a ON e.EventId = a.EventId
    WHERE Year(e.EventDate) = 2010 TOP 3
    --------------------------------------------------------------------------------
    accuracy: 0.8571428571428571
    --------------------------------------------------------------------------------

結論

例(few shots)を使って生成されたSQLクエリの精度は、例なしで生成されたもの(85%対57%)に比べて約49%高くなりました。

ご参考

1
0 146
記事 Tomoko Furuzono · 8月 4, 2024 1m read

これは、InterSystems FAQサイトの記事です。

区切り識別子は、区切り文字で囲まれた一意の識別子です。
InterSystems SQL は、その区切り文字として二重引用符 「"」 をサポートしています。
一方、リテラル値を区切る場合は、一重引用符「'」を使用します。
例えば、下記のSQLにおいて、
①は、Nameの値が「AAA」という文字列である、という検索条件と解釈されますが、
②は、Name列 = AAA列、という結合条件と解釈されます。※実際にAAA列が無ければエラーとなります。

select * from Samle.Person
whereName = 'AAA'


select * from Sample.Person
whereName = "AAA"


リテラル値(文字列、数値)を示す区切り文字として二重引用符「"」を使用したい場合は、
下記を実行し、この区切り識別子サポートするためのオプションを無効にします。

0
0 83
記事 Mihoko Iijima · 2月 29, 2024 5m read

これは InterSystems FAQ サイトの記事です。

新しいインデックスを定義した後、インデックスの再構築が完了する前にクエリを実行するとデータが存在しているにもかかわらず「検索結果0件」や検索結果数が徐々に増えるような状況が発生します。

インデックスを永続クラス定義(またはテーブル定義)に追加しコンパイルすることで今まで使用していたクエリ実行経路が削除され、再度同じクエリを実行するタイミングで新しいインデックス定義を含めた実行経路が作成されるためです。(この時にインデックス再構築が完了していないとインデックスデータが存在しない、または不完全であるため0件や徐々に検索結果数が増えるような状況を起こします。)

これを起こさなために、新しいインデックスの再構築が終了するまでクエリオプティマイザにインデックスを使用させないように指定する方法が用意されています。

※ 2024/8/2: 2024.1以降から利用できる方法を追加しました。

2024.1以降

CREATE INDEXのDEFERオプションを使用します(オプションを付けないCREATE INDEX文では、作成時にインデックスの再構築も同時に行われます)。

1
0 319
記事 Megumi Kakechi · 7月 28, 2024 2m read

これは InterSystems FAQ サイトの記事です。
通常SQLCODE -114(一致する行が既に別のユーザにロックされています)のエラーはロックが競合した場合に発生します。

こちらはレコードロック競合があったり、ロック閾値を超える更新を行いテーブルロックに昇格した際に、そのテーブルレコードに対して別のプロセスよりSelectを行い共有ロックを取ろうとして失敗した(ロック待ちがタイムアウトとなった)場合に発生します。

Selectで共有ロックを取る場合というのは、IRIS の ISOLATION LEVEL がREAD COMMITTED(デフォルトはREAD UNCOMMITTED)で、Selectを行った場合です。

例:Sample.Personテーブルにテーブルロックがかかった状態で以下を実行する場合

0
0 157
記事 Megumi Kakechi · 7月 23, 2024 4m read

これは InterSystems FAQ サイトの記事です。
 

JDBC および ODBC 経由でInterSystemsIRISから外部データベースにアクセスしたい場合、SQLゲートウェイを使用しリンクテーブルを作成して接続できます。

2023.1以降のバージョンでは、リンクテーブルに加えて、外部テーブル/FOREIGN TABLE を使用することが可能となりました(2024.1時点で実験的機能)。

外部テーブルというのは、物理的に別の場所に保存されているデータを IRIS SQL に投影する非常に便利な機能です。
外部テーブルを使用する場合は、Java(2023.1の場合は1.8~)を事前にインストールし、JAVA_HOME環境変数を設定するだけで、簡単に接続することが可能です。

※JAVA_HOME環境変数設定例:
 


外部テーブルの使用方法については、以下の記事で紹介しております。
レシピデータセットを外部テーブルで読み込み、組み込みPythonでLLMを使って分析する (Langchain + OpenAI)
 

こちらの記事では、外部テーブルで作成できる2種類のテーブル(「CSVファイル直接接続」と「外部DBへのJDBCゲートウェイ経由での接続」)の簡単なサンプル作成例と、外部テーブルの特徴を紹介しています。
 

0
0 223
記事 Megumi Kakechi · 7月 16, 2024 2m read

これは InterSystems FAQ サイトの記事です。
 

SQLゲートウェイの接続設定は管理ポータルで作成できますが、プログラムでも作成が可能です。

管理ポータル:
[システム管理] > [構成] > [接続性] > [SQLゲートウェイ接続]

こちらのトピックでは、ODBC/JDBCそれぞれの設定をプログラムで行う方法をご紹介します。


--- SQL Gateway for ODBC ----

set gc = ##class(%SQLConnection).%New()
 set gc.Name = "test"set gc.DSN = "IRIS User"set gc.Usr = "_system"set gc.pwd = "SYS"set gc.bUnicodeStream = 1set gc.useCOALESCE = 1write gc.%Save()
 


--- SQL Gateway for JDBC ----

0
0 153
記事 Toshihiko Minamoto · 7月 16, 2024 12m read

Pandas は単に人気のあるソフトウェアライブラリだけではありません。 これは、Python データ分析環境の基礎でもあります。 その単純さとパワーで知られており、データの準備と分析の複雑さをより扱いやすい形態に変換する上で不可欠な多様なデータ構造と関数が備わっています。 これは、主要なデータ管理および分析ソリューションである InterSystems IRIS プラットフォームのフレームワーク内で、主要評価指標(KPI)やレポート作成用の ObjectScript などの特殊な環境に特に関連しています。
 
データの処理と分析の分野において、Pandas はいくつかの理由により際立っています。 この記事では、それらの側面を詳細に探ります。
 

  • データ分析における Pandas の主なメリット:

ここでは、Pandas を使用する様々なメリットについて深く掘り下げます。 直感的な構文、大規模なデータセットの効率的な処理、および異なるデータ形式のシームレスな操作などが含まれます。 Pandas を既存のデータ分析ワークフローに統合する容易さも、生産性と効率を強化する大きな要因です。

  • Pandas による一般的なデータ分析タスクのソリューション:

Pandas には、単純なデータ集計から複雑な変換まで、日常的なデータ分析タスクを処理できる十分な汎用性が備わっています。 こういった一般的な課題の解決に Pandas をどのように使用できるについて、データクリーニング、変換、および探索的データ分析における機能を紹介しながら説明します。 このセクションでは、Pandas によってこれらのタスクがどれほど単純化されるかに関する実用的なデータを提供します。

  • IRIS の ObjectScript KPI で直接 Pandas を使用する:

IRIS プラットフォームで KPI の開発に Pandas と ObjectScript を統合すると、まさに変革がもたらされます。 ここでは、直接 ObjectScript 内で Pandas を使用して KPI 開発プロセスを強化する方法を説明します。 また、Pandas を使ってデータの分析と可視化を行い、それによってより堅牢でインサイトに満ちた KPI を得る実用的な例も探ります。

  •  IRIS 分析プロセスで Pandas を実装する際の推奨事項:

既存の分析プロセスに新しいツールを実装するのは困難な場合があります。 そのため、このセクションでは、Pandas をできる限り円滑に IRIS 分析エコシステムに統合するためにベストプラクティスと推奨事項を紹介します。 セットアップと構成から最適化とベストプラクティスまで、データ分析ワークフローへの Pandas の統合を成功させるための基本的なガイドラインを説明します。
 
Pandas は、Python プログラミング言語による強力なデータ分析ライブラリです。 Pandas でデータ分析を行うことには、以下のようないくつかのメリットがあります。
 

  1. 使いやすさ: Pandas にはデータ操作用の単純で直感的なインターフェースが備わっています。 NumPy ライブラリをベースに構築されており、DataFrames などの高レベルデータ構造を提供するため、表形式データを簡単に操作できます。  
  2. データ構造: Pandas の主なデータ構造は Series と DataFrame です。 Series はラベル付きの一次元配列であるのに対し、DataFrame は 1 セットの Series を表現する 2 次元のテーブルです。 これらのデータ構造を組み合わせることで、データを便利に格納し、操作することができます。  
  3. 欠損データの処理: Pandas には欠損データ(NaN または None)の検出と処理に使用する便利なメソッドが備わっています。 欠損データを削除、入力、または置換するメソッドがいくつか含まれるため、実際のデータの操作が単純化されます。  
  4. データのグループ化と集計: Pandas では、特徴毎のデータのグループ化と各データグループへの集計関数(合計、平均、中央など)の適応を簡単に行えます。  
  5. 強力なインデックス作成機能: Pandas には、データのインデックスを作成するための柔軟なツールが備わっています。 ラベル、数値インデックス、または複数のレベルのインデックス作成を使用できます。 データを効率的に絞り込み、選択、および操作することができます。  
  6. データの読み取りと書き込み: Pandas では、CSV、Excel、SQL、JSON、HTML など、複数のデータ形式がサポートされています。 様々なソースのデータの読み取りやソースへの書き込みのプロセスが容易です。  
  7. 広範な可視化機能: Pandas には、Matplotlib や Seaborn などの可視化ライブラリが統合されているため、特に Embedded Python 経由の統合を通じて DeepSeeWeb を使用することで、グラフの作成やデータの可視化を簡単に行えます。  
  8. 効率的な時間管理: Pandas には、タイムスタンプや期間を操作するための強力なツールなど、時系列の操作に使用できる機能が複数含まれています。  
  9. 広範なデータ操作機能: ライブラリには、データの絞り込み、ソート、および再構成や、テーブルの結合やマージを行うための様々な関数が備わっているため、強力なデータ操作ツールを得られます。  
  10. 優れたパフォーマンス: Pandas は、大量のデータを処理できるように意図的に最適化されています。 Cython と強化されたデータ構造を使用することで、高いパフォーマンスを提供しています。

 
ObjectScript 環境で Pandas の実装例を見てみましょう。 開発環境として VSCode を使用します。 この場合の IDE は、ObjectScript 用のデバッガーとエディターを提供する InterSystems ObjectScript Extension Pack の提供状況に基づいて選択されました。
まずは、KPI クラスを作成しましょう。

  Class BI.KPI.pandasKpi Extends%DeepSee.KPI
{
}


 
次に、KPI のタイプ、名前、および列とフィルターの数を定義する XML ドキュメントを作成する必要があります。
 

XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ]
{
<!-- 'manual' KPI タイプは、ユーザーが定義したクラスメソッドからデータが収集されることを DeepSee に示します-->
 
<kpiname="MembersPandasDemo"sourceType="manual">
 
 <!-- この KPI クエリに必要となる列は 1 つのみです -->
 
<propertycolumnNo="1"name="Members"displayName="Community Members"/>
 
<!-- 最後に、メンバーのフィルターを定義する必要があります -->
 
<filtername="InterSystemsMember"displayName="InterSystems member"sql="SELECT DISTINCT ISCMember from Community.Member"/>
 
 </kpi>
}


 
次のステップは、Python 関数の定義、インポートの記述、および必要な変数の作成です。
 

ClassMethod MembersDF(sqlstring) As%Library.DynamicArray [ Language = python ]
{
            # First of all, we import the most important library in our script: IRIS.
            # IRIS library provides syntax for calling ObjectScript classes.
            # It simplifies Python-ObjectScript integration.
            # With the help of the library we can call any class and class method, and
            # it returns whatever data type we like, and ObjectScript understands it.
            import iris
            # Then, of course, import the pandas itself.
            import pandas as pd
            # Create three empty arrays:
            Id_list = []
            time_list = []
            ics_member = []


 
次のステップ: データベースに対するクエリを定義します。
 

# Define SQL query for fetching data.
# The query can be as simple as possible.
# All the work will be done by pandas:
            query = """
            SELECT
            id as ID, CAST(TO_CHAR(Created, 'YYYYMM') as Int) as MonthYear, ISCMember as ISC
            FROM Community.Member
            order by Created DESC
            """


次に、生成されるデータを配列グループに保存する必要があります。

# Call the class specified for executing SQL statements.
# We use embedded Python library to call the class:
sql_class = iris.sql.prepare(query)
 
# We use it again to call dedicated class methods:
rs = sql_class.execute()
 
# Then we use pandas directly on the result set to make dataFrame:
data = rs.dataframe()


            
We also can pass an argument to filter our data frame.

# フィルターの例
# We take an argument sqlstring which, in this case, contains boolean data.
# With a handy function .loc filtering all the data
sqlstring が False でない場合:
        data = data.loc[data["ISC"] == int(sqlstring)]


 
次に、データをグループ化して、その x 軸を定義する必要があります。
 
 

# Group data by date displayed like MonthYear:
grouped_data = data.groupby(["MonthYear"]).count()

 

残念ながら、直接グループ化されたデータ DataFrame から日付列を取得することはできないため、
代わりに元の DataFrame から日付列を取得して処理します。


 

# Filter out duplicate dates and append them to a list.
# After grouping by MonthYear, pandas automatically filters off duplicate dates.
# We should do the same to match our arrays:
sorted_filtered_dates = [item for item in set(data["MonthYear"])]
# Reverse the dates from left to right:
date = sorted(sorted_filtered_dates, reverse=True)
# Convert dict to a list:
id = grouped_data["ID"].id.tolist()
# Reverse values according to the date array:
id.reverse()
 
# In order to return the appropriate object to ObjectScript so that it understands it,
# we call '%Library.DynamicArray' (it is the closest one to python and an easy-to-use type of array).
# Again, we use IRIS library inside python code:
OBJIDList = iris.cls('%Library.DynamicArray')._New()
OBJtimeList = iris.cls('%Library.DynamicArray')._New()
 
# Append all data to DynamicArray class methods Push()
for i in date:
        OBJtimeList._Push(i)
for i in ID:
        OBJIDList._Push(i)
return OBJIDList, OBJtimeList
}


 
次のステップでは、DeepSee がどのデータを取得するかを理解するように KPI 固有のメソッドを定義します。
 

// メソッドを定義します。 The method must always be %OnLoadKPI(). Otherwise, the system will not recognise it.
 
Method %OnLoadKPI() As%Status
{
 
 //Define string for the filter. Set the default to zero
 set sqlstring = 0
    //Call %filterValues method to fetch any filter data from the widget.
    if$IsObject(..%filterValues) {
        if (..%filterValues.InterSystemsMember'="")
        {
            set sqlstring=..%filterValues.%data("InterSystemsMember")
        }
    }
    //Call pandas function, pass filter value if any, and receive dynamic arrays with data.
    set sqlValue = ..MembersDF(sqlstring)
 
    //Assign each tuple to a variable.
    set idList = sqlValue.GetAt(1)
    set timeList = sqlValue.GetAt(2)
  
    //Calculate size of x-axis. It will be rows for our widget:
    set rowCount = timeList.%Size()
 
    //Since we need only one column, we assign variable to 1:
    set colCount = 1
    set ..%seriesCount=rowCount
  
    //Now, for each row, assign time value and ID value of our members:
    for rows = 1:1:..%seriesCount
    {
        set ..%seriesNames(rows)=timeList.%Get(rows-1)
       
        for col = 1:1:colCount
        {
            set ..%data(rows,"Members")=idList.%Get(rows-1)
        }
    }
    quit$$$OK


この時点で、KPI をコンパイルし、KPI データソースを使ってダッシュボードにウィジェットを作成します。

 

以上です! InterSystems IRIS の ObjectScript アプリケーションで Pandas の統合と使用のプロセスを確認できました。 このプロセスでは、データのフェッチと整形から絞り込みと表示までを 1 つの合理化された関数で行いました。 この実演では、データ分析における Pandas の効率性と力がハイライトされています。 では次に、IRIS 環境内で Pandas を実装する際の実用的な推奨事項を詳しく見て、変換による影響に関するインサイトで締めくくりましょう。
IRIS における実用的な Pandas アプリケーションの推奨事項

  • プロトタイピングから始める:

サンプルのデータセットとユーティリティを使用して Pandas での作業を始めましょう。 この方法によって、制御された使い慣れた環境で Pandas の基本と意味合いを理解できます。 プロトタイピングでは、ライブデータに関連するリスクを伴うことなく、様々な Pandas 関数とメソッドを実験できます。

  • 段階的な実装:

既存のデータプロセスに Pandas を徐々に導入しましょう。 全面的に変更するのではなく、Pandas によってデータ処理と分析が強化または単純化されるエリアを特定します。 データクリーニング集計などの単純なタスクであることも、Pandas の機能を完全に活用できるより複雑な分析であることもあります。

  •  Pandas の使用を最適化する:

大きなデータセットで作業する前に、Pandas コードを最適化しておくことが重要です。 コードの効率によって、処理時間やリソース消費量が大幅に削減されるため、大規模なデータ分析では特に重要です。 ベクトル化操作、適切なデータ型の使用、データ操作でのループの回避といった手法によって、パフォーマンスは大幅に強化されます。


まとめ

InterSystems IRIS プラットフォームの ObjectScript アプリケーションへの Pandas の統合は、データ分析の分野における著しい進歩です。 Pandas によってデータ処理、分析、および可視化に使用できる多数の強力なツールを使用できるようになり、IRIS ユーザーはこれを使用できるようになりました。 この統合は KPI の開発と分析を高速化して単純化するだけでなく、IRIS エコシステム内でのより洗練された高度なデータ分析機能への道も切り開いています。
 
Pandas を使用することで、アナリストと開発者は、その広範な機能を活用してデータからより深い洞察を得ることで、データ分析の新たな地平を探ることができます。 大規模なデータセットを効率的に処理して分析する能力に、魅力的な可視化の作成しやすさを合わせ、ユーザーはより多くの情報に基づいた意思決定を行い、これまで検出が困難であった傾向やパターンを明らかにできるようになります。
 
要約すると、InterSystems IRIS 環境への Pandas の統合は変革的なステップであり、プラットフォームの機能を強化し、増え続ける最新のデータ分析の課題と複雑さに取り組むための拡張されたツールキットをユーザーに提供することができます。

0
0 118
記事 Toshihiko Minamoto · 6月 26, 2024 8m read

近頃、LLM や AI などに関する話題で非常ににぎわっています。 ベクトルデータベースもそれなりに関わっており、IRIS 以外では、世界中で多様なサポートがすでに実現されています。

なぜベクトルなのでしょうか?

  • 類似検索: ベクトルでは、データベース内で最も類似する項目やドキュメントを検索するなど、効率的な類似検索が可能です。 従来のリレーショナルデータベースは完全一致検索向けに設計されているため、画像やテキストの類似検索といったタスクには向いていません。
  • 柔軟性: ベクトル表現には汎用性があり、テキスト(Word2Vec、BERT などの埋め込み経由)や画像(ディープラーニングモデル経由)などの様々なデータタイプから導き出すことができます。
  • クロスモーダル検索: ベクトルでは、様々なデータモダリティでの検索が可能です。 たとえば、画像のベクトル表現を基に、マルチモーダルデータベースで類似する画像や関連するテキストを検索できます。

理由は他にも多数あります。

そこで、この Python コンテストでは、このサポートを実装してみることにしました。 残念ながら時間内に完成させることはできませんでしたが、その理由を以下で説明します。

完全にするには、やらなければならない主な項目がいくつかあります。

  • ベクトル化データを SQL で受け入れて格納する。以下は単純な例です(この例の「3」は次元数であり、フィールドごとに固定されており、そのフィールドのすべてのベクトルにこの正確な次元が必要です)。
    createtable items(embedding vector(3));
    insertinto items (embedding) values ('[1,2,3]');
    insertinto items (embedding) values ('[4,5,6]');
    
  • 類似関数。類似には様々なアルゴリズムがあり、インデックスを使用しない少量のデータでの単純な検索に適しています。
    -- ユークリッド距離select embedding, vector.l2_distance(embedding, '[9,8,7]') distance from items orderby distance;
    -- コサイン類似度select embedding, vector.cosine_distance(embedding, '[9,8,7]') distance from items orderby distance;
    -- 内積select embedding, -vector.inner_product(embedding, '[9,8,7]') distance from items orderby distance;
  • カスタムインデックス。大量のデータでのより高速な検索に役立ちます。インデックスには異なるアルゴリズム、上記の異なる距離関数、およびその他のオプションを使用できます。
    • HNSW
    • 転置ファイルインデックス
  • 検索は作成されたインデックスを使用し、そのアルゴリズムによってリクエストされた情報が検索されます。

ベクトルの挿入

ベクトルは、整数や浮動小数点数のほかに、符号付きや符号なしの数値の配列であることが期待されています。 IRIS では、それを単に $listbuild として格納できます。これには最適な表現があり、すでにサポートされているため、ODBC から論理への変換のみを実装する必要があります。

すると、ODBC/JDBC などの外部ドライバーを使って、または IRIS 内では ObjectScript を使って、プレーンテキストとして値を挿入できます。

  • プレーンな SQL を使用
    insertinto items (embedding) values ('[1,2,3]');
  • ObjectScript を使用
    set rs = ##class(%SQL.Statement).%ExecDirect(, "insert into test.items (embedding) values ('[1,2,3]')")
    

    set rs = ##class(%SQL.Statement).%ExecDirect(, "insert into test.items (embedding) values (?)", $listbuild(2,3,4))

  • または埋め込み SQL を使用
    &sql(insertinto test.items (embedding) values ('[1,2,3]'))
    

    set val = $listbuild(2,3,4) &sql(insertinto test.items (embedding) values (:val))

必ず $lb() として格納され、ODBC でテキスト形式で戻されます。

 
予期しない動作
DBeaver を使ってテストした際に、接続後の最初の行は正しく挿入されても、他の行は検証や変換が行われずにそのまま挿入されているのが判明しました。

その後、JDBC はデフォルトで高速挿入を使用しており、その場合、挿入されたデータを直接 globals に格納することがわかったため、その機能を手動でオフにする必要がありました。

DBeaver では、FeatureOption フィールドの optfastSelect を選択してください。

計算

ベクトルは主に、2 つのベクトルの間の距離の計算をサポートするために必要です。

コンテストにおいては、Embedded Python を使用する必要がありました。問題はここからです。Embedded Python で $lb をどのように操作するのか。%SYS.Class には ToList メソッドがありますが、Python パッケージは iris にビルトインされていないため、ObjectScript のやり方が必要となります。

ClassMethod l2DistancePy(v1 As dc.vector.type, v2 As dc.vector.type) As%Decimal(SCALE=10) [ Language = python, SqlName = l2_distance_py, SqlProc ]
{
    import iris 
    import math
vector_type = iris.cls('dc.vector.type')
v1 = iris.cls('<span class="hljs-built_in">%SYS.Python</span>').ToList(vector_type.Normalize(v1))
v2 = iris.cls('<span class="hljs-built_in">%SYS.Python</span>').ToList(vector_type.Normalize(v2))

<span class="hljs-keyword">return</span> math.sqrt(sum([(val1 - val2) ** <span class="hljs-number">2</span> <span class="hljs-keyword">for</span> val1, val2 in zip(v1, v2)]))

}

まったく正しいようには見えません。 $lb は Python でその場でリストとして、または少なくともビルトイン関数の o_list と from_list として解釈されるのが好ましいと思います。

もう 1 つの問題は、この関数を様々な方法でテストしようとしたときにありました。 Embedded Python で記述された SQL を 使用する SQL を Embedded Python から使用すると、クラッシュします。 そこで、ObjectScript の関数も追加する必要がありました。

ModuleNotFoundError: No module named 'dc'
SQL Function VECTOR.NORM_PY failed with error:  SQLCODE=-400,%msg=ERROR #5002: ObjectScript error: <OBJECT DISPATCH>%0AmBm3l0tudf^%sqlcq.USER.cls37.1 *python object not found

距離を計算するために現在実装されている関数(Python と ObjectScript の両方)

  • ユークリッド距離
    [SQL]_system@localhost:USER> select embedding, vector.l2_distance_py(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+----------------------+
    | embedding | distance             |
    +-----------+----------------------+
    | [4,5,6]   | 5.91607978309961613  |
    | [1,2,3]   | 10.77032961426900748 |
    +-----------+----------------------+
    2 rows in setTime: 0.011s
    [SQL]_system@localhost:USER> select embedding, vector.l2_distance(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+----------------------+
    | embedding | distance             |
    +-----------+----------------------+
    | [4,5,6]   | 5.916079783099616045 |
    | [1,2,3]   | 10.77032961426900807 |
    +-----------+----------------------+
    2 rows in setTime: 0.012s
  • コサイン類似度
    [SQL]_system@localhost:USER> select embedding, vector.cosine_distance(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+---------------------+
    | embedding | distance            |
    +-----------+---------------------+
    | [4,5,6]   | .034536677566264152 |
    | [1,2,3]   | .11734101007866331  |
    +-----------+---------------------+
    2 rows in setTime: 0.034s
    [SQL]_system@localhost:USER> select embedding, vector.cosine_distance_py(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+-----------------------+
    | embedding | distance              |
    +-----------+-----------------------+
    | [4,5,6]   | .03453667756626421781 |
    | [1,2,3]   | .1173410100786632659  |
    +-----------+-----------------------+
    2 rows in setTime: 0.025s
  • 内積
    [SQL]_system@localhost:USER> select embedding, vector.inner_product_py(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+----------+
    | embedding | distance |
    +-----------+----------+
    | [1,2,3]   | 46       |
    | [4,5,6]   | 118      |
    +-----------+----------+
    2 rows in setTime: 0.035s
    [SQL]_system@localhost:USER> select embedding, vector.inner_product(embedding, '[9,8,7]') distance from items orderby distance;
    +-----------+----------+
    | embedding | distance |
    +-----------+----------+
    | [1,2,3]   | 46       |
    | [4,5,6]   | 118      |
    +-----------+----------+
    2 rows in setTime: 0.032s

数学関数(加減乗除)を追加で実装しました。 InterSystems は独自の集計関数の作成をサポートしているため、 すべてのベクトルを合計したり平均を求めることが可能かもしれません。 しかし、残念ながら、InterSystems では同一の名前の使用をサポートしていないため、関数に独自の名前(およびスキーマ)を使用する必要があります。 ただし、集計関数では数値以外の結果はサポートされていません。

2 つのベクトルの合計を返す単純な vector_add 関数

集計として使用すると、0 を示し、期待されるベクトルも同様に表示されます。

インデックスの作成

残念ながら、実装中に直面した障害により、この部分は完成させられませんでした。

  • IRIS のベクトルが $lb に格納されている場合のビルトイン $lb から Python リストへの変換とその逆変換が不足しており、インデックス作成のすべてのロジックが Python で書かれていることが期待されるため、$lb からデータを取得して globals にも設定することが重要です。
  • globals のサポートの欠如
    • IRIS の $Order は方向をサポートしているため、逆方向でも使用可能ですが、Python Embedded での順序の実装にはこれが存在しないため、すべてのキーを読み取って順序を逆にするか、最後をどこかに格納する必要があります。
  • 上記の Python から呼び出される Python の SQL 関数がうまくいかないため、疑問を感じている
  • インデックス作成中、ベクトル間の距離がグラフに格納されることが期待されていたのに、global で浮動小数点数に関するバグが発生した

この作業中に見つかった Embedded Python 関連の課題を 11 件作成しました。ほとんどの時間は問題を解決するための回避策を見つけるのに費されました。 いくつかの問題は、@Guillaume Rongieriris-dollar-list というプロジェクトのお陰でなんとか解決できました。

インストール

いずれにせよ、これは引き続き提供中であり、IPM でインストールし、機能が制限されていても使用できます。

zpm "install vector"

または開発モードでは docker-compose を使用できます。

git clone https://github.com/caretdev/iris-vector.git
cd iris-vector
docker-compose up -d
0
0 173
記事 Tomoko Furuzono · 6月 6, 2024 2m read

これは、InterSystems FAQサイトの記事です。

IRIS/IRIS for Health2024.1以降のバージョンのSQLで、JSON_TABLE関数がサポートされています。
【ドキュメント】JSON_TABLE(SQL)

これを使用することにより、JSON形式データを表形式で取得することが出来ます。
【例】郵便番号情報を外部から取得し、表形式にマッピングする。
(取得データ(JSON))

{
	"message": null,
	"results": [
		{
			"address1": "東京都",
			"address2": "新宿区",
			"address3": "西新宿",
			"kana1": "トウキョウト",
			"kana2": "シンジュクク",
			"kana3": "ニシシンジュク",
			"prefcode": "13",
			"zipcode": "1600023"
		}
	],
	"status": 200
}

(SQL例)
 ※下記の実行には、SSL構成が必要になります。事前に構成を作成して、その構成名を使用してください。

0
0 122
お知らせ Mihoko Iijima · 3月 26, 2024

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

(2024/5/30:6月の日時、ウェビナー内容を更新しました)

InterSystems IRIS、InterSystems IRIS for Healthの新バージョン2024.1がリリースされました。

様々な機能の追加や実験的機能としての追加が行われましたが、その中から以下3種類の内容についてウェビナーを開催します!📣

✅4月23日(火)13時半~14時:IRIS 2024.1の管理用Webサーバ(PWS)廃止に備えて

YouTube公開しました👉https://youtu.be/bVwWZt1oNws?list=PLzSN_5VbNaxCeC_ibw2l-xneMCwCVf-Or

✅5月30日(木)13時半~14時:ベクトル検索機能のご紹介

YouTube公開しました👉https://youtu.be/v0G7K2et_Yk?list=PLzSN_5VbNaxB39_H2QMMEG_EsNEFc0ASz

✅6月25日(火)13時半~14時:FHIR新機能のご紹介~2024.1~

オンデマンド配信はこちら👉https://event.on24.com/wcc/r/4597704/ADA161B6446E6BA01623C875CF596FD0
(資料PDFもオンデマンド配信画面よりダウンロードいただけます)
 

2
0 208
記事 Megumi Kakechi · 5月 24, 2024 4m read

こちら の記事では、LinuxでJDBC接続を行う方法  をご紹介しました。

今回は、SSL/TLS を使用するように InterSystems IRIS スーパーサーバを構成 した IRIS に対して、JDBCで SSL/TLS 接続をする方法をご紹介します。

LinuxでJDBC接続を行う方法 の記事で紹介している手順で、SSL/TLS なしでJDBC接続できる環境を用意していることを前提にご説明します。

手順は以下のようになります。手順の詳細は、この後で説明します。

1.CA証明書を用意します

2.Java キーストアに証明書をインポートします

3.Java ファイルを含むディレクトリに、SSLConfig.properties という名前の構成ファイルを作成ます

4.Java のコードに SSL/TLS の使用を指定する設定を追加します


1.CA証明書を用意します

最初に、CA証明書を用意します。証明書に問題がないか証明書情報を確認します。
※ ***.***.***.*** :接続先IRISサーバのIPアドレス

0
0 437
記事 Megumi Kakechi · 5月 6, 2024 4m read

前回、LinuxでODBC接続を行う方法 をご紹介しました。

今回は、LinuxでJDBC接続を行う方法 をご紹介します。作業は、root ユーザ で行います。

はじめに、Linuxのバージョンを確認します。

$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
:


1. yumパッケージのアップデートを行います

$ su -
Password:
Last login: Tue May  7 01:04:35 UTC 2024 on pts/0
# yum update


2. Java をインストールします

今回は、Adoptium OpenJDK の Version 8 - LTS を使用してテストします。
※ *.tar.gz は、/usr/java 以下にダウンロードします。

#cd /usr/java# ls
OpenJDK8U-jdk_x64_linux_hotspot_8u412b08.tar.gz
# tar zxvf OpenJDK8U-jdk_x64_linux_hotspot_8u412b08.tar.gz
:
# ls
jdk8u412-b08  OpenJDK8U-jdk_x64_linux_hotspot_8u412b08.tar.gz
0
0 1245
記事 Megumi Kakechi · 5月 2, 2024 3m read

こちらの記事では、LinuxでODBC接続の設定を行う方法をご紹介します。


はじめに、Linuxのバージョンを確認します。

$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
:


1. yumパッケージのアップデートを行います

$ sudo yum update


2. unixODBCをインストールします

$ sudo yum install unixODBC

確認します

$which odbcinst
/usr/bin/odbcinst
$which isql
/usr/bin/isql
$ odbcinst -j
unixODBC 2.3.9
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/ec2-user/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8


3. IRISクライアントをインストールします

0
0 831
記事 Megumi Kakechi · 4月 25, 2024 2m read

大きなサイズのデータを持つフィールドに対してインデックスを作成すると、<SUBSCRIPT>エラーとなることがあります。

これは、グローバルの添え字(サブスクリプト)のサイズには制限があり、制限を超えるとエラーとなるためです。

例えば、以下のようなインデックスの場合、

^Sample.PersonI("NameIdx"," xxx...xxx",1)       =       ""

グローバル名+サブスクリプト部(=の左側)が、エンコード文字数で最長 511 文字を超えるとエラーとなります(日本語の場合はもっと小さな文字数です)。

※ご参考:グローバル参照の最大長


大きいデータを持つカラムに対してインデックスを設定したい場合の回避策としては、こちらの ドキュメント にありますように
「該当のプロパティのインデックス照合文字列を任意の文字数(例:128文字)に制限した照合を定義」
する方法があります。


具体的には、以下の2つの方法になります。
※クラス定義の変更/保存/コンパイル+インデックスの再構築が必要です。

1. プロパティ定義で対応する:

0
0 136
記事 Toshihiko Minamoto · 4月 18, 2024 13m read

我々には、Redditユーザーが書いた、おいしいレシピデータセット がありますが, 情報のほとんどは投稿されたタイトルや説明といったフリーテキストです。埋め込みPythonLangchainフレームワークにあるOpenAIの大規模言語モデルの機能を使い、このデータセットを簡単にロードし、特徴を抽出、分析する方法を紹介しましょう。

データセットのロード

まず最初に、データセットをロードするかデータセットに接続する必要があります。

これを実現するにはさまざまな方法があります。たとえばCSVレコードマッパーを相互運用性プロダクションで使用したり csvgenのようなすばらしい OpenExchange アプリケーションを使用することもできます。

今回、外部テーブルを使用します。これは物理的に別の場所に保存されているデータをIRIS SQLで統合する非常に便利な機能です。

まずは外部サーバ(Foreign Server)を作成します。

CREATE FOREIGN SERVER dataset FOREIGN DATA WRAPPER CSV HOST '/app/data/'

その上でCSVファイルに接続する外部テーブルを作成します。

CREATE FOREIGN TABLE dataset.Recipes (
  CREATEDDATE DATE,
  NUMCOMMENTS INTEGER,
  TITLE VARCHAR,
  USERNAME VARCHAR,
  COMMENT VARCHAR,
  NUMCHAR INTEGER
) SERVER dataset FILE 'Recipes.csv' USING
{
  "from": {
    "file": {
       "skip": 1
    }
  }
}

以上です。すぐに「dataset.Recipes」にSQLクエリを実行できます。 image

## どんなデータが必要?

データセットは興味深く、直ぐに処理したいと思うのですが、調理のレシピを決めたいのであれば、分析に使える情報がもう少し必要です。 2つの永続化クラス(テーブル)を使用します。

  • yummy.data.Recipe抽出分析したいレシピのタイトルと説明、他のプロパティが入ったクラス (例: スコア、難易度、材料、調理タイプ、準備時間)
  • yummy.data.RecipeHistory レシピのログを取るためのシンプルなクラス

これで 「yummy.data*」 テーブルにデータセットの内容をロードすることができます。

do ##class(yummy.Utils).LoadDataset()

一見良さそうに見えますが、スコア、難易度、材料、準備時間、調理時間フィールドのデータをどのように生成するのかを見つける必要があります。

## レシピの分析 各レシピのタイトルと説明を処理します

  • 難易度, 材料, 調理タイプなどの抽出
  • 何を作りたいか決められるよう、基準に基づいて独自のスコアを構築

以下を使用します

  • より多くの分析を構築したい場合に再利用できる一般的な分析構造

LLM(大規模言語モデル)は自然言語を処理するための本当に素晴らしいツールです。

LangChainはPythonで動くようになっているので、Embedded Pythonを使ってInterSystems IRISで直接使うことができます。 LangChain is ready to work in Python, so we can use it directly in InterSystems IRIS using Embedded Python.

完全な SimpleOpenAI クラスは以下のようになります。

/// レシピ向けのシンプルな OpenAI 分析
Class yummy.analysis.SimpleOpenAI Extends Analysis
{

Property CuisineType As %String;

Property PreparationTime As %Integer;

Property Difficulty As %String;

Property Ingredients As %String;

/// 実行
/// ターミナルから実行できます。
/// set a = ##class(yummy.analysis.SimpleOpenAI).%New(##class(yummy.data.Recipe).%OpenId(8))
/// do a.Run()
/// zwrite a
Method Run()
{
    try {
        do ..RunPythonAnalysis()

        set reasons = ""

        // 好きな調理タイプ
        if "spanish,french,portuguese,italian,korean,japanese"[..CuisineType {
            set ..Score = ..Score + 2
            set reasons = reasons_$lb("It seems to be a "_..CuisineType_" recipe!")
        }

        // 丸一日調理に費やしたくない :)
        if (+..PreparationTime < 120) {
            set ..Score = ..Score + 1
            set reasons = reasons_$lb("You don't need too much time to prepare it") 
        }
        
        // 好きな材料ボーナス
        set favIngredients = $listbuild("kimchi", "truffle", "squid")
        for i=1:1:$listlength(favIngredients) {
            set favIngred = $listget(favIngredients, i)
            if ..Ingredients[favIngred {
                set ..Score = ..Score + 1
                set reasons = reasons_$lb("Favourite ingredient found: "_favIngred)
            }
        }

        set ..Reason = $listtostring(reasons, ". ")

    } catch ex {
        throw ex
    }
}

/// 分析結果でレシピを更新する
Method UpdateRecipe()
{
    try {
        // 親クラスの処理を先に呼び出す
        do ##super()

        // 個別のOpenAI 解析結果を追加
        set ..Recipe.Ingredients = ..Ingredients
        set ..Recipe.PreparationTime = ..PreparationTime
        set ..Recipe.Difficulty = ..Difficulty
        set ..Recipe.CuisineType = ..CuisineType

    } catch ex {
        throw ex
    }
}

/// 埋め込み Python + Langchain で分析を実行
/// do ##class(yummy.analysis.SimpleOpenAI).%New(##class(yummy.data.Recipe).%OpenId(8)).RunPythonAnalysis(1)
Method RunPythonAnalysis(debug As %Boolean = 0) [ Language = python ]
{
    # load OpenAI APIKEY from env
    import os
    from dotenv import load_dotenv, find_dotenv
    _ = load_dotenv('/app/.env')

    # account for deprecation of LLM model
    import datetime
    current_date = datetime.datetime.now().date()
    # date after which the model should be set to "gpt-3.5-turbo"
    target_date = datetime.date(2024, 6, 12)
    # set the model depending on the current date
    if current_date > target_date:
        llm_model = "gpt-3.5-turbo"
    else:
        llm_model = "gpt-3.5-turbo-0301"

    from langchain.chat_models import ChatOpenAI
    from langchain.prompts import ChatPromptTemplate
    from langchain.chains import LLMChain

    from langchain.output_parsers import ResponseSchema
    from langchain.output_parsers import StructuredOutputParser

    # init llm model
    llm = ChatOpenAI(temperature=0.0, model=llm_model)

    # prepare the responses we need
    cuisine_type_schema = ResponseSchema(
        name="cuisine_type",
        description="What is the cuisine type for the recipe? \
                     Answer in 1 word max in lowercase"
    )
    preparation_time_schema = ResponseSchema(
        name="preparation_time",
        description="How much time in minutes do I need to prepare the recipe?\
                     Anwer with an integer number, or null if unknown",
        type="integer",
    )
    difficulty_schema = ResponseSchema(
        name="difficulty",
        description="How difficult is this recipe?\
                     Answer with one of these values: easy, normal, hard, very-hard"
    )
    ingredients_schema = ResponseSchema(
        name="ingredients",
        description="Give me a comma separated list of ingredients in lowercase or empty if unknown"
    )
    response_schemas = [cuisine_type_schema, preparation_time_schema, difficulty_schema, ingredients_schema]

    # get format instructions from responses
    output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
    format_instructions = output_parser.get_format_instructions()
    
    analysis_template = """\
    Interprete and evaluate a recipe which title is: {title}
    and the description is: {description}
    
    {format_instructions}
    """
    prompt = ChatPromptTemplate.from_template(template=analysis_template)

    messages = prompt.format_messages(title=self.Recipe.Title, description=self.Recipe.Description, format_instructions=format_instructions)
    response = llm(messages)

    if debug:
        print("======ACTUAL PROMPT")
        print(messages[0].content)
        print("======RESPONSE")
        print(response.content)

    # populate analysis with results
    output_dict = output_parser.parse(response.content)
    self.CuisineType = output_dict['cuisine_type']
    self.Difficulty = output_dict['difficulty']
    self.Ingredients = output_dict['ingredients']
    if type(output_dict['preparation_time']) == int:
        self.PreparationTime = output_dict['preparation_time']

    return 1
}

}

「RunPythonAnalysis」メソッドがOpenAIが詰め込むところです :)  ターミナルから直接実行してレシピを受け取れます。

do ##class(yummy.analysis.SimpleOpenAI).%New(##class(yummy.data.Recipe).%OpenId(12)).RunPythonAnalysis(1)

以下のような出力を受け取れます。

USER>do ##class(yummy.analysis.SimpleOpenAI).%New(##class(yummy.data.Recipe).%OpenId(12)).RunPythonAnalysis(1)
======実際の課題
                    レシピタイトルを解釈、評価: 巻きずし - アラスカロール
                    説明: 寿司がたべたいのに巻きすがない? 代わりに簡単なバージョンを試してみてください。超簡単なのに、同じようにおいしい!
[Video Recipe](https://www.youtube.com/watch?v=1LJPS1lOHSM)
# 材料
提供量:  \~サンドイッチ5枚分
* 米1カップ
* 水 3/4 カップ + 大さじ 2 1/2
* 昆布 小口切り 1枚
* 米酢 大さじ2
* さとう 大さじ1
* 塩 小さじ1
* アボカド 2個
* カニカマ 6個
* 和風マヨ 大さじ2
* サーモン 1/2 ポンド  
# レシピ     
* 酢飯1合をボウルに入れ、2回以上、または水が透明になるまで米を洗う。炊飯器に米を移し、昆布の小口切り1枚と水3/4カップ+大さじ2と1/2杯を加える。炊飯器の指示に従って炊く。
* 米酢大さじ2、砂糖大さじ1、塩小さじ1を中くらいのボウルに入れる。全体がよく混ざるまで混ぜる。
* 炊き上がったら昆布を取り除き、すぐに酢を入れた中ボウルに米をすべてすくい入れ、飯ベラを使ってよく混ぜる。米をつぶさないように、切るように混ぜること。炊きあがったら、キッチンタオルをかけて室温まで冷ます。
* アボカド1個の上部を切り、アボカドの中央に切り込みを入れ、ナイフに沿って回転させる。次にアボカドを半分ずつ取り、ひねる。その後、ピットのある側を取り、慎重にピットに切り込みを入れ、ひねって取り除く。その後、手で皮をむく。この手順をもう片方のアボカドでも繰り返す。作業スペースを確保するため、作業台を片付けるのを忘れずに。次に、アボカドを下向きに置き、薄くスライスする。スライスしたら、ゆっくりと広げていく。それが終わったら、脇に置いておく。
* カニカマから包みをはずす。カニカマを縦にむいていく。すべてのカニカマを剥いたら、横に回転させながら細かく刻み、和風マヨ(大さじ2)とともにボウルに入れ、全体がよく混ざるまで混ぜる。
* 鋭利なナイフを斜めに入れ、木目に逆らって薄くスライスする。切り口の厚さは好みによる。ただ、すべてのピースが同じような厚さになるようにする。
* 海苔巻きラップを手に取る。キッチンバサミを使い、海苔巻きラップの半分の位置から切り始め、ラップの中心を少し過ぎるまで切る。ラップを垂直に回転させ、作り始める。すし飯を握るために、手に水をつけておく。酢飯を手に取り、海苔巻きの左上の四辺に広げる。次に、右上にサーモンを2切れ並べる。右下にアボカドを2切れのせる。最後に左下にカニサラダを小さじ2杯ほどのせる。次に、右上の四つ角を右下の四つ角に折り込み、さらに左下の四つ角に折り込む。最後に、左上の四つ角をサンドイッチの残りの部分に折り込む。その後、ラップを上に置き、半分に切って、生姜とわさびを2、3枚添えれば出来上がり。
                    
                    出力は、先頭と末尾の"``json "と"``"を含む、以下のスキーマでフォーマットされたマークダウンのコードスニペットでなければなりません:
json
{
        "cuisine_type": string  // レシピの調理タイプは?                                  小文字の1単語で回答
        "preparation_time": integer  // レシピの準備に必要な時間(分)は? 整数で回答(不明な場合はnull)
        "difficulty": string  // レシピの難易度は?                               「容易」「標準」「難しい」「とても難しい」のうちから1つを回答
        "ingredients": string  // 小文字のカンマ区切りの材料リスト、不明な場合は空
}

                    
======応答
json
{
        "cuisine_type": "japanese",
        "preparation_time": 30,
        "difficulty": "easy",
        "ingredients": "sushi rice, water, konbu, rice vinegar, sugar, salt, avocado, imitation crab sticks, japanese mayo, salmon"
}

良さそうです。OpenAIのプロンプトは有用な情報を返してくれるようです。ターミナルから分析クラス全体を実行してみましょう:

set a = ##class(yummy.analysis.SimpleOpenAI).%New(##class(yummy.data.Recipe).%OpenId(12))
do a.Run()
zwrite a
USER>zwrite a
a=37@yummy.analysis.SimpleOpenAI  ; <OREF>
+----------------- general information ---------------
|      oref value: 37
|      class name: yummy.analysis.SimpleOpenAI
| reference count: 2
+----------------- attribute values ------------------
|        CuisineType = "japanese"
|         Difficulty = "easy"
|        Ingredients = "sushi rice, water, konbu, rice vinegar, sugar, salt, avocado, imitation crab sticks, japanese mayo, salmon"
|    PreparationTime = 30
|             Reason = "It seems to be a japanese recipe!. You don't need too much time to prepare it"
|              Score = 3
+----------------- swizzled references ---------------
|           i%Recipe = ""
|           r%Recipe = "30@yummy.data.Recipe"
+-----------------------------------------------------

## 全レシピを解析する!

当然、読み込んだすべてのレシピで分析を実行したいでしょう。 この方法でレシピ ID の範囲を分析することができます

USER>do ##class(yummy.Utils).AnalyzeRange(1,10)
> Recipe 1 (1.755185s)
> Recipe 2 (2.559526s)
> Recipe 3 (1.556895s)
> Recipe 4 (1.720246s)
> Recipe 5 (1.689123s)
> Recipe 6 (2.404745s)
> Recipe 7 (1.538208s)
> Recipe 8 (1.33001s)
> Recipe 9 (1.49972s)
> Recipe 10 (1.425612s)

その後、レシピテーブルを再度表示させ、結果をチェックします。

select * from yummy_data.Recipe

image

どんぐりカボチャのピザか、豚肉入り韓国風豆腐キムチを試してみます:) いずれにせよ、家で再確認する必要がありますね :)

最後に

サンプルソースは全て https://github.com/isc-afuentes/recipe-inspector にあります。

この簡単な例で、InterSystems IRIS で LLM テクニックを使用して機能を追加したり、データの一部を分析する方法を学びました。

これを起点に以下のことが考えられます

  • InterSystems BIを使い、キューブやダッシュボードでデータの検索やナビゲートをおこなう。
  • Webアプリを作成し、UIを提供する(例:Angular)RESTForms2のようなパッケージを活用することで、永続クラスへのREST APIを自動的に生成することができます。 *レシピが好きか嫌いかを保存し、新しいレシピが好きかどうかを判断するのはいかがでしょうか。IntegratedMLアプローチ、あるいはLLMアプローチでいくつかの例データを提供し、RAG(Retrieval Augmented Generation)ユースケースを構築してみるのも良いでしょう。

他にどんなことが試せそうでしょうか?ご意見をお聞かせください!

0
0 458
記事 Minoru Horita · 4月 4, 2024 6m read

みなさんこんにちは! 今回は、IRIS 2024.1で実験的機能として実装されたVector Search (ベクトル検索)について紹介します。ベクトル検索は、先日リリースされたIRIS 2024.1の早期アクセスプログラム(EAP)で使用できます。IRIS 2024.1については、こちらの記事をご覧ください。

ベクトル検索でどんなことができるの?

ChatGPTをきっかけに、大規模言語モデル(LLM)や生成AIに興味を持たれている方が増えていると思います。開発者の方々の中には、中はどうなっているのか気になっている方も多いのではないでしょうか。実は、LLMや生成AIの仕組みを理解したいと思えば、ベクトルの理解は不可欠な要素となります。

ベクトルとは?

ベクトルは、高校の数学で習う「あの」ベクトルのことです。が、今回は、複数の数値をまとめて扱うデータ型であるという理解で十分です。例えば、

( 1.2, -4.5 )

という感じです。この例は、1.2と-4.5という2つの数値をまとめており、数値の個数(ここでは2)のことを次元数と言います。我々の生きている場所を3次元空間と呼ぶことがありますが、これは、3つの数値で場所が特定できることを表しています(例えば、緯度、経度、標高の3つで地球上の位置を完全に特定できます)。

ベクトルをどのように使うのか?

1
1 713
記事 Megumi Kakechi · 4月 2, 2024 3m read

これは InterSystems FAQ サイトの記事です。

Caché 2016.2以降(IRISはすべてのバージョン)で、クエリプランの凍結機能 が実装されました。
この機能により、メジャーバージョンのアップグレードを行った場合、既存のクエリプランは自動的に凍結(※)されます。
2023.1以降のバージョンより、アダプティブモードが無効の場合のみ、クエリプランが自動的に凍結されます。有効の場合は、既存のクエリプランは無効になり、新しいシステムでクエリの最初の実行時に新しい最適化されたクエリプランを生成します。既定は有効です。

こちらのトピックでは、
「新しいバージョンにしたのに、一部のクエリで思うようなパフォーマンスが出ない」
「凍結プランが使用されている場合、新しいプランでパフォーマンスがどのくらいでるのかを知りたい」
という場合の確認手順について、ご説明します。
 

%NOFPLANキーワードで新しいプランを試してみる

Frozen Plan (古いバージョンと同じプラン)を使用していて思ったようなパフォーマンスが出ない場合、凍結を解除して新しいプランを試すことが可能です。
新しいプランを試したい場合は、%NOFPLANキーワードをつけてクエリを実行します。
%NOFPLANを付けた方がパフォーマンスが良ければ、プラン凍結を解除して新しいプランで実行するようにします。

0
0 93
記事 Toshihiko Minamoto · 3月 28, 2024 12m read

ローコードへの挑戦

こんな状況を思い浮かべてください。「ウィジェットダイレクト」というウィジェットとウィジェットアクセサリーを販売する一流のネットショップで楽しく勤務しています。先日、上司から一部の顧客がウィジェット商品にあまり満足していないという残念な話を聞き、苦情を追跡するヘルプデスクアプリケーションが必要となりました。さらに面白いことに、上司はコードのフットプリントを最小限に抑えることを希望しており、InterSystems IRIS を使って 150 行未満のコードでアプリケーションを提供するという課題をあなたに与えました。これは実際に可能なのでしょうか?

免責事項: この記事は、非常に基本的なアプリケーションの構築を記すものであり、簡潔さを維持するために、セキュリティやエラー処理などの重要な部分は省略されています。このアプリケーションは参考としてのみ使用し、本番アプリケーションには使用しないようにしてください。この記事ではデータプラットフォームとして IRIS 2023.1 を使用していますが、それ以前のバージョンでは記載されているすべての機能が提供されているとは限りません。

ステップ 1 - データモデルの定義

クリーンなネームスペースを新規に定義することから始めましょう。CODE と DATA データベースを使用します。 すべてを 1 つのデータベースで賄うことはできますが、分割してデータのリフレッシュを実行できるようにすると便利です。

このヘルプデスクシステムには 3 つの基本クラスが必要です。スタッフアドバイザーユーザーアカウント(UserAccount) と顧客連絡先ユーザーアカウント(UserAccount)間のやり取りを文書化するアクション(Actions)を含められる Ticket オブジェクトです。

19 行のコードで完全なデータモデルができました!2 つのクラスはデータベースに保存できるように Persistent(永続)に設定し、%JSON.Adapter を継承しています。この継承によって、JSON フォーマットでのオブジェクトのインポートとエクスポートを非常に簡単に行うことができます。テストとして、最初のユーザーをターミナルにセットアップし、保存してから JSONExport が正しく動作することを確認します。

すべてうまくいったようです。上司から、スタッフと顧客のリストが含まれる csv ファイルを渡されました。これを解析して読み込むコードを書くことは可能ですが、簡単に行う方法はないものでしょうか?

ステップ 2 - データの読み込み

InterSystems IRIS には、CSV ファイルから簡単にデータを読み込み、ヘッダーの解析やフィールド名の変更のオプションも使用できる SQL のLOAD DATA ステートメントが備わっています。使い方も単純です。では、それを使用してユーザーテーブルを読み込んでみましょう。

ヘッダーラベルを使ってこのデータを抽出し、データベースに読み込みます。

1 つのコマンドで全 300 行のデータがインポートされました。この 4 行のコードを加えると、合計 23 行のコードが記述したことになります。これらのレコードが正しいことを、基本的な SQL の SELECT を使って素早く確認してみましょう。

最初のデータを得られました。では、フロントエンドを接続できる基本的な API を作成しましょう。この API は、JSON を送受信する REST サービスとして作成します。

ステップ 3 - REST API の作成

InterSystems IRIS には、%CSP.REST クラスの継承を通じてネイティブの RESTサポートが備わっています。そこで、REST.Dispatch クラスを作成して %CSP.REST を継承することにします。このクラスは、URL と動詞をメソッドにマッピングする XData UrlMap と、これらの URL から呼び出されるメソッドの 2 つのセクションで構成されます。

ここで作成する実用最低限のツールには、スタッフまたは顧客のユーザーリストの取得、発行された最近のチケットの取得、ID 番号による単一のチケットの取得、および新しいチケットの作成の 4 つの演算が必要です。ここで使用する動詞を定義してからメソッドを定義します。

GetUserList は、直接 JSON にデータを出力する基本的な埋め込み SQL カーソルです。その後で、ネイティブの JSON 機能を使ってこれを解析し、JSON 配列にプッシュして、レスポンス本文として送信することができます。URL から直接クエリにスタッフ変数を渡して、データのコンテキストを変更します。

TicketSummary はほぼ同じですが、クエリは TICKET テーブルにアクセスします。

TicketSummary は最もシンプルなサービスです。ID でオブジェクトを開き、組み込みの %JSONExport を出力に書き込みます。オブジェクトが読み込みに失敗する場合、エラーパケットを出力します。

最後に、UploadTicket は最も複雑なメソッドです。 リクエストオブジェクトからペイロードを読み取り、JSON に解析してから %JSONImport を使って Ticket の新しいインスタンスに適用します。また、入力を待つ代わりに現在の時間から OpenDate と OpenTime も設定します。正しく保存できたら、オブジェクトの JSON 表現を呼び出すか、読み込み失敗する場合はエラーを返します。

このサービスにより、さらに 60 行のコードが全体に追加されました。これで、このアプリケーションの合計コード行数は、89 行になりました。

次は、セキュリティ > アプリケーションに Web アプリケーションを作成する必要があります。これには REST タイプのアプリケーションに設定し、クラス名を今作成したディスパッチクラスとして設定する必要があります(このアプリケーションがコードとデータにアクセスできるように適切なセキュリティロールを付与する必要があることに注意してください)。保存すると、REST サービスを定義した URL から呼び出せるようになります。

UserList を呼び出して確認してみましょう。

これで、データを作成する準備ができました。REST クライアントを使用して、ペイロードをチケット作成サービスに送信してみましょう。Keyword、Description、Advisor、および Contact を提供すると、作成したチケットの JSON が OpenDate と TicketId と共に返されます。

これで実用最低限のツールが完成しました。任意のフロントエンドフォームビルダーを使用して、REST サービス経由でチケット情報を送受信できるようになりました。

ステップ 4 - 相互運用性の要件

たった 89 行のコードで基本的なチケット管理アプリケーションが完成しました。上司も絶対に驚いたのでは?確かにそうですが、上司から悪い知らせを受けました。要件を逃しているというのです。ウィジェットダイレクトにはフランス語圏での特別な契約があり、フランス語によるチケットはすべて初回レビューを行う Mme Bettie Francis(ベティー・フランシス)を通過しなければならないのです。幸いにも、Robert Luman の Python 自然言語サポートに関する優れた記事を読み、テキストサンプルを受け入れて言語を識別できる REST サービスを作成したことのある同僚がいました。InterSystems IRIS 相互運用性を使用してこのサービスを呼び出し、テキストがフランス語であればアドバイザーを自動的にフランシスさんに更新するようにすることはできるでしょうか?

まずは、リクエストを送受信できるように、メッセージクラスを作成することから始めましょう。チケット ID とサンプルテキストを格納するリクエストと、言語コードと説明を返すレスポンスが必要です。 それぞれ Ens.Request と Ens.Response を継承します。

さて、さらに 6 行が追加され、合計 95 行のコードとなりました。次に演算を作成する必要があります。同僚のサービスにリクエストを送信して回答を取得する演算です。Outbount Operation を Server と URL のプロパティで定義し、これらを SETTINGS パラメーターに含めてユーザー構成に公開します。こうすることで、サーバーのパスが変更した場合に簡単にリクエストを更新できます。HTTPRequest をセットアップするヘルパーメソッドを作成してから、それを使用してサービスを呼び出し、レスポンスを作成します。

27 行のコードが追加され 100 行を超え、合計 122 行となりました。次に、このクラスを Ensemble 本番環境内にセットアップする必要があります。相互運用性の本番構成に移動し、「演算」ヘッダーの下にある「追加」を押します。クラス名と表示名で演算をセットアップしましょう。

次に、それをクリックして設定を開き、サーバー名と URL を入力して演算を有効にします。

次に、チケット ID を取り、入力されたユーザーアカウント ID をアドバイザーに設定する 2 つ目の演算が必要です。メッセージと演算クラスが必要ですが、この場合レスポンスは返さず、演算はフィードバックなしでタスクを実行します。

さらに 12 行が追加され、合計 134 行になりました。言語サービスを追加した方法でこの演算を本番環境に追加しますが、この場合、構成を設定する必要はありません。

次に、サービスを呼び出し、レスポンスを評価し、オプションとしてフランス語アドバイザーの演算を呼び出すルーターが必要です。「相互運用性」>「ビルド」>「ビジネスプロセス」に移動し、ビジュアルルールビルダーを開きます。リクエストとレスポンスのコンテキストを設定してから、呼び出しの項目を追加します。作成したメッセージクラスに入力と出力を設定したら、リクエストビルダーを使って入力をマッピングします。「非同期」フラグのチェックがオフになっていることを確認してください。レスポンスを待ってから処理を進めるためです。

次に「If」項目を追加して、返される言語コードを評価します。「fr」であれば、FrenchAdvisor 演算を呼び出すようにします。

フランシスさんのユーザー ID は 11 であるため、AdvisorUpdate メッセージを FrenchAdvisor サービスに供給するように呼び出しオブジェクトを設定し、ビルダーを使って、TicketID と固定値 11 を Advisor パラメーターに渡します。

「プロセス」ヘッダーの下にある「追加」をクリックし、クラスを選択して表示名「FrenchRouter」を指定したら、本番にこれを追加します。

これでルーティングが設定されました。 後は、新しいチケットをスキャンして、ルーターでの処理に送信するサービスが必要です。SQL アダプターに従ってサービスクラスを定義します(さらに 8 行のコードが追加されます)。

次に、演算オブジェクトとプロセスオブジェクトと同じようにして、これを本番に追加します。SQL アダプターのセットアップが必要です。ODBC DSN を介してローカルデータベースへの接続情報を提供し、CallInterval 設定に設定されたタイマーでチケットをクエリするためにサービスが使用する基本的な SQL クエリを指定します。このクエリはクエリに一意のキーを定義し、送信済みのレコードが再送信されないようにする「キーフィールド名」設定と組み合わされます。

この設定により、新しいチケットをスキャンし、テキストを外部サービスに渡して言語を解析し、オプションとしてこのレスポンスに応じてアドバイザーをリセットする処理が完成しました。では試してみましょう!英語のリクエストを送信してみましょう。これは TicketID 70 で返されます。数秒待ってから、GetTicket REST サービスを介してこのレコードにアクセスすると、アドバイザーは元のリクエストから変わっていないのがわかります。

では、フランス語のテキストを使ってみましょう。

チケット ID 71 をリクエストすると、期待どおり、アドバイザーはフランシスさんに変更されています! これは相互運用性内で、ビジュアルトレースでメッセージの場所を探し、演算が期待どおりに呼び出されたことを確認すればわかります。

この時点でのコード行数は 142 行であり、データを永続させ、LOAD DATA でデータを読み込み、データの表示と編集を行える基本的な REST API と、外部 REST サービスへの呼び出しに基づいて意思決定サポートを提供する高度な統合エンジンを備えた InterSystems IRIS アプリケーションが出来上がりました。これ以上のことを求める人はきっといないですよね?

ステップ 5 - 更なる要求: 分析

このアプリケーションは大成功をおさめ、データもさらに増えています。この貴重データを利用するには専門知識が必要であり、ウィジェットダイレクトの経営陣はインサイトを希望しています。データへの対話型アクセスを提供できるでしょうか?

InterSystems IRIS Analytics を使用すると、高度なデータ操作ツールを素早く簡単に利用できます。まずは、内部 Web アプリケーションに対し、Analytics サポートを有効化する必要があります。

これにより、ネームスペースの分析セクションを使用できるようになります。「分析」>「アーキテクト」を開きましょう。「新規」を選択してフォームに入力し、Ticket クラスの分析キューブを作成します。

次に、ビジュアルビルダーを使って、次元と、基本的なドリルダウンのリストをセットアップします。このビューはドラッグアンドドロップで操作します。リストは、ユーザーがデータポイントを調査する際に表示されるコンテンツをカスタマイズするためのビジュアルエディターででも作成できます。

基本のセットアップが完了したら、キューブを保存、コンパイル、ビルドできます。これによりすべてのインデックスがセットアップされ、アナライザーでの分析用にキューブが有効化されます。アナライザーを開いてデータを操作してみましょう。例では、アドバイザーを年と四半期の階層に対して比較されており、保存されている連絡先でフィルターされています。セルをクリックすると双眼鏡のアイコンが表示されるため、それをクリックすると作成したドリルダウンリストが呼び出されます。それを使用してさらに分析し、エクスポートすることができます。

まとめ

たった 142 行のコードで、基本的ではありながらも機能性のあるモダンなバックエンドアプリケーションを作成しました。アプリケーション間の通信と高度な分析が可能なツールもサポートされています。これは過剰に単純化した実装であり、IRIS でデータベースアプリケーションを構築するために必要最低限の例としてのみ使用してください。この記事の冒頭で述べたように、このコードは本番対応かつ実用できるものではありません。開発者は InterSystems IRIS ドキュメントとベストプラクティスを参考にしながら、自分のコードを堅牢かつ安全で、スケーラブルにしてください(このコードベースはどれにも該当しません)。それでは、コーディングをお楽しみください!

1
0 131
記事 Megumi Kakechi · 3月 24, 2024 2m read

これは InterSystems FAQ サイトの記事です。

クエリパフォーマンスを左右するクエリプランは、テーブルチューニングを行った結果の統計情報を元に生成されます。

ある環境で期待したプランになったけれど、他の環境では意図したプランにならない場合、(期待したプランとなる)既存環境からテーブル統計情報をエクスポートして別の環境にインポートし、同じ統計情報をもとにしたクエリプランで実行することができます。
 

既存環境からテーブル統計情報をエクスポートして、対象環境にインポートする方法

新規環境にてテーブルチューニングをしても思うようなパフォーマンスが出ない場合に、パフォーマンスの出ていたテスト環境と、もう一つの別の環境で同じクエリプランでの実行を試してみたい場合があるかと思います。
そんな時は、テーブル統計情報である選択性(Selectivity)とデータ数(ExtentSize)情報等をエクスポートして、対象環境にインポートする方法が使用できます。
もちろん、データの偏りによってクエリオプティマイザが適切だと判断して作成したプランが最適だと考えられますが、どうしても思うようなパフォーマンスが出ない場合に、原因調査も含めてこちらの方法をお試しください。

以下のように統計情報をエクスポート/インポートすることで、同じテーブル統計情報=同じクエリプラン で実行することが可能となります。

0
0 250
記事 Megumi Kakechi · 3月 11, 2024 2m read

これは InterSystems FAQ サイトの記事です。

SQLのINSERT/UPDATE/DELETE文で大量のデータを更新する際に、高速化する方法をご紹介します。
以下の2つの手順を実行することで、更新処理のパフォーマンスを向上させることが可能です。

1.INSERT/UPDATE/DELETE時にインデックスを作成せず、あとでまとめて作成する

2.INSERT/UPDATE/DELETE時にジャーナルをOFFにする

1は、%NOINDEX キーワードを指定してインデックスの生成を後でまとめて行うことで、インデックスの構築を抑制しパフォーマンスを向上させる方法です。

クエリ実行例は、以下のようになります。

例:
UPDATE %NOINDEX tablename …
INSERT %NOINDEX INTO tablename …
DELETE %NOINDEX FROM tablename ...


更新後、あとでまとめてインデックスを再構築する場合は管理ポータルで行う方法と、コマンドで行う方法の2種類があります。

◆ 管理ポータルの場合...

[システムエクスプローラ] > [SQL]
 (ネームスペース指定&テーブルを選択して) アクション - テーブルのインデックスを再構築...

◆ コマンドの場合...

0
0 863
記事 Megumi Kakechi · 3月 3, 2024 2m read

これは InterSystems FAQ サイトの記事です。

ユーザに権限を与えたい場合、「GRANT」コマンドや「GrantPrivilegeメソッド」を使用しますが、ロールに対しても権限を与えることができます。

例えば、特定スキーマにのみ何でもできるロールを作成し、それを特定のユーザに割り当てるようなことが可能となります。

こちらの記事では、その方法をご紹介します。

(1) GrantPrivilegeメソッドを使用して「スキーマXXX に何でもできるロール」を作成し、
(2) 該当ユーザに (1) のロールを割り当てる


★GRANT文を使う場合

GRANT <priv> ONSCHEMA <your schema> TO <role>


例:ロール testRole に、スキーマ XXX に対する、挿入/更新/参照/削除 の権限を付与します。

GRANTInsert,Update,Select,DeleteONSCHEMA XXX TO testRole
※その他、Alter, References, Execute, Use などの指定も可能です。

こちらは、まだ存在しないスキーマに対しても実行可能です。
XXXスキーマにテーブルが登録されれば、自動的にそのテーブルに対して指定した権限が有効になります。

0
0 125
InterSystems公式 Seisuke Nakahashi · 1月 16, 2024

InterSystems IRIS Cloud SQL と InterSystems IRIS Cloud IntegratedML がリリースされました。これらサービスは、実績やエンタープライズクラスのパフォーマンスおよび信頼性を兼ね備えた InterSystems IRIS テクノロジーをもとにした、クラウド環境におけるソリューション開発のベースとなるサービスです。 

InterSystems IRIS Cloud SQL は、多くのエンタープライズのお客様にご利用いただいている InterSystems IRIS のリレーショナル・データベース機能を、アプリケーション開発者やデータ専門家など幅広いみなさまにお届けする、フルマネージドのクラウドサービスです。InterSystems IRIS Cloud IntegratedML は、DBaaS (database-as-a-service) であるこの InterSystems IRIS Cloud SQL のオプション機能であり、SQL ネイティブによる自動機械学習機能への容易なアクセスを提供します。このサービスを利用して、アプリケーション・コードに簡単に組み込めるシンプルなSQLコマンドセットを通じて、データに近いところで実行されるMLモデルを実装することが可能となり、アプリケーションをより強力なものにすることが出来ます。

0
0 76
記事 Mihoko Iijima · 10月 3, 2023 4m read

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

この記事では、Muhammad Waseem さんが(US開発者コミュニティに)投稿された「SQLのスキルを次のレベルに引き上げることのできる5つの便利なSQL関数」の記事についてご紹介します。

✅ SQLに関わらず、IRIS/Caché全般で日頃利用されている便利な機能、使い方、関数などなどありましたら、ぜひコミュニティで共有いただければと思います。

✅ 現在「技術文書ライティングコンテスト」開催中です! 🎁 参加賞/特賞 🏆ありますので、ぜひチャレンジしてみてください!

以下、Muhammad さんの記事です。


この記事では、5つの便利なSQL関数の説明を実行例と共にご紹介します👇

  • COALESCE
  • RANK
  • DENSE_RANK
  • ROW_NUMBER
  • Function to Get Running Totals

まずは、COALESCE関数から始めてみましょう

0
0 639
記事 Mihoko Iijima · 9月 26, 2023 4m read

この記事では、2023年3月1日~31日の期間に開催された「技術文書ライティングコンテスト:InterSystems IRISチュートリアル」に応募された24作品の中から、Open Exchangeに公開されている sqlalchemy-iris を利用してPythonとSQLでIRISのデータを操作する方法を投稿された Heloisa Paivaさんの記事をご紹介します。

Open Exchangeは、世界各地にいる開発者コミュニティメンバーが開発したインターシステムズ製品で利用できるサンプルアプリが登録されているページで、自由にダウンロードしてご利用いただけます。

Heloisaさんの記事のように公開されている Open Exchange の利用例があると、「ちょっと使ってみたいな・・」と思われているメンバーの方への情報共有ができてとても有用な記事になると思います!丁度日本で初開催の「技術文書ライティングコンテスト」開催中ですので、ぜひ使用例や感想など、投稿してみてください!💪

0
0 787
記事 Mihoko Iijima · 9月 13, 2023 3m read

この記事では、2023年3月1日~31日の期間に開催された「技術文書ライティングコンテスト:InterSystems IRISチュートリアル」に応募された24作品の中から、Heloisa Paivaさんが投稿されたシンプルですぐに試せる記事をご紹介します。

はじめに

このチュートリアルは、テストやチュートリアル用のサンプル作成など、あらゆる目的でサンプルデータベースを作成するための、私が見つけた最も簡単な方法についての簡単なチュートリアルです。

ネームスペースの作成

  1. ターミナルを開きます。
  2. 次のコマンドを実行します。 "Do $SYSTEM.SQL.Shell()"   (※または :sql の入力でもSQLシェルに切り替えできます)
  3. "CREATE DATABASE " コマンドを実行します。実行時、作成したいネームスペース名をコマンドの引数に指定します。(TESTネームスペースを作成する例:CREATE DATABASE TEST)

これで、管理ポータルから新しいネームスペースを作成するより簡単で素早い方法でネームスペースを作成できます。

ネームスペースに移動するには、現在開いているSQLシェルを終了させるため、"quit" を入力し、zn "ネームスペース名" と入力します。これでターミナルで行うすべての動作がこのネームスペースのスコープに入ります。

テーブルの作成

0
0 176
記事 Megumi Kakechi · 8月 31, 2023 4m read

 IRISをアップグレードすると、SQLクエリオプティマイザの機能向上により、旧バージョンとは異なるクエリプランによるクエリ実行コード(クエリキャッシュ)が作成される場合があります。
ほとんどの場合はパフォーマンスが向上するのですが、稀にパフォーマンスが低下するケースもあります。

・アップグレードによりオプティマイザが改善しているとはいえ、中には遅くなるクエリがあるのではないか?
・予期しないSQLの問題が起きるのではないか?
・アップグレード後に全てのクエリパターンをテストするには時間と労力がかかりすぎる

このように、機能向上よりも安定性を優先して「今までのプランのまま実行したい」というご要望もあることでしょう。
こちらの記事では、そのようなお客様への解決策をご案内します。


解決策 = 凍結プラン(Frozen Plan)を使用する:

Cache2016.2以降(IRISはすべてのバージョン)で、クエリプランの凍結機能 が実装されました。
この機能により、IRISを新しいバージョンにアップグレードする際、既存のクエリプランは自動的に凍結されます。
これにより、アップグレードによる既存のクエリのパフォーマンスの低下の可能性を防げます(古いバージョンと同じプランが使用されるため)。
新しいクエリについてはもちろん、アップグレード後のクエリオプティマイザによるプランが使用されます。

0
0 177
記事 Toshihiko Minamoto · 2月 16, 2021 8m read

グローバルをクラスにマッピングする技術 (1/3)

グローバルをクラスにマッピングする技術 (1/3)

古くなった MUMPS アプリケーションに新たな生命を吹き込みたいとお考えですか?  以下にご紹介するステップを実行すれば、既存のグローバルをクラスにマッピングし、美しいデータを Object や SQL に公開できます。

本記事を含む合計 3 回の連載を通じてご紹介する簡単なステップを使えば、すべてのグローバル (特殊なものは除く) を Caché のクラスにマッピングできるようになります。  特殊なものについては、私が長年に渡って集めた様々な種類のマッピングを zip ファイルにまとめて提供いたします。  これは新しいデータを対象としたステップではありません。グローバルがないという方は、デフォルトのストレージをお使いください。

グローバルデータについて理解できないという方は、Support@InterSystems.com までデータをお送りください。喜んでサポートさせていただきます。

グローバルをクラスにマッピングするステップ。

  1. グローバルデータが繰り返し使用されるパターンを特定する。
  2. 固有キーの構成を特定する。
  3. プロパティとそれぞれの型を特定する。
  4. クラス内のプロパティを定義する (変数の添え字をお忘れなく)。
  5. IdKey のインデックスを定義する。
  6. Storage Definition を以下の手順で定義する。
    1. 添え字を IdKey まで (IdKey を含む) 定義する。
    2. Data セクションを定義する。
    3. Row ID セクションは触らない。  デフォルトが 99% の割合で適切なので、これはシステムに任せます。
</ol>  7. クラス / テーブルをコンパイルし、テストします。

それでは例をご紹介します!

以下のようなグローバルが 2 種類 (mapping と index) あるとしましょう。

^mapping("Simple",1)="Brendan Bannon^55192^SQL Manager"

^mapping("Simple",2)="Nicole Aaron^63375^Support Specialist"

^mapping("Simple",3)="Kyle Baxter^61155^Senior Support Specialist"

^mapping("Simple",4)="Prasad Kari^58471^Support Specialist"

^mapping("Simple",5)="Clive Morgan^57982^Senior Support Specialist"

^index("Simple","HireDate",55192,1)=""

^index("Simple","HireDate",57982,5)=""

^index("Simple","HireDate",58471,4)=""

^index("Simple","HireDate",61155,3)=""

^index("Simple","HireDate",63375,2)=""

それでは、以下 7 つのステップを実行し、SQL や Object を使ってこのデータの確認ができるクラスを作成しましょう。

ステップ 1

^mapping グローバルはいたってシンプルです。  各ノードには同じ型のデータが含まれています。  ^index グローバルについては、^mapping グローバルの後に解説します。

ステップ 2

最初の添え字は単なる定数です。 2 つ目の添え字は、1 つずつ増加するカウンタで、データの各行で異なる数字になっています。

ステップ 3

プロパティは、それぞれ Name、HireDate、Title のようです。  55192 というのは、^index グローバルを参照したり、データの用途を把握している人に確認したりしないと、それが日付であることは分かりにくいと思います。採用日であることはなおさら分からないでしょう。  2 つ目の添え字の値のプロパティを忘れずに定義しておきましょう。

ステップ 4

Property Name As %String;

Property HireDate As %Date;

Property Title As %String;

Property Sub2 As %Integer;

ステップ 5

Caché SQL Storage を使用する各クラスの IdKey インデックスをそれぞれ定義する必要があります。

     Index Master On Sub2 [ IdKey ];

インデックスマップのインデックスを定義する必要はありませんが、定義しておくと良いでしょう。

     Index  hireDateindex On HireDate;

ステップ 6

では、ここでクラスとグローバルの間でマッピングを作成する必要があります。  私はウィザードを使うのが好きなので、そのスクリーンショットをお見せします。XML を書くのが得意な方は、Caché SQL Storage を手動で定義していただけます。

Storage アイコン  をクリックします。  Storage Definition には好きな名前を付けてください。私はデフォルト名を使いました。  Caché SQL Storage をクリックし、「完了」をクリックします。

(補足)
Caché SQL Storage を作成しますと、以下のように右側のインスペクタ画面にそのプロパティが表示されますので、「SQL storage map」欄をクリックして右にある「...」をクリックします。

私は下のウィンドウで Map Name を変更しましたが、Map1 を使っても構いません。  唯一入力する必要があるのは、Global Name です。  「^」を付けるのを忘れないでください。  永続クラスにはそれぞれデータマップが 1 つずつ必要です。  複数のインデックスマップを持たせることができます。

「OK」をクリックするとウィザードを終了してしまうので、すべて完了するまではクリックしないでください。

ステップ 6a

次は添え字を定義したいと思います。  ここでは、グローバルの添え字を IdKey まで (IdKey を含む) すべて定義します (IdKey には 複数の添え字が使われる場合があります)。  式ボックスでフィールドを参照するには、そのフィールドを {} の中に入れます。  有効な COS 式であれば、どのような式でも入力できます。  ここではシンプルに、Subscript 1 には定数を、Subscript 2 にはフィールドを使用しています。 

ステップ 6b

データについては、IdKey の後に来るすべての添え字と「=」サインの右側にあるすべてのデータを説明しています。  Node 列は、追加の添え字がある場合に使用するものです (この例は次の記事でご紹介します)。  Piece と Delimiter は、グローバルの中にあるプロパティの位置を説明しています。  グローバルデータを解析する場合、デフォルトでは $PIECE コマンドが使用されます。

ステップ 6c

ここでは表示するものがありません。空白にしておきます。

では、^index グローバルに対してもステップ 6 を実行してください。

ステップ 6a

今回は添え字を 4 つ (定数 2 つ、HireDate、IdKey (Sub2)) を使います。  各インデックスマップは IdKey を作成できる必要があります。  通常は、添え字の中にあるものですが、データの一部となっている場合もあります。

ステップ 6b

追加の添え字もデータもないので、このステップは空白にしておきます

ステップ 6c

ここも特になしです。

ステップ 7

残るはクラスをコンパイルしてから、テーブルに対しクエリを実行し、データが正しく表示されることを確認するだけです。

Compilation started on 08/15/2016 15:20:58 with qualifiers 'fck /checkuptodate=expandedonly'
Compiling class Mapping.Example1
Compiling table Mapping.Example1
Compiling routine Mapping.Example1.1
Compilation finished successfully in 0.270s.

SELECT Sub2, Name, HireDate, Title FROM Mapping.Example1

Sub2              Name                                    HireDate              Title

1                      Brendan Bannon              1992-02-10          SQL Manager

2                      Nicole Aaron                      2014-07-07          Support Specialist

3                      Kyle Baxter                         2008-06-08          Senior Support Specialist

4                      Prasad Kari                          2001-02-01          Support Specialist

5                      Clive Morgan                     1999-10-01          Senior Support Specialist

また、自分で入力したいという方のために、XML で記述された Storage の定義を下にお見せしておきます。

/// アクティブな Storage Definition は各クラスごとに 1 つしか記述できません。
/// 各 Storage Definition にはそれぞれ複数のマップを持たせることができます。
Storage NewStorage1
{
<SQLMap name="HireDateIndex">
<ConditionalWithHostVars></ConditionalWithHostVars>
<Global>^index</Global>
<Subscript name="1">
<Expression>"Simple"</Expression>
</Subscript>
<Subscript name="2">
<Expression>"HireDate"</Expression>
</Subscript>
<Subscript name="3">
<Expression>{HireDate}</Expression>
</Subscript>
<Subscript name="4">
<Expression>{Sub2}</Expression>
</Subscript>
<Type>index</Type>
</SQLMap>
<SQLMap name="SimpleDataMap">
<Data name="HireDate">
<Delimiter>"^"</Delimiter>
<Piece>2</Piece>
</Data>
<Data name="Name">
<Delimiter>"^"</Delimiter>
<Piece>1</Piece>
</Data>
<Data name="Title">
<Delimiter>"^"</Delimiter>
<Piece>3</Piece>
</Data>
<Global>^mapping</Global>
<Subscript name="1">
<Expression>"Simple"</Expression>
</Subscript>
<Subscript name="2">
<Expression>{Sub2}</Expression>
</Subscript>
<Type>data</Type>
</SQLMap>
<StreamLocation>^Mapping.Example1S</StreamLocation>
<Type>%CacheSQLStorage</Type>
}

自分で入力したくないという方は、グローバルとクラスが記述されたこちらのファイルをお使いください:  mappingexample1.zip

さらに知識を深めたいという方は、是非パート 2 もお読みください

1
1 446
記事 Toshihiko Minamoto · 7月 24, 2023 8m read

Python は世界で最も使用されているプログラミング言語になり(出典: https://www.tiobe.com/tiobe-index/)、SQL はデータベース言語としての道をリードし続けています。 Python と SQL が連携して、SQL だけでは不可能であった新しい機能を提供できれば、素晴らしいと思いませんか? 結局のところ、Python には 380,000 を超える公開ライブラリがあり(出典: https://pypi.org/)、Python 内で SQL クエリを拡張できる興味深い機能が提供されています。 この記事では、Embedded Python を使用して、InterSystems IRIS データベースに新しい SQL ストアドプロシージャを作成する方法を詳しく説明します。

サンプルとして使用する Python ライブラリ

この記事では、IRIS で SQL を扱う人にとって非常に便利な GeoPy と Chronyk という 2 つのライブラリを使用します。 

Geopy は、ジオコーディング(住所と地理座標の修飾)を住所データに適用するために使用するライブラリです。 これを使用すると、通りの名前から郵便番号と完全な住所を郵便局の形式で取得することができます。 多くのレコードには住所が含まれるため、非常に便利です。

Chronyk は、人間の言語で日付と時刻を処理するために使用されます。 これは、IRIS と Python の両方において、日付は内部的に最初の日付から経過した時間を表す数字でたるため、非常に便利です。 人間の場合、日付は 7 月 20 日、または昨日や明日、または 2 時間前と表現しますが、 Chronyk では、このような日付を受け取って、ユニバーサル日付形式に変換します。

InterSystems IRIS への Python サポート

バージョン 2021.1 より、Python を使用してクラスメソッド、ストアドプロシージャ、相互運用プロダクション、Python と IRIS(ObjectScript)間の双方向のネイティブ呼び出しを作成できるようになりました。 Python とこれほど深く連携するデータプラットフォームを他に知りません。 これが機能するためには、要件として、Python が IRIS と同じ同じ物理マシンか仮想マシンまたはコンテナにインストールされている必要があります。 詳細は、https://docs.intersystems.com/iris20221/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_epython をご覧ください。 Python をインストールするには、以下を実行します。

# install libraries required for python and pip
RUNapt-get-yupdate\
    &&apt-get-yinstallapt-utils\
    &&apt-getinstall-ybuild-essentialunzippkg-configwget\
    &&apt-getinstall-ypython3-pip  

InterSystems IRIS への Python ライブラリサポート

InterSystems IRIS が Python ライブラリを使用できるようにするには、Python ライブラリが <installdir>/mgr/python にインストールされている必要があります。 installdir は IRIS がインストールされているフォルダです。 新しいパッケージをインストールするには、以下を実行します。

# use pip3 (the python zpm) to install geopy and chronyk packages
RUNpip3install--upgradepipsetuptoolswheel
RUNpip3install--target/usr/irissys/mgr/pythongeopychronyk

Pip3 は Python の最も一般的なパッケージマネージャーおよびインストーラー Pip です。

Python 言語でストアドプロシージャを作成する

InterSystems IRIS で Python を使用する可能性の 1 つは、Python を使用してストアドプロシージャを作成することです。 以下の 2 つの可能性があります。

  1. Create 関数またはプロシージャの SQL 文を使用したストアドプロシージャ Python の作成。
  2. sqlProc タグと language=Python タグを使用した ObjectScript クラス内での ClassMethod の作成。

Create プロシージャの SQL 文を使用したストアドプロシージャ Python の作成

InterSystems ドキュメントによると、以下に示すとおり、CREATE ステートメントに LANGUAGE PYTHON 引数を指定することで、Embedded Python を使って SQL 関数またはストアドプロシージャを記述することもできます(出典: https://docs.intersystems.com/iris20221/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_runpython_sql)。

CREATE FUNCTION tzconvert(dt TIMESTAMP, tzfrom VARCHAR, tzto VARCHAR)
    RETURNS TIMESTAMP
    LANGUAGE PYTHON
{
    from datetime import datetime
    from dateutil import parser, tz
    d = parser.parse(dt)
    if (tzfrom is not None):
        tzf = tz.gettz(tzfrom)
        d = d.replace(tzinfo = tzf)
    return d.astimezone(tz.gettz(tzto)).strftime("%Y-%m-%d %H:%M:%S")
}

この新しい SQL 関数を実行する場合:

SELECT tzconvert(now(), 'US/Eastern', 'UTC')

関数は以下のようなものを返します。

2022-07-20 15:10:05

sqlProc タグと language=Python タグを使用した ObjectScript クラス内での ClassMethod の作成

正直に言うと、sqlProc タグと language=Python タグを使って ClassMethod を作成するこのアプローチが私のお気に入りです。 私の意見では、管理しやすく、十分な文書化で明確に示されており、ソースコードバージョンの管理もうまく行えます。 このアプローチのためのサンプルアプリケーションを公開しました(https://openexchange.intersystems.com/package/Python-IRIS-SQL-Procedures-Sample)。 これを使用して、この 2 番目のアプローチを詳しく説明します。

サンプルアプリケーションのインストール

サンプルアプリケーションをインストールするには、以下の手順に従います。

  1. リポジトリを任意のローカルディレクトリに Clone/git pull します。
$ git clone https://github.com/yurimarx/iris-sql-python-sample.git
  1. このディレクトリで Docker ターミナルを開き、以下を実行します。
$ docker-compose build
  1. IRIS コンテナを実行します。
$ docker-compose up -d

もう 1 つのインストール方法は、ZPM を使用する方法です。

zpm "install iris-sql-python-sample"

Python を使用したストアドプロシージャのサンプル

最初の例は、住所のジオコーディングを処理するストアドプロシージャです。ソースコードを参照してください。

ClassMethodGetFullAddress(StreetAs%String,CityAs%String,StateAs%String)
  <div>
    <span style="color: #85a6ff;">As</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">%String</span><span style="color: #d4d4d4;"> </span><span style="color: #ffffff;">[</span><span style="color: #d4d4d4;"> </span><span style="color: #85a6ff;">Language</span><span style="color: #d4d4d4;"> </span><span style="color: #ffffff;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #d4b57c;">python</span><span style="color: #ffffff;">,</span><span style="color: #d4d4d4;"> </span><span style="color: #85a6ff;">SqlName</span><span style="color: #d4d4d4;"> </span><span style="color: #ffffff;">=</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">GetFullAddress</span><span style="color: #ffffff;">,</span><span style="color: #d4d4d4;"> </span><span style="color: #85a6ff;">SqlProc</span><span style="color: #d4d4d4;"> </span><span style="color: #ffffff;">]</span>
  </div>
  
  <div>
    <span style="color: #ffffff;">{</span>
  </div>
  
  <div>
    <span style="color: #85a6ff;">    </span><span style="color: #85a6ff;">import</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">geopy</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">geocoders</span>
  </div>
  
  <div>
    <span style="color: #85a6ff;">    </span><span style="color: #85a6ff;">from</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">geopy</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">geocoders</span><span style="color: #85a6ff;"> </span><span style="color: #85a6ff;">import</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">Nominatim</span>
  </div>
  
  <div>
    <span style="color: #ade2ff;">    </span><span style="color: #ade2ff;">geopy</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">geocoders</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">options</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">default</span><span style="color: #ade2ff;">_</span><span style="color: #ade2ff;">timeout</span><span style="color: #ffffff;"> =</span><span style="color: #d4b57c;"> </span><span style="color: #d4b57c;">7</span>
  </div>
  
  <div>
    <span style="color: #ade2ff;">    </span><span style="color: #ade2ff;">geolocator</span><span style="color: #ffffff;"> =</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">Nominatim</span><span style="color: #ffffff;">(</span><span style="color: #ade2ff;">user</span><span style="color: #ade2ff;">_</span><span style="color: #ade2ff;">agent</span><span style="color: #ffffff;">=</span><span style="color: #d4b57c;">"intersystems_iris"</span><span style="color: #ffffff;">)</span>
  </div>
  
  <div>
    <span style="color: #ade2ff;">    </span><span style="color: #ade2ff;">location</span><span style="color: #ffffff;"> =</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">geolocator</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">geocode</span><span style="color: #ffffff;">(</span><span style="color: #ade2ff;">Street</span><span style="color: #ffffff;"> +</span><span style="color: #d4b57c;"> </span><span style="color: #d4b57c;">", "</span><span style="color: #ffffff;"> +</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">City</span><span style="color: #ffffff;"> +</span><span style="color: #d4b57c;"> </span><span style="color: #d4b57c;">", "</span><span style="color: #ffffff;"> +</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">State</span><span style="color: #ffffff;">,</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">country</span><span style="color: #ade2ff;">_</span><span style="color: #ade2ff;">codes</span><span style="color: #ffffff;">=</span><span style="color: #d4b57c;">"US"</span><span style="color: #ffffff;">)</span>
  </div>
  
  <div>
    <span style="color: #85a6ff;">    </span><span style="color: #85a6ff;">return</span><span style="color: #ade2ff;"> </span><span style="color: #ade2ff;">location</span><span style="color: #ffffff;">.</span><span style="color: #ade2ff;">address</span>
  </div>
  
  <div>
    <span style="color: #ffffff;">}</span>
  </div>
</div>

ClassMethod が [ Language = python, SqlProc] タグで(dc.pythonsql.Company クラス内に)宣言されているのが分かります。
SqlName タグによって、新しいストアドプロシージャの名前を SQL 分に設定できます。

管理ポータルの[システム]>[SQL]に移動し、以下のコードを実行します。

SELECT 
ID, City, Name, State, Street, Zip, dc_pythonsql.GetFullAddress(Street, City, State) As FullAddress 
FROM dc_pythonsql.Company

結果が表示されます。

Geopy

不完全な住所から「完全な」住所(完全修飾)が返されるようになりました。

注意: 何も返されない場合は、#class(dc.pythonsql.Company).CreateFiveCompanies() を実行してください。 テストに使用する 5 つの会社が作成されます。

このパッケージは、主なオープンのジオコーディングサービスと有料のサービスと連携できます。 この例では、Nominatim というオープンサービスを使用していますか、Bing、Google、ArcGIS などを使用することも可能です。 利用可能なサービスについて、https://geopy.readthedocs.io/en/stable/#module-geopy.geocoders をご覧ください。

2 つ目の例は、人間が読み取れる形式による Chronyk という日付と時刻のパッケージです。

「明日」、「昨日」、「今から 4 時間後」、「2022 年 7 月 4 日」などの文を送信し、ユニバーサル日付形式の結果を取得できます。 ストアドプロシージャの作成を参照してください。

ClassMethodGetHumanDate(SentenceAs%String)As%String[Language=python,SqlName=GetHumanDate,SqlProc]
{
    fromchronykimportChronyk
    t =Chronyk(Sentence)
    returnt.ctime()
}

管理ポータル >[システム]>[SQL]で、以下の呼び出しを実行します。

SELECT 
ID, City, Name, State, Street, Zip, dc_pythonsql.GetHumanDate('yesterday') As Datetime      
FROM dc_pythonsql.Company

結果が表示されます。

https://raw.githubusercontent.com/yurimarx/iris-sql-python-sample/main/screen2.png

ストアドプロシージャを呼び出すだけの場合は、この SQL 分を使用できます。

select dc_pythonsql.GetHumanDate('yesterday') as Datetime  

このライブラリには、人間が読み取れる日付と時刻の例が複数含まれています。https://github.com/KoffeinFlummi/Chronyk をご覧ください。

Python ストアドプロシージャは簡単に作成できます。ぜひ試してみてください!

0
0 399
記事 Toshihiko Minamoto · 7月 5, 2023 39m read

この記事では、InterSystems IRIS の学習に関連したトピックについて、開発者コミュニティでの厳選された記事にアクセスすることができます。機械学習や Embedded Python、JSON、API と REST アプリ、InterSystems環境の構築と管理、DockerとCloud、VSCode、SQL、Analytics/BI、グローバル、セキュリティ、DevOps、インターオペラビリティNative API、それぞれでランク付けされたトップの記事を見ることができます。ぜひ、楽しみながら学んでください!  

機械学習

機械学習は、高度なデータ分析を構築し、優れた効率で手動活動を自動化するための必須技術です。既存のデータから学習する認知モデルを作成し、自己調整されたアルゴリズムに基づいて予測、確率計算、分類、識別、「非創造的」な人間の活動の自動化を実行します。

すべてのシナリオにおいて、InterSystems IRISは、これらのマシンラーニングモデルを作成、実行、利用可能にし、使用するためのデータプラットフォームおよび環境として機能します。IRISは、SQLコマンドからのML利用(IntegratedML)、Embedded PythonやPMML(Predictive Model Markup Language)による機械学習が可能です。以下の記事でその機能を確認することができます。

名称概要URL
IntegratedMLハンズオンラボIntegratedMLの実践的な概要https://community.intersystems.com/post/integratedml-hands-lab
InterSystems IRISデータプラットフォームによるAIロボット化IRISプロダクションのAIhttps://community.intersystems.com/post/ai-robotization-intersystems-iris-data-platform
IRIS IntegratedMLを使った糖尿病予測WebアプリIntegratedMLサンプルhttps://jp.community.intersystems.com/node/535221
妊産婦の健康リスクの予測IntegratedMLサンプルhttps://community.intersystems.com/post/predict-maternal-health-risks
機械学習によるコミュニティー記事の整理 - 1Python MLライブラリの利用https://community.intersystems.com/post/using-machine-learning-organize-community-1

 

ObjectScript言語

ObjectScript は InterSystems のオフィシャルプログラミング言語です。簡単で柔軟性があり、バックエンド、統合、および分析アプリケーションの作成に非常に強力です。詳細については、以下の記事を参照してください。

名称概要URL
InterSystems ObjectScript 101++ (EN)ObjectScriptを学ぶビデオシリーズhttps://community.intersystems.com/post/intersystems-objectscript-101-en
$Sequence関数について数列の作成するhttps://community.intersystems.com/post/sequence-function
Caché ObjectScript でのパフォーマンスの高いループの作成ループの作成https://jp.community.intersystems.com/node/481811
データの匿名化、iris-Disguiseの導入ObjectScript の永続的なクラスとプロパティをカスタマイズする方法について説明するhttps://jp.community.intersystems.com/node/510731
ObjectScriptのエラー処理に関するスニペット例外処理https://jp.community.intersystems.com/node/491451
ObjectScriptにおける従来のデバッグデバッグ手法https://community.intersystems.com/post/traditional-debugging-objectscript
Caché での正規表現の使用正規表現を使った作業https://jp.community.intersystems.com/node/481816
ObjectScript における堅牢なエラー処理とクリーンアップ品質の高いコードを書くhttps://jp.community.intersystems.com/node/486226
InterSystems Ensembleを愛し、心配することをやめた理由プロダクションでのJSON処理https://community.intersystems.com/post/how-we-learned-stop-worrying-and-love-intersystems-ensemble
より使いやすくなったオブジェクト・ダンプダンプするオブジェクトhttps://community.intersystems.com/post/more-usefull-object-dump
InterSystems IRISのマクロを使ったロギングマクロを使ったロギングhttps://jp.community.intersystems.com/node/503796
SYSLOG - その実態と意味することシスログのデバッグ情報https://jp.community.intersystems.com/node/492146
%Statusを使ったデバッグのヒント%Statusを使ったデバッグhttps://jp.community.intersystems.com/node/503801
$Queryの有効活用$Query を使ってデータを探すhttps://community.intersystems.com/post/making-most-query
多次元プロパティの永続性 - Part 1 (クラシック)多次元永続プロパティhttps://community.intersystems.com/post/multidimensional-property-persistence-part-1-classic
採用されたBitmapBitmap インデックスhttps://community.intersystems.com/post/adopted-bitmap
タイムロードになる方法 - 誕生日付と時刻のAPIhttps://jp.community.intersystems.com/node/527796
正確なバージョン情報($zv / $zversion)の重要性と収集についてIRISバージョン取得https://community.intersystems.com/post/importance-and-collection-exact-version-information-zv-zversion
1840年12月以前の日付 ? $H( orolog )がネガティブ?ネガティブな日付https://community.intersystems.com/post/date-dec1840-negative-horolog
Caché でのカスタム・インデックス・タイプの作成カスタムインデックスの作成https://jp.community.intersystems.com/node/479316
$LIST 文字列フォーマットと %DynamicArray および %DynamicObject クラス$LIST、%DynamicObject、%DynamicArrayの使用法https://jp.community.intersystems.com/node/483711
^ERRORグローバルに対するSQLSQLを使ってエラーの内容の確認https://community.intersystems.com/post/sql-error-global
コードによるデフォルト設定値の追加デフォルト値の設定https://community.intersystems.com/post/add-default-setting-value-code
ダイナミックオブジェクトの反復処理イテレート(反復処理)の使用https://community.intersystems.com/post/iterate-over-dynamic-object
クラスのすべてのプロパティをリストアップする (ObjectScriptがお気に入りな理由)ObjectScriptプロパティの反復使用https://jp.community.intersystems.com/node/515786
いつも使っているtry catchブロックTry Catchのハンドリングhttps://community.intersystems.com/post/try-catch-block-i-usually-use-intersystems-objectscript
ObjectScriptでシェルコマンドの実行ObjectScriptでシェルコマンドの実行https://community.intersystems.com/post/running-shell-commands-objectscript

Embedded Python

Python は、世界で最も人気があり、よく使われているプログラミング言語の 1 つです (https://www.tiobe.com/tiobe-index/)。InterSystems IRIS は、すべての主要なプログラミング言語に対して開かれたデータ・プラットフォームです。しかし、Python は、この素晴らしい言語とそのライブラリは、クラス、SQL、および統合/プロダクショ ンなど、IRIS のあらゆる場所で使用することができます。ObjectScript ( InterSystems のプログラミング言語 ) を知らない、または知りたくない人にとって、Python は素晴らしい選択肢となります。そのやり方については、以下の記事を参照してください。

名称概要URL
機械と戦おうEmbedded Pythonを使ったチックタックトー・ゲームの構築https://community.intersystems.com/post/lets-fight-against-machines
InterSystems IRIS 2021.2+ Python サンプル ( Embedded, Native API およびノートPC)複数のPythonノートPCでPythonとIRISを見るhttps://community.intersystems.com/post/intersystems-iris-20212-python-examples-embedded-native-apis-and-notebooks
Embedded PythonによるWebSocketクライアントCustom Socket サンプルhttps://community.intersystems.com/post/websocket-client-embedded-python
AWS LambdaにおけるIRIS Python Native APIAWSでのPythonhttps://community.intersystems.com/node/485361
JupyterノートPCにObjectScriptを追加する方法ノートPCでのIRIShttps://jp.community.intersystems.com/node/521496
ようこそDjangoIRISをデータベースとしたPython Djangoアプリの作成https://jp.community.intersystems.com/node/527801
IRISとGoogle Maps APIによるジオコーディングGeocoding python ライブラリの使用https://community.intersystems.com/post/geocoding-iris-and-google-maps-api
IRISとPython gTTSを用いたテキストから音声への変換のためのRESTサービスgTTSを使用したPythonサンプルhttps://community.intersystems.com/post/rest-service-convert-text-audio-using-iris-and-python-gtts
Python Flask WebフレームワークによるIRISレスポンシブダッシュボードの作成IRISによるFlask Webアプリhttps://community.intersystems.com/post/building-iris-responsive-dashboard-python-flask-web-framework

JSON

JSON は、マーケットで最も広く使用されている、データの送受信のための相互運用性フォーマットの 1 つです。InterSystems IRIS は、いくつかの方法でこの形式をサポートしています。JSON (DocDB) でネイティブ・データベースを持ち、オブジェクトを直列化および非直列化し、特に REST サービスからの要求と応答を JSON で処理することが可能です。以下の記事を確認してください。

名称概要URL
Caché 2016.1における新しいJSON機能の紹介ObjectScript JSON API の紹介https://community.intersystems.com/post/introducing-new-json-capabilities-cach%C3%A9-20161
JSONの機能強化JSON Adaptor APIhttps://jp.community.intersystems.com/node/481776

APIとRESTアプリ

バックグラウンドアプリケーションは現在、REST(Representational State Transfer)パラダイムで開発され、Web APIとして公開されています。以下の記事で、その仕組みを確認してください。

名称概要URL
InterSystemsのデータプラットフォームのためのGraphQLGraphQLスタイルでREST APIの作成https://jp.community.intersystems.com/node/481796
InterSystems API Managerの紹介API Managementの概要https://community.intersystems.com/post/introducing-intersystems-api-manager
RESTの高度なURLマッピングAPIへの経路のマッピングhttps://jp.community.intersystems.com/node/497976
AppS.REST: InterSystems IRISのための新しいRESTフレームワークRESTアプリを簡単に作成https://jp.community.intersystems.com/node/497991
RESTForms : クラスのためのREST APICRUDアプリケーションのためのREST APIの開発https://jp.community.intersystems.com/node/479226
スペックファーストのアプローチによるREST APIの作成Contract First ApproachによるAPI開発https://jp.community.intersystems.com/node/476556
ObjectScript REST API クックブックREST API 開発のヒントhttps://community.intersystems.com/post/objectscript-rest-api-cookbook
永続クラスとシリアルクラスからSwaggerスペックを生成するContract First ApproachによるAPI開発https://jp.community.intersystems.com/node/490976
InterSystems IRIS REST アプリケーションのパターンIRISによるAPI RESTの作成https://community.intersystems.com/post/intersystems-iris-rest-application-patterns
SUSHIでFHIRプロファイルを作成しよう 第1回カスタムFHIRプロファイルの作成https://jp.community.intersystems.com/node/493351
ゼロから使いこなすIAMIAMでAPIの管理https://jp.community.intersystems.com/node/493416
InterSystems API Management を使用してAPIの負荷を分散するAPIMによるAPIのロードバランスhttps://jp.community.intersystems.com/node/482711
InterSystems API Management で OAuth 2.0 による API のセキュリティの確保 - 第1回APIMによるAPI のセキュリティの確保hhttps://jp.community.intersystems.com/node/497946
InterSystems IRISアプリケーションのAngular UIを5分で取得IRISとAngularによるFull Stackアプリhttps://community.intersystems.com/post/getting-angular-ui-your-intersystems-iris-application-5-minutes
InterSystems IRIS REST APIへのアップロードREST APIによるファイル保存https://community.intersystems.com/post/upload-intersystems-iris-rest-api

InterSystems 環境の管理と設定

IRIS環境を適切に管理・設定することは、ユーザーが使用するアプリケーションのパフォーマンス、セキュリティ、可用性、信頼性にとって不可欠です。これらの記事は、これを行うための優れたヒントを与えてくれるでしょう。

名称概要URL
InterSystemsデータプラットフォームにおける容量計画およびパフォーマンスのシリーズのインデックス性能とパフォーマンスの向上https://jp.community.intersystems.com/node/477596
InterSystems Cache での %Installer によるアプリケーションのデプロイメント%Installer によるネームスペース、データベース、およびアプリケーションの構成の作成https://jp.community.intersystems.com/node/478966
InterSystems IRISによる水平方向のスケーラビリティIRISインスタンスを設定し、水平方向のスケーラビリティの実現https://jp.community.intersystems.com/node/477591
Raspberry Pi Raspberry で動作する InterSystems Iris Fhirserver が FHIRserver として動作Raspberry PI内部でIRISの動作https://jp.community.intersystems.com/node/516361
バーチャルIPアドレスを使用しないデータベースミラーリングVIPによるミラーの設定https://jp.community.intersystems.com/node/493401
DockerによるApache Web GatewayWebアプリケーションのSSLとWeb Gatewayの設定https://jp.community.intersystems.com/node/542181
IRISにおけるSAMLとの連携Webサービス向けSAMLhttps://community.intersystems.com/post/work-saml-iris
SYSTEM.Encryption クラスの習得IRISによる暗号化・復号化https://jp.community.intersystems.com/node/523406

Docker と Cloud

新しいアプリケーション・アーキテクチャは、コンテナ Docker と Cloud において動作し、弾力的なスケーラビリティ、インストール、設定、プロビジョニング時間の短縮、インフラの複雑性とコストの削減を実現することを目的としています。これらの記事を読んで、IRISをクラウド化する方法を学んでください。

名称概要URL
Kubernetesにおけるミラーリングを使用しない高可用性IRISデプロイKubernetesによるIRISをクラウドクラスターで利用するhttps://jp.community.intersystems.com/node/490971
Amazon Web Services (AWS)のためのInterSystems IRISリファレンス・アーキテクチャAWSでのIRIShttps://jp.community.intersystems.com/node/481326
Microsoft Azure Resource Manager (ARM)のInterSystems製リファレンス・アーキテクチャ安価なマシン(ARM machine)を使ったAzureでのIRIShttps://jp.community.intersystems.com/node/478971
Dockerfileと仲間たち、またはInterSystems IRISでのObjectScriptプロジェクトの実行と共同作業の方法Dockerプロジェクトにおける重要なファイルについて知ることhttps://community.intersystems.com/post/dockerfile-and-friends-or-how-run-and-collaborate-objectscript-projects-intersystems-iris
CloudFormationテンプレートを使用したAWS向けInterSystems IRISデプロイメントガイドCloudFormationを使ったAWSで使うIRIShttps://jp.community.intersystems.com/node/486206
Google Cloud Platform(GCP) におけるInterSystems IRIS のリファレンス・アーキテクチャGoogle Cloudで使うIRIShttps://jp.community.intersystems.com/node/479806
InterSystems IRISでAWS Glueの使用IRISとAWS Glue(AWSのETLツール)の利用https://jp.community.intersystems.com/node/485971
AmazonのEKSとIRIS。高可用性とバックアップAWSによるHAで使うIRIShttps://jp.community.intersystems.com/node/501186 AWSによるHAでのIRIS
コンテナでの InterSystems レポートの動かしてみるDockerに関するIRISのレポートhttps://jp.community.intersystems.com/node/501656
InterSystems IRIS を Kubeless を使って FaaS モードで実行Kubernetesで使うIRIShttps://jp.community.intersystems.com/node/523446
InterSystems Kubernetes Operator Deep Dive ‐ Kubernetes Operatorの紹介Kubernetesで使うIRIShttps://community.intersystems.com/post/intersystems-kubernetes-operator-deep-dive-introduction-kubernetes-operators
クラウドホストのスケーリングとInterSystems IRISの再構築AWS、Azure、またはGCPでのIRISのスケーリングhttps://community.intersystems.com/post/scaling-cloud-hosts-and-reconfiguring-intersystems-iris
Amazon EKSを用いたシンプルなIRISベースのWebアプリケーションのデプロイメントAWSで使うIRIShttps://jp.community.intersystems.com/node/478961

VSCode

VSCodeは世界で最も使われているIDEの1つです。IRISはこのIDEをフルサポートしています。以下の記事をご覧ください。

名称概要URL
VSCode-ObjectScriptのGitHubでの使用Web Github VSCodeでIRISアプリの開発https://jp.community.intersystems.com/node/510736
IRISによるGitHubのコードスペースGithubでIRISアプリの開発https://jp.community.intersystems.com/node/510736
VSCodeのヒントとコツ - SOAPウィザードVSCodeにショートカットのオプションの作成https://community.intersystems.com/post/vscode-tips-tricks-soap-wizard
VS Codeへの独自のスニペットの追加スニペットの作成https://community.intersystems.com/post/adding-your-own-snippets-vs-code

SQL

SQLは、リレーショナルデータベースを扱うのに最もよく使われる言語の1つです。これらの記事は、クエリの実行方法とデータの永続性を示しています。

名称概要URL
フリーテキスト検索:SQL開発者が隠しているテキストフィールドの検索方法*インデックスの活用で高度な検索を促進https://jp.community.intersystems.com/node/479321
日付範囲クエリのSQLパフォーマンスの向上日付を使ったSQLクエリの実行https://jp.community.intersystems.com/node/479286
スタティックWHERE条件永続的なクラ使うWherehttps://community.intersystems.com/post/static-where-conditions
2021.2 SQL機能スポットライト - ランタイムプランの選択ランタイムSQL実行プランの選択https://jp.community.intersystems.com/node/510746
2020.1 の新機能:ユニバーサルクエリキャッシュSQL Cachehttps://jp.community.intersystems.com/node/535211
マテリアライズド・ビュー永続的なクラスの中にビューの作成https://community.intersystems.com/post/materialized-views
SQLを使ったデバッグのコツSQLコマンドのデバッグhttps://community.intersystems.com/post/debugging-trick-sql
ClassQueries()をテーブルとして使用ビューの作成https://community.intersystems.com/post/using-classqueries-tables
M:Nの関係N対Nの関係性のマッピングhttps://community.intersystems.com/post/mn-relationship
IRISでCOVIDにたいしてのAWS S3データをSQLテーブルとして読み込むAWS S3からCSVデータをIRISのテーブルに取得https://community.intersystems.com/post/reading-aws-s3-data-covid-sql-table-iris
知っておくと便利なクエリパフォーマンスのコツ - Tune TableSQLチューニングhttps://jp.community.intersystems.com/node/535211
データストレージ:開発がうまくいくために知っておくべき情報より高いパフォーマンスを得るために、データストレージ部を永続的なクラスで構成するhttps://community.intersystems.com/post/data-storage-information-you-must-know-make-good-decisions-when-developing
日付範囲クエリのSQLパフォーマンスを改善する vol2SQLクエリの日付に関するチューニングhttps://jp.community.intersystems.com/node/479291
スクロール可能なResultSetのページネーションのサンプルSQLの結果をページ分割する(コメントも参照)https://community.intersystems.com/post/scrollable-resultset-pagination-sample
1日目 InterSystems ObjectsとSQLを用いた開発InterSystems IRISへのSQLに関するコンセプトhttps://community.intersystems.com/post/day-1-developing-intersystems-objects-and-sql
SQLgatewayを利用したDBマイグレーションPostgreSQL、MySQL、その他のデータベースからIRISへのマイグレーションhttps://jp.community.intersystems.com/node/518861
InterSystems IRIS の既存のテーブルに CSV のインポートCSVからSQLテーブルへのインポートhttps://community.intersystems.com/post/importing-csv-existing-table-intersystems-iris
データベースの4つのAPISQLの APIhttps://community.intersystems.com/post/four-database-apis
アトミックでない属性のインデックス作成高度なインデックスのオプションの作成https://jp.community.intersystems.com/node/486236
インデックスについてインデックス作成の基礎知識https://jp.community.intersystems.com/node/492126
Dynamic SQLからDynamic ObjectへDynamicSQLの使用https://community.intersystems.com/post/dynamic-sql-dynamic-object
データ移行ツール - その1:PostgresからIRISへ一般的なデータベースからIRISデータベースへの移行方法を紹介する連載記事https://jp.community.intersystems.com/node/518871

アナリティクスとビジネスインテリジェンス(BI)

アナリティクスとBIは、グラフ、ダッシュボード、サマリー、詳細表などのデータ分析、およびアナリスト・ユーザーによるナビゲーションとデータ探索に基づいて意思決定を行うことを可能にします。ここでは、IRISを使った分析アプリケーションの構築方法を紹介します。

名称概要URL
InterSystems IRISのCOVID-19アナリティクスInterSystems IRISにおけるCOVID-19アナリティクスhttps://community.intersystems.com/post/covid-19-analytics-intersystems-iris
DeepSeeトラブルシューティングガイド不具合修正https://jp.community.intersystems.com/node/542206
AnalyzeThis - InterSystems BIへのクイックスタートInterSystems BIへのクイックスタートhttps://community.intersystems.com/post/analyzethis-%E2%80%93-quick-start-intersystems-bi
InterSystems IRIS用のPower BIコネクタ パート1Power BIでIRISのデータの利用https://jp.community.intersystems.com/node/482606
DeepSee でのポートレットの作成IRIS BIによるアナリティクスポートレットhttps://community.intersystems.com/post/creating-portlets-deepsee
Game Of Throne Analytics、またはアリア スタークリストの長さアナリティクスのサンプルhttps://community.intersystems.com/post/game-throne-analytics-or-how-long-aryas-stark-list
DeepSee Web。AngularJSによるInterSystems Analyticsのビジュアライゼーション。第 1 部Angularを使用するWebダッシュボードhttps://community.intersystems.com/post/deepsee-web-intersystems-analytics-visualization-angularjs-part-1
IRIS でアナリティクスソリューションを構築するIRISでアナリティクスを行うための主なオプションの紹介https://jp.community.intersystems.com/node/501571

グローバル

IRIS では、SQL、クラス、JSON ドキュメント、BI キューブ、その他のカスタム形式など、データを柔軟に保存および取得するための重要なメカニズムとして、グローバルが使用されています。以下の記事で、その方法を垣間見てください:

名称概要URL
グローバルをクラスにマッピングする技術 :1 / 3グローバルの SQL テーブルおよびオブジェクトへのマッピングhttps://jp.community.intersystems.com/node/486176
グローバルは、データ管理の魔法の剣。第1回グローバルに関する基礎知識https://jp.community.intersystems.com/node/476486
GlobalToJSON-embeddedPython-pureグローバルをJSONへの書き出しhttps://community.intersystems.com/post/globaltojson-embeddedpython-pure
InterSystems IRIS のグローバルを使ったトランザクショングローバルパーシスタンスのトランザクション管理https://jp.community.intersystems.com/node/486476
グローバルによる マインドマップの保存グローバルを使ってマインドマップデータの永続化https://jp.community.intersystems.com/node/516226

セキュリティ

どのようなアプリケーションでも、セキュリティを確保することは非常に重要です。セキュリティは、アクセスや承認の管理、トランザクションの追跡と監査、保存および転送されるコンテンツの暗号化、感性的なリソースの保護を保証するための正しい設定パラメータに関連しています。これらの記事を読んで、セキュリティを確立する方法について理解を深めてください。

名称概要URL
InterSystems IRIS Open Authorization Framework (OAuth 2.0) の実装 - 第1回OAuthの使用https://jp.community.intersystems.com/node/478821
WebのデバッグCSPおよびRESTアプリのデバッグhttps://jp.community.intersystems.com/node/501166
InterSystems IRIS のクラスクエリ永続クラス内部でのSQL Queryの定義https://jp.community.intersystems.com/node/483716
TLS/SSLでOSの証明書ストアの使用SSLを行うためにOSの証明書の使用https://community.intersystems.com/post/using-os-certificate-store-tlsssl
インテグリティチェック :スピードアップまたはスピードダウンインテグリティの確保https://community.intersystems.com/post/integrity-check-speeding-it-or-slowing-it-down
データ変更の追跡 - 監査ログ - 1 / 2監査データの保存https://jp.community.intersystems.com/node/483691
TLS/SSL/HTTPS による管理ポータル(プライベート Web サーバー)の運用IRIS Web サーバーへの SSL の設定https://community.intersystems.com/post/running-management-portal-private-web-server-over-tlssslhttps
OAuth認証とInterSystems IRIS:信頼プロトコルのテイム化OAuthの使用https://community.intersystems.com/post/oauth-https://jp.community.intersystems.com/node/493421
SOAP(Web)サービスでのOauth2の利用についてSOAPサービスにおけるOauthの設定https://jp.community.intersystems.com/node/483696
DeepSee: セキュリティの設定 - 1/5IRIS BIにおけるセキュリティhttps://community.intersystems.com/post/deepsee-setting-security-part-1-5
システムのセキュリティレベルの変更についてデフォルトでセキュリティhttps://community.intersystems.com/post/changes-security-level-system

DevOps

DevOpsとは、ソースコードの開発(Dev)から本番運用(Ops)への高速かつ高品質な移行を自動化することを可能にするプラクティスやツールを採用する方法です。IRISでその方法をご覧ください。

名称概要URL
GitLabを使ったInterSystemsソリューションの継続的デリバリー - 第1回:GitGitLabによる継続的デリバリーhttps://jp.community.intersystems.com/node/476396
InterSystems ObjectScripts パッケージ・マネージャの紹介ZPMを使用して、アプリケーション内のサードパーティパッケージを設定およびインストールhttps://jp.community.intersystems.com/node/486186
ZPMshow - 疲れた指のためのヘルパーZPM - IRISパッケージマネージャの使用方法https://community.intersystems.com/post/zpmshow-helper-tired-fingers
プログラムによるミラーのセットアップ方法新しいミラーの作成を自動化するhttps://jp.community.intersystems.com/node/516091
ObjectScript パッケージマネージャにおけるユニットテストとテストカバレッジObjectScriptのコード品質のためのUnit Testsの作成https://jp.community.intersystems.com/node/516111
DockerとMergeCPFを使ったシャードクラスターの展開cpfファイルによる設定の自動化https://community.intersystems.com/post/deploying-sharded-cluster-docker-and-mergecpf
Caché ObjectScript クイックリファレンスObjectScriptリファレンスpdfドキュメントhttps://community.intersystems.com/post/cach%C3%A9-objectscript-quick-reference
ZPMモジュールの解剖学:InterSystems Solution のパッケージングZPMを使用してデプロイメントの自動化https://jp.community.intersystems.com/node/487071
IRISコンテナへのVSCodeの追加VSCodeをdockerインスタンスに埋め込むhttps://community.intersystems.com/post/adding-vscode-your-iris-container
InterSystems IRIS用の新しいデータベース、ネームスペース、およびWebアプリケーションをプログラムによって作成する方法データベースとネームスペースの作成の自動化https://community.intersystems.com/post/how-create-new-database-namespace-and-web-application-intersystems-iris-programmatically
ユニットテスト: ObjectScript コードの品質ユニットテストによる品質保証https://community.intersystems.com/post/unit-tests-quality-your-objectscript-code
インターシステムズ開発者コミュニティのDockerイメージDockerコミュニティイメージhttps://community.intersystems.com/post/some-intersystems-developer-community-docker-images

インターオペラビリティ

IRISは、強力なデータおよびアプリケーションのインタラクティブなバスを備えています。以下の記事でその使い方をご覧ください。

名称概要URL
EnsembleからTelegramでアラートの送信テレグラムにデータを送信するためのプロダクションhttps://community.intersystems.com/post/sending-alerts-ensemble-telegram
[初めてのInterSystems IRIS] インターオペラビリティを使ってみようビジネスサービス、オペレーション、プロセス、プロダクションの作成https://jp.community.intersystems.com/node/483021
Embedded PythonによるInterSystems IRISのインターオペラビリティーPythonによるビジネスサービス、オペレーション、プロセス、プロダクションの作成https://jp.community.intersystems.com/node/518846
Ensemble / Interoperabilityトレーニングコースプロダクションの作り方を学ぶのに最適なサンプルhttps://community.intersystems.com/post/ensemble-interoperability-training-course
プログラムによるインターオペラビリティーのサンプルPythonまたはObjectScriptを使用したプログラムによるプロダクションhttps://jp.community.intersystems.com/node/521511
フォルダ内のファイルのリスティングフォルダー内のファイルをリスト化するhttps://community.intersystems.com/post/listing-files-folder
.Net/Java Gatewayのコンテナ化(またはKafka統合のデモ)Javaまたは.Net Native APIを使用したKafkaサポートhttps://jp.community.intersystems.com/node/542191
PEXを使用した.NETまたはJavaでのIRIS統合の実装PEXによるJavaまたは.Netを使ったプロダクションの作成https://community.intersystems.com/post/implementing-iris-integrations-net-or-java-using-pex
Java Business HostからPEXへの移行PEXの使用https://jp.community.intersystems.com/node/486231
Tesseract OCRとJava Gatewayの使用についてJava PEXの使用https://community.intersystems.com/post/using-tesseract-ocr-and-java-gateway
PEXのビジネスオペレーションを作成についてCreate Java PEX Business Operationhttps://community.intersystems.com/post/creating-pex-business-operation
OCRとNLPを統合したInterSystems IRISJava PEX のサンプルhttps://community.intersystems.com/post/ocr-and-nlp-together-intersystems-iris
HTTP Adapterを使用したカスタムインターオペラビリティビジネスサービスの作成ビジネスサービスの作成https://community.intersystems.com/post/creating-custom-interoperability-business-service-using-http-adapter

Native API

IRISは、市場で最も使用されているプログラミング言語(Java、Javascript/NodeJS、.Net、C++、Python)を使用することに前向きです。これを実現するために、これらの言語ごとにNative APIを使用しています。以下の記事をご覧ください。

名称概要URL
Docker Micro ServerとしてIRIS Native APIを使用したWebSocket Client JSIRISとNodeJSを使ってWebSocketを行うhttps://jp.community.intersystems.com/node/507846
ObjectScript用IRIS Native APINative APIの使用https://community.intersystems.com/post/iris-native-api-objectscript
Node.jsでのZPMの使用Node.jsプロジェクトでのZPMの使用https://jp.community.intersystems.com/node/507866
テキストファイルからPDFファイルの作成PDFファイルの生成用Java Native APIhttps://community.intersystems.com/post/creating-pdf-text-file
InterSystems IRISを使った開発を1分以内に始める方法IRISを使った開発の開始https://community.intersystems.com/post/how-start-development-intersystems-iris-less-minute
Python + IRIS Globals を使ったブログの作成Python Native API用ブログhttps://jp.community.intersystems.com/node/501856
0
2 245