#Message Search

0 Followers · 48 Posts

All communication within an InterSystems Ensemble production is accomplished with messages. InterSystems Ensemble provides many tools for viewing and working with messages.

Documentation

Question Colin Brough · Oct 3, 2025

Is there any way of saving a representation of the results of a query created in the Message Viewer to a file - most obviously CSV.

We are reasonably adept at creating queries. We'd like to be able to send the output to a file, rather than resorting to cut'n'pasting from the message viewer window...

Is this possible? (on any version of Ensemble/Iris?)

Desired output to file something like:

ID,TimeCreated,Session,Status,Error,Source,Target,Body_MSH_MessageControlId,.....
1,8888888,2025-08-20 05:03:14.324,8438123,Completed,OK,ICE ADT Validator,ICE ADT TCP,1z123456,20220822......
13
0 130
Article Timothy Scott · Feb 28, 2025 7m read

High-Performance Message Searching in Health Connect

The Problem

Have you ever tried to do a search in Message Viewer on a busy interface and had the query time out? This can become quite a problem as the amount of data increases. For context, the instance of Health Connect I am working with does roughly 155 million Message Headers per day with 21 day message retention. To try and help with search performance, we extended the built-in SearchTable with commonly used fields in hopes that indexing these fields would result in faster query times. Despite this, we still couldn't get some of these queries to finish at all.

More Info Defining a Search Table Class.

image

For those of us working as HL7 integrators, we know that troubleshooting and responding to issues on a day-to-day basis is a huge part of our role. Quickly identifying and resolving these issues is critical to ensuring that we are maintaining the steady and accurate flow of data. Due to the poor search performance, we would have to gather very detailed information about each specific issue to find examples in Health Connect. Without a very narrow time frame (within a few minutes), we often were unable to get Message Viewer search to return any results before timing out. This caused a significant delay both in determining what the actual problem was and resolving it moving forward.

The Solution

This was not acceptable, so we had to find a solution in order to best serve our customers. Enter WRC.

image

We created a ticket, and I am happy to report a fix was identified. This fix involved going through our custom SearchTable fields and identifying which fields were not unique enough to warrant being treated as an index by the Message Viewer search.

For example, in our environment, MSH.4 (or FacilityID) is used to denote which physical hospital location the HL7 message is associated with. While this field is important to have on the SearchTable for ease of filtering, many messages come through each day for each facility. This means that it is inefficient to use this field as an index in the Message Viewer search. Counter to this would be a field like PID.18 (or Patient Account Number). The number of messages associated with each account number is very small, so using this field as an index greatly increases the speed of the search.

Adding the Unselective parameter to the appropriate items tells message search which ones to treat as indexes. This in essence modifies the SQL used to pull the messages. Below you will find the difference in queries, based on fields being used as index or not, and how you can use these queries to determine which fields should be Unselective.

Index vs NoIndex Queries

Unselective="false" (Indexed) SQL Query Plan

image

This query is looping over the SearchTable values and, for each row, cross-referencing the MessageHeader table. For a value that is unique and doesn’t have many messages associated with it (i.e. Patient Account Number), this is more efficient.

Unselective="true" (%NOINDEX) SQL Query Plan

image

This query is looping over the MessageHeader table and, for each row, cross-referencing the SearchTable values. For a value that has many results associated with it (i.e. FacilityID), this method is faster to return the results.

How to Identify Problem Fields

The best way I have found to identify which fields need to be marked as Unselective is with Show Query. Create a separate search using each field in Message Viewer (adding the SearchTable field via Add Criterion) then click Show Query to show you the actual SQL being used by Message Viewer to pull the messages based on the filters selected.

image

Our first example is using a field from the SearchTable that does not have the Unselected parameter added. Notice the EnsLib_HL7.SearchTable.PropId = 19 and EnsLib_HL7.SearchTable.PropValue = '2009036'. This indicates the SearchTable field added as a filter and what value is being checked. Keep in mind that the ProdId will be unique to each search table field and may change from environment to environment.

image

How to Add Show Query to Message Viewer

If you don’t have the Show Query button enabled in Message Viewer, you can set the following Global in your given namespace.

set ^Ens.Debug("UtilEnsMessages","sql")=1

Viewing the SQL Query Used by the Message Viewer

SQL - Unselective=“false”

SELECT TOP 100 
head.ID As ID, {fn RIGHT(%EXTERNAL(head.TimeCreated),999 )} As TimeCreated, 
head.SessionId As Session, head.Status As Status, 
CASE head.IsError 
WHEN 1 
THEN 'Error' ELSE 'OK' END As Error, head.SourceConfigName As Source, 
head.TargetConfigName As Target, head.SourceConfigName, head.TargetConfigName, 
head.MessageBodyClassName As BodyClassname, 
(SELECT LIST(PropValue) 
FROM EnsLib_HL7.SearchTable 
WHERE (head.MessageBodyId = DocId) And PropId=19) As SchTbl_FacilityID, 
EnsLib_HL7.SearchTable.PropId As SchTbl_PropId 
FROM Ens.MessageHeader head, EnsLib_HL7.SearchTable 
WHERE (((head.SourceConfigName = 'component_name' OR head.TargetConfigName = 'component_name')) 
AND head.MessageBodyClassName=(('EnsLib.HL7.Message')) 
AND (head.MessageBodyId = EnsLib_HL7.SearchTable.DocId) 
AND EnsLib_HL7.SearchTable.PropId = 19 AND EnsLib_HL7.SearchTable.PropValue = '2009036') 
ORDER BY head.ID Desc

Next, take that query into SQL and manually modify it to add %NOINDEX. This is what is telling the query to not treat this value as an index.

SQL - Unselective=”true” - %NOINDEX

SELECT TOP 100 
head.ID As ID, {fn RIGHT(%EXTERNAL(head.TimeCreated),999 )} As TimeCreated, 
head.SessionId As Session, head.Status As Status, 
CASE head.IsError 
WHEN 1 
THEN 'Error' ELSE 'OK' END As Error, head.SourceConfigName As Source, 
head.TargetConfigName As Target, head.SourceConfigName, head.TargetConfigName, 
head.MessageBodyClassName As BodyClassname, 
(SELECT LIST(PropValue) 
FROM EnsLib_HL7.SearchTable 
WHERE (head.MessageBodyId = DocId) And PropId=19) As SchTbl_FacilityID, 
EnsLib_HL7.SearchTable.PropId As SchTbl_PropId 
FROM Ens.MessageHeader head, EnsLib_HL7.SearchTable 
WHERE (((head.SourceConfigName = 'component_name' OR head.TargetConfigName = 'component_name')) 
AND head.MessageBodyClassName='EnsLib.HL7.Message' 
AND (head.MessageBodyId = EnsLib_HL7.SearchTable.DocId) 
AND EnsLib_HL7.SearchTable.PropId = 19 AND %NOINDEX EnsLib_HL7.SearchTable.PropValue = (('2009036'))) 
ORDER BY head.ID Desc

If there is a significant difference in the amount of time needed to return the first and second queries, then you have found a field that should be modified. In our case, we went from queries timing out after a few minutes to an almost instantaneous return.

Applying the Fix - Modifying Your Code

Once you have identified which fields need to be fixed, you can add the Unselective="true" to each affected Item in your custom SearchTable class. See the below example.

Custom SearchTable Class

/// Custom HL7 Search Table adds additional fields to index.
Class CustomClasses.SearchTable.CustomSearchTable Extends EnsLib.HL7.SearchTable
{

XData SearchSpec [ XMLNamespace = "http://www.intersystems.com/EnsSearchTable" ]
{
<Items>
		// Increase performance by setting Unselective="true" on fields that are not highly unique.
		// This essentially tells Message Search to not use an index on these fields.

		// facility ID in MSH.4
   		<Item DocType=""	PropName="FacilityID" Unselective="true">		[MSH:4]		</Item>
   		// Event Reason in EVN.4
   		<Item DocType=""	PropName="EventReason" Unselective="true">		[EVN:4]		</Item>
   		// Patient Account (Add PV1.19 to prebuilt PID.18 search)
   		<Item DocType=""	PropName="PatientAcct">		[PV1:19]	</Item>
   		// Document type
   		<Item DocType=""	PropName="DocumentType" Unselective="true">	[TXA:2]		</Item>
   		// Placer Order ID
   		<Item DocType=""	PropName="PlacerOrderID">	[OBR:2.1]	</Item>
   		// Filler Order ID
   		<Item DocType=""	PropName="FillerOrderID">	[OBR:3.1]	</Item>
   		// Universal Service ID
   		<Item DocType=""	PropName="ServiceID" Unselective="true">		[OBR:4.1]	</Item>
   		// Universal Service ID
   		<Item DocType=""	PropName="ProcedureName" Unselective="true">	[OBR:4.2]	</Item>		
   		// Diagnostic Service Section
   		<Item DocType=""	PropName="ServiceSectID" Unselective="true">	[OBR:24]	</Item>
   		// Appointment ID
   		<Item DocType=""	PropName="AppointmentID">	[SCH:2]		</Item>
   		// Provider Fields
   		<Item DocType=""	PropName="ProviderNameMFN">	[STF:3()]		</Item>
   		<Item DocType=""	PropName="ProviderIDsMFN">	[MFE:4().1]		</Item>
   		<Item DocType=""	PropName="ProviderIDsMFN">	[STF:1().1]		</Item>
   		<Item DocType=""	PropName="ProviderIDsMFN">	[PRA:6().1]		</Item>
	</Items>
}

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

}

Summary

Quick message searching is vital to day-to-day integration operations. By utilizing the Unselective property, it is now possible to maintain this functionality, despite an ever-growing database. With this quick and easy-to-implement change, you will be back on track to confidently providing service and troubleshooting issues in your Health Connect environment.

1
8 219
Question Yone Moreno Jiménez · Feb 28, 2025

Good morning,

We need your help:

We wonder if there is a way to filter EnsLib.DICOM.Document, by using its DataSet properties on the Message Viewer.

For example, we would like to find the following DICOM.Document which DataSet.AccessionNumber is SR115985013100

By using the Message Viewer Filter we have tried the following:

FixedDataSet.AccessionNumber = SR115985013100

Because when we look fod a Body Property of the EnsLib.DICOM.Document it shows this drop down menu:

However, it replies with an error:

3
0 132
Question Victor Castanon · Jul 9, 2025

I'm trying to gather more data for one of my namespaces so I can do some analysis. However when I run .BuildIndex() nothing populates in the resulting SQL table. I've tried deleting the class and reimporting and compiling and still nothing. I feel like I'm doing something OBVIOUS that's wrong but I can't quite figure out what it is. Here's what I'm doing (Customer name redacted)
 

3
0 74
Job Ying Zhang · Jul 8, 2025

I am seeking work with InterSystems HealthConnect/Cache. My experience is working with Rules and DTLs, plus message search, and export of components.With 10 years of dedicated expertise in SOA and ESB platform development, I have successfully designed and implemented enterprise-level integration solutions for large organizations, driving significant improvements in system interoperability and business efficiency.I have actively developed and supported HL7 V2/V3 、FHIR、XML/JSON interfaces.I reside in China. Available for full-time or contract positions, with remote work options preferred.The

0
0 67
Question Mark OReilly · Aug 30, 2024

As part of fully decoupling code we send a snapshot from a business service (running a SQL statement). 

sql service                         Processor                                File Out

This is picked up by a processer and puts it into a file .txt. 

Issue is if you open it up via the SQL.snapshot message as this is 46,819 rows it'll take too long to respond to opening up the sql.snapshot in the message viewer when viewing the session if looking from the business service 

Is there any way to not have this xml open up in full in the portal? I.e. have a see more? 

3
0 178
Question prashanth ponugoti · Oct 23, 2024

Hello Experts ,

Could you help to search message details based on MRN in intersytems iris. 

We have created 100+ interfaces and currenly in live (interystems cloud) . Now I try to search message details based on MRN using below query. it is working fine in DEV. but in prod it is taking ages.

SELECT Header.SessionId, Header.SourceConfigName ,Body.RawContent
FROM Ens.MessageHeader AS Header 
JOIN EnsLib_HL7.Message AS Body ON Header.MessageBodyId = Body.ID     
 where  Body.TimeCreated BETWEEN '2023-03-15 13:10:22.993' AND '2023-03-15 13:10:25.993'
 AND Body.RawContent LIKE '%40103262%'

2
0 148
Question Martin Staudigel · Sep 27, 2024

Hello community

I sent a http post message with a large message body (approx. 200 kB) to a standard EnsLib.REST.GenericService using a standard EnsLib.HTTP.InboundAdapter.

When inspecting the message in the message viewer I expected to see a HTTPMessage XML in the Contents preview, but I found a GenericMessage with no HTTPHeaders section. After a while, I found out that the display in the message's Visual Trace differs from what is shown, when going to the View Full Contents view in the Contents tab of the message viewer.

2
0 143
Question Mark OReilly · Apr 19, 2024

In message bank how do you search within XML? XML is imported on message bank so that side is ok as can see it like below

On source system message viewer finds message

On Message bank it doesn't 

More basic queries using the MessageHeader will work so the filters do work just must not be using the right one (if it is possible) to query the XML message 

1
0 185
Question Stella Ticker · Jun 11, 2024

We have an operation that sends a Rest request to an external endpoint. The request includes the secret, which shows up in the Message Viewer. While access to the Production is restricted to only those who need it, we have been asked to remove it from the Message Traces. Is there a way to hide certain information on the Message Viewer ?

Thanks for reading

2
1 157
Question Larry Pinsky · Apr 23, 2024

We are upgrading to Iris for Healthshare 2024.1.  When resending HL7 (resend and edit), the new message displays with a blank line in between each line of text.  In order to resend the message successfully, these blank lines need to be deleted.  Is this a setting, a bug or new functionality?  Is there a way to remove this functionality?

1
1 217
Question Jimmy Christian · Dec 21, 2023

Hello community,

I am trying to see the complete HL7 message for the class EnsLib.HL7.Message.

But it is showing the truncated version only.

I also tried to convert to stream

msg.OutputToLibraryStream(.streammsg)
newmsg=##class(EnsLib.HL7.Message).ImportFromLibraryStream(streammsg)

While (streammsg.AtEnd = 0) {
     Set len = 1000
        Set tPrintMessage=newstream.Read(.len)
     Write tPrintMessage
}

But when i print it, its not showing complete message.

Any idea or suggestions?

Thank you in advance.

Jimmy Christian.
 

2
1 320
Question Daniel Lee · Aug 1, 2023

I would like to search for all messages where their body size is greater than 3MB. 

I have searched through the common Header and body properties and I have not found a size property. I have looked at the extended properties but I am unsure if any of the extended classes allows me to find the Doc size. 

I have stepped through most of the body property classes related to messages or documents that have an exposed property that filters by document or message size. 

Is there a way to do this within the Message Viewer or Terminal? 

Thank you in advance. 

Dan 

4
0 382
Question Mark OReilly · Jul 3, 2023

In show Query messages in the message viewer the head.%Id is always used. How do you do this via your own sql/objectscript as fast as the portal does a search as using dates searching Ens.MessageHeader on portal is slow. 

For instance if you try do a search saying (TimeProcessed >='2023-06-01 00:00:00.000' and TimeProcessed <'2023-06-02 00:00:00.000') it is slow but using the portal the search would know this is head.%ID >= 5344549861 AND head.%ID <= 5347641372. How do you utilize this in your own queries as can't see the logic in EnsPortal.MsgFilter.Assistant 

3
1 336
Announcement Shane Nowack · Feb 14, 2023

Hello InterSystems HL7 Community,

InterSystems Certification is developing a certification exam for InterSystems HL7 interface specialists and, if you match the exam candidate description given below, we would like you to beta test the exam. The dates the exam will be available for beta testing are March 28 - April 30, 2023. Interested beta testers should sign up now by emailing certification@intersystems.com (see below for more details)

1
0 1090
Question Mark OReilly · Feb 3, 2023

Hi:

I don't understand how to use this open exchange item for auto creating deleting items. I think it assumes knowledge in the steps of how to use it which i don't get. 

Added the code into dev on  SRFT.Utility.DeleteHelper.OnDeleteSuper and SRFT.Utility.DeleteHelper.AddHelper  

current class is 

Class Messages.XML.GenericWif.fileparameters Extends (%Persistent, %XML.Adaptor)
{

Property revisionnumber As %String;

Property primarylink As Messages.XML.GenericWif.primarylink;

Property additionalindexes As Messages.XML.GenericWif.additionalindexes;

2
0 314
Question Mark OReilly · Jul 18, 2022

I'm not sure why on some message you cannot edit/resend and change the inforatmation in the message 

i.e. 

Property property1As Messages.MesaageType1;

Property property2 As Messages.MesaageType2;

Property property3 As list Of Messages.MesaageType3;

All extend Extends (Ens.Request, %XML.Adaptor)

is there anything we are missing? 

1
0 281
Question Stefan Schick · Nov 8, 2022

Hello,

searching messages in our Message Bank is quite slow, often runs into timeout.

I wanted to perform a tune table on Ens_Enterprise_MsgBank.MessageHeader because this apparently has not been done yet - the Tune Table utility shows no entries for selectivity, etc.

I tried

w $SYSTEM.SQL.Stats.Table.GatherTableStats("""Ens_Enterprise_MsgBank"".MessageHeader")

and got this error message

6
1 555
Question Stefan Schick · Mar 24, 2022

Hello,

I'd like to add/remove items to/from a custom HL7 searchtable (which extends EnsLib.HL7.SearchTable).

Adding new items worked fine by:

  • -add new item to class definition
  • compile class in all namespaces
  • reindexing messages with the BuildIndex() method

Question 1:

How can I remove items from the searchtable properly? Doing the same as above (removing them from the class, recompiling, reindexing) seemed to work, but the removed items still appear in the message viewer's search criteria list. So I think there must be an additional step to the procedure. What am I missing?

3
0 509
Question Ahmad Bukhtiar · Sep 23, 2020

Any syntax help, i want to check different msg types and then reach out to the value in that particular segment. Here is example, i want to get SSNNumber from a method. Trying to use NOTIN, and Lookup

Class Training.RulesFunctionSet Extends Ens.Rule.FunctionSet

{

ClassMethod getEmiratesId(pHL7 As EnsLib.HL7.Message) As %String
{
SET msgType = pHL7.GetValueAt("MSH:MessageType.TriggerEvent")
 

IF msgType NotIn "A39,A40,O01,O11,O09,R01" {
return pHL7.GetValueAt("PID:SSNNumberPatient")}

5
0 704
Question Ewan Whyte · Feb 21, 2018

I'm trying to get a count of specific message type with a specific entry and thought I could build the query in Message Viewer but  this does not provide counts (as far as I am aware). So when I take the SQL from 'Show Query' it omits the segment criteria as the code shows below. 

 I have attached the criteria that has been excluded. Is this possible?

Thank you

2
0 1600
Article Dmitry Zasypkin · May 22, 2020 2m read

If you work with interoperability productions of InterSystems IRIS or Ensemble, no doubt you are familiar with the Message Viewer page. The page supports filtering messages according to filter criteria you enter in the Basic and/or Extended Criteria sections. Extended Criteria conditions are specified as property-operator-value triples. Once you click Search button, such triples become WHERE clause conditions of a generated SQL query executed against message header/body tables.

As a side note, one can view recently generated message queries by following the instructions listed in the doc.

Unfortunately stream properties cannot be used in the filtering conditions since most of the SQL WHERE predicates (including LIKE) are applied to OID of a stream - not to its contents. But there is a way to overcome that limitation *to some extent* using a simple two-step approach:

1) Subclass EnsPortal.MsgFilter.Assistant as follows

Class iscru.interop.MsgFilterAssistant Extends EnsPortal.MsgFilter.Assistant
{
ClassMethod GetSQLCondition(pOperator As %String, pProp As %String, pValue As %String, pDisplay As %Boolean = 0, pNoIndex As %Boolean = 0) As %String
 {
  if (pValue = "") || ((pOperator '= "Like") && (pOperator '= "NotLike")) quit ##super(pOperator, pProp, pValue, pDisplay, pNoIndex)
  
  if ("%%" = $extract(pValue, *-2, *-1))
  {
    set pValue = "'" _ $extract(pValue, 1, *-3) _ "' ESCAPE '" _ $extract(pValue, *) _ "'"
  }
  else
  {
    set pValue = "'" _ $replace(pValue, "'", "''") _ "'"
  }
  quit "substring(" _ pProp _ ", 1, 3000000) " _ $case(pOperator, "Like": "LIKE", "NotLike": "NOT LIKE") _ " " _ pValue
 }
}

2) Execute the following command in the current namespace:
         set ^EnsPortal.Settings("MessageViewer", "AssistantClass") = "<name of the class created in step 1>"

Now you can apply Like/NotLike conditions to stream properties of message bodies with one limitation: only the first 3 mln bytes of a stream are taken into account when applying Like/NotLike pattern. Anyway this is more of a proof-of-concept solution that does not "scale", but still works well in some cases.

If the 3M limitation is not acceptable then it might make sense to look into implementing Like operator with stream argument, wrapping it in a stored procedure method, and using that procedure for WHERE subclause in the code above. Perhaps that can be a good topic for another article... 

0
2 651