Pesquisar

Artículo
· 9 hr atrás Lectura de 2 min

Se familiarizando com FHIR

🔥 Curioso sobre o padrão FHIR de que todo mundo está falando?

📚 Leia para uma breve introdução e, em seguida, experimente um novo caminho de aprendizado para adquirir conhecimento mais aprofundado!

  

O padrão HL7® FHIR® revolucionou a forma como os desenvolvedores da área de saúde enfrentam os desafios da interoperabilidade de dados. O FHIR permite que sistemas de saúde troquem informações de forma fluida, e os dados dos pacientes podem ser consolidados em tempo real, independentemente de onde estejam armazenados.

O FHIR é uma API REST que pode lidar com dados narrativos e codificados, e consiste em resources (recursos), que são essencialmente blocos de construção para diferentes conceitos de dados, como pacientes ou medicamentos. Os FHIR profiles também fornecem contexto e definem relações entre os elementos de dados, garantindo descrições consistentes entre sistemas, assim é fácil trocar informações e transmitir o significado correto.

Para ir além do básico, você pode usar FHIR Extensions para representar casos específicos que não são cobertos pelo padrão. É possível criar extensões e publicá-las em URLs públicas, para que qualquer pessoa recebendo dados com essas extensões possa descobrir o que elas significam.

E para facilitar ainda mais, existem os FHIR Implementation Guides. Esses guias contêm recursos perfilados, incluindo extensões, bindings de terminologia e conjuntos de valores específicos para um caso de uso particular. Eles fornecem documentação e exemplos de como utilizá-los, tornando mais fácil implementar o FHIR em suas aplicações. Além disso, são legíveis por máquina, permitindo validar suas aplicações FHIR e garantir que estejam corretas.

Pronto para mergulhar no mundo do FHIR? Acesse o site de aprendizado da InterSystems para experimentar o novo caminho de aprendizado no catálogo de aprendizado online Introduction to the FHIR Standard. 

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 9 hr atrás Lectura de 3 min

Dicas para lidar com grande volume de dados

Olá comunidade,

Quero compartilhar minha experiência trabalhando em projetos que lidam com um volume masivo de dados. Ao longo dos anos, tive a oportunidade de lidar com enormes volumes de dados de pacientes, dados de pagadores e logs transacionais enquanto trabalhava na indústria hospitalar. Tive a chance de criar relatórios enormes, que precisavam ser escritos usando lógicas avançadas para buscar dados em múltiplas tabelas, cujos índices não ajudavam a escrever código eficiente.

Aqui está o que aprendi sobre como gerenciar grandes volumes de dados de forma eficiente.

 

Escolhendo o melhor método de acesso aos dados

Como todos nós da comunidade sabemos, o IRIS oferece múltiplas maneiras de acessar dados. A escolha do método correto depende do requisito.

  • Acesso direto a global: o mais rápido para operações de leitura/gravação em massa. Por exemplo, se eu precisar percorrer índices e buscar dados de pacientes, posso percorrer as globais para processar milhões de registros. Isso economiza muito tempo.
Set ToDate=+H
Set FromDate=+$H-1 For  Set FromDate=$O(^PatientD("Date",FromDate)) Quit:FromDate>ToDate  Do
. Set PatId="" For  Set PatId=$Order(^PatientD("Date",FromDate,PatID)) Quit:PatId=""  Do
. . Write $Get(^PatientD("Date",FromDate,PatID)),!
  • Usando SQL: Útil para relatórios ou necessidades analíticas, embora seja mais lento para conjuntos de dados muito grandes.

Otimização de Operações em Lote

Processar milhões de registros um por um é lento e pesado. Para otimizar, descobri que salvar em lotes, usar globais temporárias para etapas intermediárias e dividir grandes tarefas em partes menores faz uma grande diferença. Desativar índices não essenciais durante inserções em massa também acelera o processo.

Usando Streams

Para textos grandes, XML ou payloads JSON, objetos Stream evitam sobrecarga de memória. Lidar com arquivos enormes pode consumir muita memória se carregarmos tudo de uma vez. Prefiro usar objetos Stream para ler ou escrever os dados em partes. Isso mantém o processo rápido e eficiente.

Set stream = ##class(%Stream.GlobalCharacter).%New()
Do stream.CopyFromFile("C:\Desktop\HUGEDATA.json")
w "Size: "_stream.Size(),!

Esta é uma forma simples de manipular os dados com segurança, sem deixar o sistema mais lento.

Então é isso. Lidar com grandes volumes de dados não é apenas sobre fazer as coisas rapidamente, mas sim sobre escolher a forma certa de acessar, armazenar e manter o sistema equilibrado de maneira inteligente.

Desde migrar milhões de registros de pacientes até construir APIs que lidam com conjuntos de dados bastante grandes, essas abordagens fizeram uma diferença real em termos de desempenho e manutenibilidade.

Se você está trabalhando com conceitos semelhantes e quer trocar ideias, sinta-se à vontade para entrar em contato. Estou sempre feliz em compartilhar o que funcionou para mim. Também estou aberto a feedbacks e às suas opiniões...

 

Obrigado!!! :-)

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 9 hr atrás Lectura de 5 min

Aprendendo ObjectScript como Desenvolvedor Iniciante: O Que Eu Gostaria de saber antes

Entrei na InterSystems há menos de um ano. Mergulhar em ObjectScript e no IRIS foi empolgante, mas também cheio de pequenas surpresas que me pegaram de surpresa no começo. Neste artigo, reúno os erros mais comuns que eu, e muitos colegas novos, cometemos, explico por que eles acontecem e mostro exemplos concretos e correções práticas. Meu objetivo é ajudar outros desenvolvedores iniciantes a economizarem tempo e evitarem os mesmos tropeços no caminho.

 

1. Se perder entre as classes de sistema e por onde começar

O problema: ObjectScript/IRIS vem com muitas classes e pacotes de sistema (%Library, %SYS, %Persistent, %SQL, etc.). Para um desenvolvedor iniciante, é difícil saber qual classe ou padrão se encaixa melhor em uma tarefa. Lembro de tentar encontrar uma classe persistente adequada e ficar em dúvida entre estender %Persistent ou usar uma classe do tipo registry.

Por que isso importa: Escolher a abordagem errada logo no início torna o código mais difícil de manter e se integra mal com os recursos do IRIS (índices, segurança, SQL).

Dica: Comece pela necessidade concreta (armazenar registros? expor via SQL? compartilhar objetos entre processos?) e então pesquise na Class Reference as capacidades relevantes (persistência, índices, coleções). Use o Studio ou a extensão da InterSystems para VS Code para navegar pelas classes de forma interativa e analisar exemplos.

 

2. Sobrecarga da documentação: não saber as palavras-chave certas

O problema: A documentação é bastante completa, mas, se você não conhece o nome correto da classe ou o termo adequado, as buscas retornam muitas páginas não relacionadas. No início, eu frequentemente gastava muito tempo porque ainda não conhecia os termos canônicos.

Por que isso importa: Você perde tempo e pode acabar implementando padrões que não são ideais.

Dica:

  • Pesquise na comunidade de desenvolvimento por exemplos práticos (busque por “persistent class example”, “ObjectScript transaction TSTART example”, etc.).
  • Use a extensão InterSystems para VS Code; ela permite navegar diretamente até as definições das classes.
  • Ao pesquisar na documentação, combine nomes de classes e ações, por exemplo: "%Persistent property index example"

3.  Esquecer  .. na chamada de métodos locais

O problema: Chamar um método da mesma classe sem .. resulta em a chamada não ser reconhecida  em tempo de execução.

Errado:

Class MyClass Extends %Persistent { 
   Method DoWork() 
   { 
       Do Hello()  // wrong: this is not a local method invocation
   } 
   Method Hello()
   { 
       Write "Hello", ! 
   } 
}

Correto:

Method DoWork() {
   Do ..Hello()  // correct: local method call 
}

Dica:  Quando você receber o erro “Unknown routine” para os métodos da sua classe, verifique se você está usando .. para chamadas dentro da mesma classe.

 

4. Confundir globais e variáveis locais

O problema: ObjectScript diferencia globais (persistentes entre sessões, por exemplo ^MyGlobal) e variáveis locais (em memória, com escopo limitado). Desenvolvedores iniciantes frequentemente usam uma quando a intenção era usar a outra.

SET localVar = 10    // exists only during the current process/session
SET ^globalVar = 20  // persists in the database across processes and sessions

Dica: Use classes persistentes para dados que precisam ser armazenados a longo prazo. Limite o uso de globais a necessidades muito específicas de baixo nível ou apenas quando você entender bem as consequências.

 

5. Utilizar globais diretamente em vez de usar classes persistentes

O problema: Meu instinto inicial foi o “rápido e sujo”: escrever diretamente em ^MyGlobal. Isso funciona, mas ignora os benefícios baseados em classes: esquema, índices, acesso via SQL e segurança.

Melhor abordagem:

Class Person Extends %Persistent 
{ 
    Property Name As %String; 
    Property DOB As %Date; 
}

Dica: Prefira classes %Persistent para os dados da aplicação. Elas oferecem um modelo mais limpo e se integram com SQL e índices.

 

6. Ignorar transações (TSTART / TCOMMIT)

O problema: Desenvolvedores às vezes realizam várias gravações pensando que são atômicas. Sem o controle explícito de transações, falhas parciais podem deixar os dados inconsistentes.

TSTART 
// multiple updates 
TCOMMIT

Dica: Identifique unidades lógicas de trabalho e envolva-as em transações. Se algo puder falhar no meio do processo, use TSTART / TROLLBACK / TCOMMIT. Lembre-se de que o IRIS suporta transações aninhadas: múltiplas chamadas a TSTART aumentam o nível da transação, e todos os níveis devem ser confirmados (TCOMMIT) ou revertidos (TROLLBACK) antes que as alterações se tornem definitivas.

 

7. Entender mal as opções de SQL: SQL Embutido vs %SQL.Statement

O problema: SQL embutido (blocos UPDATE, SELECT dentro do ObjectScript) e a API %SQL.Statement estão disponíveis; escolher sem conhecer os prós e contras pode gerar código confuso.

Orientação: Use SQL embutido para consultas fixas/estáticas dentro de rotinas; use %SQL.Statement quando precisar construir e executar SQL de forma dinâmica.

 

8. Ignorar o tratamento adequado de erros

O problema: Não usar TRY/CATCH ou sinalizar erros corretamente torna a depuração e a confiabilidade do código mais difíceis.

TRY 
{ 
   // code that may fail 
} CATCH ex 
{  
   Write "Error: ", ex.DisplayString(),! 
}

Dica: Envolva operações de risco (I/O, chamadas externas, SQL dinâmico) com manipuladores de erro e registre mensagens informativas.

 

Notas finais
No início, eu escrevia em globais por conveniência e depois passei um tempo refatorando para classes persistentes. Essa refatoração me ensinou o valor de projetar os modelos de dados desde o início e usar as ferramentas que o IRIS oferece. Meus melhores hábitos agora: pequenos experimentos, buscas frequentes na comunidade e manter transações e tratamento de erros em mente desde o começo.

Se você é iniciante: trate suas primeiras tarefas como experimentos, crie pequenas classes persistentes, teste SQL Embutido simples e use o Management Portal e o navegador do VS Code para inspecionar as classes de sistema. Faça perguntas na comunidade; muitos outros também passaram pelas mesmas “pegadinhas”.

Para mais informações: consulte a documentação oficial do ObjectScript e a comunidade de desenvolvimento para exemplos e padrões.

Este artigo foi revisado e editado com o auxílio de ferramentas de IA para melhorar a clareza e a gramática. As experiências e sugestões descritas são de minha autoria.

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 10 hr atrás Lectura de 2 min

Adaptador de Arquivo Personalizado – Tabela de Consulta / Arquivos Dinâmicos

Meu problema era separar mensagens HL7 por tipo de mensagem. Eu precisava criar várias Operações de Arquivo. Com código personalizado, consegui usar 1 adaptador de arquivo para 1 interface e vários tipos de mensagem. Cheguei a experimentar extrair o MSH-4 do conteúdo bruto para acessar informações dinâmicas adicionais, mas isso pode trazer a necessidade de verificações de erro mais robustas e/ou ações padrão de consulta.

Seguindo a convenção de nomenclatura recomendada de "To_FILE_<IntegrationName>"

Eu decidi usar um nome e um caminho de arquivo genéricos nas configurações padrão.

Criei uma classe personalizada que estende EnsLib.File.OutboundAdapter, com um código customizado que me permite controlar dinamicamente o caminho do adaptador de arquivo específico para cada tipo de mensagem por meio de uma tabela de consulta (lookup table). Se eu não tiver um valor definido, o caminho genérico padrão será utilizado. Caso contrário, meu código sobrescreve o caminho e o nome do arquivo. O nome da lookup table pode ser qualquer um, desde que corresponda ao que está definido no código.


 

Código customizado

//SRC1 Extrair a 3ª parte do nome da operação de saída "<IntegrationName>"

//SRC2 Extrair a 1ª parte do NOME DO DOCTYPE "ORM" / "ADT" / "ORU" / etc.

// Definir uma nova variável SRC para concatenar SRC1_SRC2 juntos

//Nova tabela de lookup que irá controlar os nomes dos caminhos em um único lugar.

 

Set src1=$PIECE(..%ConfigName,"_",3,3)
Set src2=$PIECE(pDocument.DocTypeName,"_",1,1)
If src=""
{
Set src=src1_"_"_src2
} Set pFilename = ..Adapter.CreateFilename(##class(%File).GetFilename(src), $PIECE((##class(Ens.Rule.FunctionSet).Lookup("HL7FileNamePath",src)),"^",2,2)_..Filename) $$$TRACE(pFilename)
//Reset file path to return a file path based on the Lookup and PIECE function(s)
Set ..Adapter.FilePath =$PIECE((##class(Ens.Rule.FunctionSet).Lookup("HL7FileNamePath",src)),"^",1,1)
$$$TRACE(..Adapter.FilePath)
Set tSC = ..Adapter.open(pFilename) Quit:$$$ISERR(tSC) tSC
Set $ZT="Trap"
Use ..Adapter.Device  Set tSC=..OutputFramedToDevice(pDocument,pSeparators,"",0,..IOLogEntry,.pDoFraming) Use ..Adapter.OldIO
Set $ZT=""

Comentarios (0)1
Inicie sesión o regístrese para continuar
Artículo
· 10 hr atrás Lectura de 3 min

Minificando XML no IRIS

Em um projeto em que estou trabalhando, precisamos armazenar alguns XMLs arbitrários no banco de dados. Esse XML não tem nenhuma classe correspondente no IRIS; precisamos apenas armazená-lo como uma string (ele é relativamente pequeno e cabe em uma string).
Como existem MUITOS (milhões!) de registros no banco de dados, decidi reduzir o tamanho o máximo possível sem usar compressão. Sei que parte do XML a ser armazenado está indentada, parte não, isso varia.

Para reduzir o tamanho, decidi minificar o XML, mas como minificar um documento XML no IRIS?
Pesquisei em todas as classes e utilitários e não encontrei nenhum código ou método pronto, então tive que implementar por conta própria, e acabou sendo bem simples no IRIS usando a classe %XML.TextReader, sinceramente, mais simples do que eu esperava.

Como isso pode ser útil em outros contextos, decidi compartilhar esse pequeno utilitário com a Comunidade de Desenvolvedores.
Testei com alguns documentos XML relativamente complexos e funcionou bem, segue o código.

/// Minify an XML document passed in the XmlIn Stream, the minified XML is returned in XmlOut Stream
/// If XmlOut Stream is passed, then the minified XML is stored in the passed Stream, otherwise a %Stream.TmpCharacter in returned in XmlOut.
/// Collapse = 1 (default), empty elements are collapsed, e.g. <tag></tag> is returned as <tag/>
/// ExcludeComments = 1 (default), comments are not returned in the minified XML
ClassMethod MinifyXML(XmlIn As %Stream, ByRef XmlOut As %Stream = "", Collapse As %Boolean = 1, ExcludeComments As %Boolean = 1) As %Status
{
	#Include %occSAX
	Set sc=$$$OK
	Try {
		Set Mask=$$$SAXSTARTELEMENT+$$$SAXENDELEMENT+$$$SAXCHARACTERS+$$$SAXCOMMENT
		Set sc=##class(%XML.TextReader).ParseStream(XmlIn,.reader,,$$$SAXNOVALIDATION,Mask)
		#dim reader as %XML.TextReader
		If $$$ISERR(sc) Quit
		If '$IsObject(XmlOut) {
			Set XmlOut=##class(%Stream.TmpCharacter).%New()
		}
		While reader.Read() {
			Set type=reader.NodeType
			If ((type="error")||(type="fatalerror")) {
				Set sc=$$$ERROR($$$GeneralError,"Error loading XML "_type_"-"_reader.Value)
				Quit
			}
			If type="element" {
				Do XmlOut.Write("<"_reader.Name)
				If Collapse && reader.IsEmptyElement {
					; collapse empty element
					Do XmlOut.Write("/>")
					Set ElementEnded=1
				} Else {
					; add attributes
					For k=1:1:reader.AttributeCount {
						Do reader.MoveToAttributeIndex(k)
						Do XmlOut.Write(" "_reader.Name_"="""_reader.Value_"""")
					}
					Do XmlOut.Write(">")
				}
			} ElseIf type="chars" {
				Set val=reader.Value
				Do XmlOut.Write($select((val["<")||(val[">")||(val["&"):"<![CDATA["_$replace(val,"]]>","]]]]><![CDATA[>")_"]]>",1:val))
			} ElseIf type="endelement" {
				If $g(ElementEnded) {
					; ended by collapsing
					Set ElementEnded=0
				} Else {
					Do XmlOut.Write("</"_reader.Name_">")
				}
			} ElseIf 'ExcludeComments && (type="comment") {
				Do XmlOut.Write("<!--"_reader.Value_"-->")
			}
		}
	} Catch CatchError {
		#dim CatchError as %Exception.SystemException
		Set sc=CatchError.AsStatus()
	}
	Quit sc
}

P.S.: Alguém sabe se existe outra forma mais simples de minificar XML no IRIS?

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