查找

Artículo
· 12 feb, 2025 Lectura de 1 min

インターオペラビリティの処理の中でログ出力を実装する方法

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

 

インターオペラビリティ機能を使用してビジネスホストのビジネスロジックを実装する際に、デバッグ等の目的でログ出力を行うための専用マクロが用意されているので、ご紹介します。

以下のマクロが用意されています。

$$$LOGINFO("これはログです。")  
$$$LOGERROR("これはエラーです。")  
$$$LOGWARNING("これは警告です")
$$$LOGSTATUS(status) 
$$$LOGSTATUS(status2) 
$$$ASSERT("これはアサートです。")

ビジネスオペレーション等のコードに上記のコードを書くことにより、インターオペラビリティのイベントログにその内容が表示されます。

以下の様に表示されます。

 

Comentarios (0)1
Inicie sesión o regístrese para continuar
InterSystems Official
· 11 feb, 2025

InterSystems Language Server 2.7 最新情報

開発者コミュニティのみなさま、2025年もよろしくお願いします!今年も素晴らしい製品やニュースをみなさまにお届けいたします。本日は VS Code の InterSystems Language Server 拡張機能の最新バージョンをご紹介します。Language Server 拡張機能の多くは、ObjectScript 拡張機能を通じてご提供することが多いです。そのため、コード補完機能やホバー機能といった、2024年に追加された Language Server 拡張機能の新機能には、なかなか気づきにくいかもしれません。ぜひ Language Server 変更履歴 で、見逃していたかもしれない新機能がないかご確認ください。最新バージョン2.7.0では、Windows ARMプラットフォームがサポートされたので、Surface Pro 11 (私はこの記事をウキウキしながら書いています) のようなデバイスをお持ちの方は、お使いのマシンで素晴らしい ObjectScript 開発を体験いただけます。Language Server 拡張機能をお試しいただき、何かありましたらぜひコメントをお寄せくださいませ。お待ちしております。

Comentarios (0)0
Inicie sesión o regístrese para continuar
Artículo
· 11 feb, 2025 Lectura de 2 min

第二十一章 P 开头的术语

第二十一章 P 开头的术语

主持久超类 (primary persistent superclass)

对象(Objects)

一个类的主要持久超类决定了该类的持久行为。默认情况下,主要持久超类是超类列表中最左侧的持久超类。通常,与相同主要持久超类相关联的类的所有数据一起存储。

主卷 (primary volume)

系统

卷集中的第一个卷或唯一卷。

主设备 (principal device)

系统

与进程相关联的输入/输出设备,通常是终端或计算机键盘和显示器。对于后台进程,你可以在 JOB 命令中分配主设备,或者在系统配置编辑器中将其设置为父进程的主设备。如果不以这些方式设置设备,则后台进程的默认设备是空设备(null device)。

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 11 feb, 2025 Lectura de 8 min

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris - Parte 3 – REST e Interoperabilidade

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris

Parte 3 – REST e Interoperabilidade

Agora que finalizamos a configuração do Gateway SQL e conseguimos acessar os dados do banco externo via python, e montamos nossa base vetorizada, podemos realizar algumas consultas. Para isso nessa parte do artigo vamos utilizar uma aplicação que desenvolvida com CSP, HTML e Javascript que acessará uma integração no Iris, que então realiza a pesquisa por similaridade dos dados, faz o envio para a LLM e por fim devolve o SQL gerado. A página CSP chama uma API no Iris que recebe os dados a serem utilizados na consulta, chamando a integração. Para mais informações sobre REST nop Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

A seguir o código da API REST criada:

Class Rest.Vector Extends %CSP.REST
{

XData UrlMap
{
<Routes>
        <Route Url="/buscar" Method="GET" Call="Buscar"  Cors="true"/>
    </Routes>
}

ClassMethod Buscar() As %Status
{
    set arg1 = %request.Get("arg1")
    set sessionID = %request.Get("sessionID")
    Set saida = {}
    Set obj=##Class(ws.rag.msg.Request).%New()
    Set obj.question=arg1
    Set obj.sessionId=sessionID
    Set tSC=##Class(Ens.Director).CreateBusinessService("ws.rag.bs.Service",.tService)
    If tSC
    {
                  Set resp=tService.entrada(obj)
    } Else {
                  Set resp=##Class(ws.rag.msg.Response).%New()
                  Set resp.resposta=$SYSTEM.Status.GetErrorText(tSC)
    }
    Set saida = {}
    Set saida.resposta=resp.resposta
    Set saida.sessionId=sessionID // Devolve o SessionId que chegou
    //
    Write saida.%ToJSON()
    Quit $$$OK
}

}

Uma vez criado o código da API REST precisamos criar a configuração da aplicação no Portal de Administração->Administração do Sistema->Segurança->Aplicações Web:

Na aplicação CSP, em Javascript, temos então a chamada da API:

...

async function chamaAPI(url, sessionID)

    var div = document.getElementById('loader');
    div.style.opacity=1;
    fetch(url)
         .then(response => {
               if (!response.ok) {
                     throw new Error('Erro na resposta da API');
               }
              return response.json();
         })
        .then(data => {
               incluiDIVRobot(data.resposta, data.sessionID);
        })
       .catch(error => {
               incluiDIVRobot('Erro na chamada da API:: ' + error, sessionID);
       });
 }

//

 const url = 'http://' + 'localhost' + '/api/vector/buscar?arg1=' + texto + '&sessionID=' + sessionID;
 chamaAPI(url, sessionID);

...

A aplicação CSP então recebe como entrada a solicitação do usuário (por exemplo: “qual a menor temperatura registrada?”) e chama a API REST.

 

A API REST por sua vez chama uma integração no Iris composta de Service, Process e Operation. Na camada de Operation temos a chamada a LLM, que é feita por um método em python de uma classe. Vendo o trace da integração podemos verificar o processo todo ocorrendo.

Para mais informações sobre o uso de produções no Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

Abaixo os códigos utilizados nas camadas de BS, BP e BO:

A seguir o código do BS (Service):

Class ws.rag.bs.Service Extends Ens.BusinessService
{

Parameter SERVICENAME = "entrada";

Method entrada(pInput As ws.rag.msg.Request) As ws.rag.msg.Response [ WebMethod ]
{
              Set tSC=..SendRequestSync("bpRag",pInput,.tResponse)
              Quit tResponse
}

}

E o código do BP (Process)

Class ws.rag.bp.Process Extends Ens.BusinessProcessBPL [ ClassType = persistent, ProcedureBlock ]
{

/// BPL Definition
XData BPL [ XMLNamespace = "http://www.intersystems.com/bpl" ]
{
<process language='objectscript' request='ws.rag.msg.Request' response='ws.rag.msg.Response' height='2000' width='2000' >
<sequence xend='200' yend='350' >
<call name='boRag' target='boRag' async='0' xpos='200' ypos='250' >
<request type='ws.rag.msg.Request' >
<assign property="callrequest" value="request" action="set" languageOverride="" />
</request>
<response type='ws.rag.msg.Response' >
<assign property="response" value="callresponse" action="set" languageOverride="" />
</response>
</call>
</sequence>
</process>
}

Storage Default
{
<Type>%Storage.Persistent</Type>
}

}

 

E o código do BO (Operation):

 

Class ws.rag.bo.Operation Extends Ens.BusinessOperation [ ProcedureBlock ]
{

Method retrieve(pRequest As ws.rag.msg.Request, Output pResponse As ws.rag.msg.Response) As %Library.Status
{
 Set pResponse=##Class(ws.rag.msg.Response).%New()
 Set pResponse.status=1
 Set pResponse.mensagem=”OK”
 Set pResponse.sessionId=..%SessionId
 Set st=##Class(Vector.Util).RetrieveRelacional(“odbc_work”,pRequest.question,pRequest.sessionId)
 Set pResponse.resposta=st
 Quit $$$OK
}

XData MessageMap
{
<MapItems>
<MapItem MessageType=”ws.rag.msg.Request”>
 <Method>retrieve</Method>
 </MapItem>
</MapItems>
}

}

 

Na sequencia, as classes de Request e Response da integração:


Request:

 

Class ws.rag.msg.Request Extends Ens.Request
{

Property collectionName As %String;

Property question As %String(MAXLEN = "");

Property sessionId As %String;

}

 

Response:

 

Class ws.rag.msg.Response Extends Ens.Response
{

Property resposta As %String(MAXLEN = "");

Property status As %Boolean;

Property mensagem As %String(MAXLEN = "");

Property sessionId As %Integer;

 

}

 

E a classe da Production:

Class ws.rag.Production Extends Ens.Production
{

XData ProductionDefinition
{
<Production Name="ws.rag.Production" LogGeneralTraceEvents="false">
  <Description>Produção do Rag DEMO</Description>
  <ActorPoolSize>2</ActorPoolSize>
  <Item Name="ws.rag.bs.Service" Category="rag" ClassName="ws.rag.bs.Service" PoolSize="0" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
  <Item Name="bpRag" Category="rag" ClassName="ws.rag.bp.Process" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
  <Item Name="boRag" Category="rag" ClassName="ws.rag.bo.Operation" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
</Production>
}

}

 

 

 

 

Ao ser executada a integração mantém os Requests e Responses armazenados permitindo a rastreabilidade no barramento, conforme vemos no trace a seguir:

 

Podemos ver no trace, por exemplo, que o tempo que a chamada a LLM levou para enviar os dados e devolver o SQL solicitado foi de aproximadamente 10s:

Podemos ver o retorno do BO após tratar a resposta da LLM no código python, para o nosso questionamento:

Assim, através da rastreabilidade da camada de interoperabilidade do Iris, podemos ver todo o fluxo de informação trafegado, os tempos decorridos, eventuais falhas e se for o caso, reprocessar alguma chamada, caso necessário.

A chamada do BO ao método em python passa a solicitação feita pelo usuário. O código em python através da busca vetorial encontra os registros mais semelhantes e os envia a LLM junto com a solicitação do usuário (no caso o modelo da nossa tabela), o histórico de conversa (se existir) e o prompt que são as orientações para balizar a atuação da LLM.

A LLM então gera o SQL que é devolvido ao método em python. O código então executa o SQL e formata a resposta para o padrão esperado, criando as listas de apresentação, gráficos ou downloads de acordo com o retorno aguardado pelo usuário.

Assim, através da aplicação CSP criada, podemos solicitar várias informações, como por exemplo, tabelas de respostas:

Ou gráficos:

Ou ainda, o download de informações:

Para o download, baixando e abrindo o arquivo temos os dados solicitados:

Estes exemplos mostram a leitura dos dados da tabela externa com o Gateway SQL do Iris e o seu uso com código escrito em python. Desta forma podemos utilizar todo o potencial dos dados, que não precisam estar armazenados dentro do Iris. Imagine poder montar uma estação de análise que colete dados de diversos sistemas e dê como resposta informações para tomada de decisão.

Podemos, por exemplo, ter dashboards visualizando dados dos diversos ambientes que compõem o ecossistema de uma empresa, previsões baseadas em algoritmos de ML, RAG para facilitar o levantamento de dados e muito mais.

O Iris pode ser o responsável por acessar, tratar e disponibilizar os dados dos diversos ambientes, com controle, segurança e rastreabilidade, graças às características de interoperabilidade, podendo utilizar código em COS e python, e ser acessado através de códigos em R, C, Java e muito mais. E tudo isso dentro do mesmo produto e sem a necessidade de duplicar ou mover dados entre ambientes.

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 11 feb, 2025 Lectura de 7 min

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris - Parte 2 – Python e Vector Search

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris

Parte 2 – Python e Vector Search

Uma vez que temos acesso aos dados da nossa tabela externa podemos utilizar tudo que o Iris tem de excelente com estes dados. Vamos, por exemplo, ler os dados da nossa tabela externa e gerar uma regressão polinomial com eles.

Para mais informações sobre o uso do python com o Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_epython

Vamos agora então consumir os dados do banco externo para calcular uma regressão polinomial. Para isso vamos através de um código em python executar um SQL que lerá nossa tabela do MySQL e transformará ela em um dataframe pandas:

ClassMethod CalcularRegressaoPolinomialODBC() As %String [ Language = python ]
{
    import iris
    import json
    import pandas as pd
    from sklearn.preprocessing import PolynomialFeatures
    from sklearn.linear_model import LinearRegression
    from sklearn.metrics import mean_absolute_error
    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt
    matplotlib.use("Agg")

    # Define Grau 2 para a regressão
    grau = 2
    
    # Recupera dados da tabela remota via ODBC
    rs = iris.sql.exec("select venda as x, temperatura as y from estat.fabrica")
    df = rs.dataframe()
   
    # Reformatando x para uma matriz 2D exigida pelo scikit-learn
    X = df[['x']]
    y = df['y']
    
    # Transformação para incluir termos polinomiais
    poly = PolynomialFeatures(degree=grau)
    X_poly = poly.fit_transform(X)

    # Inicializa e ajusta o modelo de regressão polinomial
    model = LinearRegression()
    model.fit(X_poly, y)

    # Extrai os coeficientes do modelo ajustado
    coeficientes = model.coef_.tolist()  # Coeficientes polinomiais
    intercepto = model.intercept_       # Intercepto
    r_quadrado = model.score(X_poly, y) # R Quadrado

    # Previsão para a curva de regressão
    x_pred = np.linspace(df['x'].min(), df['x'].max(), 100).reshape(-1, 1)  # Valores para a curva de regressão
    x_pred_poly = poly.transform(x_pred)  # Transformando para base polinomial
    y_pred = model.predict(x_pred_poly)
    
    # Calcula Y_pred baseado no X
    Y_pred = model.predict(X_poly)
            
    # Calcula MAE
    MAE = mean_absolute_error(y, Y_pred)
    
    # Geração do gráfico da Regressão
    plt.figure(figsize=(8, 6))
    plt.scatter(df['x'], df['y'], color='blue', label='Dados Originais')
    plt.plot(df['x'], df['y'], color='black', label='Linha dos Dados Originais')
    plt.scatter(df['x'], Y_pred, color='green', label='Dados Previstos')
    plt.plot(x_pred, y_pred, color='red', label='Curva da Regressão Polinomial')
    plt.title(f'Regressão Polinomial (Grau {grau})')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.legend()
    plt.grid(True)

    # Salvando o gráfico como imagem
    caminho_arquivo = 'c:\\temp\\RegressaoPolinomialODBC.png'
    plt.savefig(caminho_arquivo, dpi=300, bbox_inches='tight')
    plt.close()
    
    resultado = {
        'coeficientes': coeficientes,
        'intercepto': intercepto,
        'r_quadrado': r_quadrado,
        'MAE': MAE
    }

    return json.dumps(resultado)
}

A primeira ação que realizamos no código é a leitura os dados da nossa tabela externa via SQL e então os transformamos em um dataframe Pandas. Sempre lembrando que os dados estão fisicamente armazenados no MySQL e são acessados via ODBC através do Gateway SQL configurado no Iris. Com isso podemos utilizar as bibliotecas do python para cálculo e gráfico, conforme vemos no código.

Executando nossa rotina temos as informações do modelo gerado:

Nossa rotina também gera um gráfico que nos dá um suporte visual para a regressão polinomial. Vamos ver como o gráfico ficou:

Outra ação que podemos realizar com os dados que agora estão disponíveis é o uso do Vector Search e RAG com o uso de uma LLM. Para isso vamos vetorizar o modelo da nossa tabela e a partir daí pedir algumas informações a LLM.

Para mais informações sobre o uso de Vector Search no Iris veja o texto disponível em https://www.intersystems.com/vectorsearch/

Primeiro vamos vetorizar o modelo da nossa tabela. Abaixo o código com o qual realizamos esta tarefa:

ClassMethod IngestRelacional() As %String [ Language = python ]
{

    import json
    from langchain_iris import IRISVector
    from langchain_openai import OpenAIEmbeddings
    from langchain_text_splitters import RecursiveCharacterTextSplitter
    import iris    

    try:
    
        apiKey = iris.cls("Vector.Util").apikey()
        collectionName = "odbc_work"

        metadados_tabelas = [
            "Tabela: estat.fabrica; Colunas: chave(INT), venda(INT), temperatura(INT)"
        ]
        
        text_splitter = RecursiveCharacterTextSplitter(chunk_size=2048, chunk_overlap=0)
        documents=text_splitter.create_documents(metadados_tabelas)
            
        # Vetorizar as definições das tabelas
        vectorstore = IRISVector.from_documents(
        documents=documents,
        embedding=OpenAIEmbeddings(openai_api_key=apiKey),
        dimension=1536,
        collection_name=collectionName
        )
        
        return json.dumps({"status": True})
    except Exception as err:
        return json.dumps({"error": str(err)})
}

 

Note que não passamos para o código de ingest o conteúdo da tabela, e sim seu modelo. Desta forma a LLM é capaz de, ao receber as colunas e suas propriedades, definir um SQL de acordo com nossa solicitação.

Este código de ingest cria a tabela odbc_work que será utilizada para fazer a busca por similaridade no modelo da tabela, e a seguir solicitar a LLM que devolva um SQL. Para isso criamos uma API KEY na OpenAI e utilizamos o langchain_iris como biblioteca python. Para mais detalhes sobre o langchain_iris veja o link https://github.com/caretdev/langchain-iris

Após realizar o ingest da definição da nossa tabela teremos a tabela odbc_work gerada:

Agora vamos a nossa terceira parte que é o acesso de uma API REST que vai consumir os dados que estão vetorizados para montar um RAG.

Até logo!

Comentarios (0)1
Inicie sesión o regístrese para continuar