Release notes for NLP API 2.37

Contents

Brief Summary

Release versions

  • NLP API version 2 Release 37.
  • Python SDK and client v7.1.0.
  • NLP API specification v2.24.0: new processing features added entity-experiencer, entity-factuality, entity-contextual-validity, document-infer-structure.
  • JSON result output schema v2.37.0 for emtellipro-json-2: added output for entity-experiencer, entity-factuality, and added the method and value fields to the document category and subcategory attributes.
  • Depending on the installation parameters of the NLP API, not all the processing features are enabled by default. A subset of the most useful processing features is enabled by default in most installed versions of the NLP API.

Highlights

  • New processing features: entity-experiencer, entity-factuality, entity-contextual-validity. These new features are not run by default as they are compute intensive.
  • New automated document category and subcategory detection.
  • New relation concept links for the Experiencer relation.
  • New fast entity linking approach (when the requested processing features are ontology only; invoked without relation finding or confidence scores).
  • New document-infer-structure processing feature for documents missing table formatting and newlines.

New Features

Entity Contextual Validity

New processing feature entity-contextual-validity is an option provided to improve the precision of entity linking and negation finding. A larger context is used to validate entity linking. Since this check is more compute intensive it is not run by default but only when requested explicitly. It is meant to be run on more noisy sources of data and is less useful for the more constrained language used in Radiology and Pathology reports. Clinical notes can sometimes include common uses of medical terms which can be ruled out using this feature.

Here are some examples of how this works:

The patient was transferred from PIH Health this morning at
approximately 10:30 AM via non-emergent ambulance transport.

In the above input, the mention PIH could be erroneously linked to the SNOMED concept ID 48194001, which stands for Pregnancy-induced hypertension (disorder). However, in this case we can infer from the wider context that PIH Health is the name of an institution and therefore we can rule out the false positive entity link.

MRI imaging revealed a complete tear of the patient's VL tendon
sustained during an athletic injury three weeks prior.

In the above input, the mention VL could be erroneously linked to the SNOMED concept ID 395058002, which stands for Viral load (procedure). However, in this case we can identify this as incorrect and suppress that entity link.

There is no pleural abnormality. Similarly lacking evidence of
central adenopathy.

In the above input, the negation for adenopathy is linked to the negation in the previous sentence via the use of the term Similarly. By using a wider context we can determine that adenopathy should be negated rather than asserted.

There is no additional output in the NLP API JSON when the processing feature entity-contextual-validity is requested. It improves the precision of the entity linking concept links and polarity attribute output specifically for the SNOMED and MEDCIN ontologies (MEDCIN output has to be explicitly enabled via a specific license for a particular installation of the NLP API).

Entity Experiencer Attribute

A new attribute called experiencer is generated for each entity mention when enabled using the processing feature entity-experiencer. For example, for the input:

the patient's mother said he had hepatitis during his vacation to
France last month.

The output JSON has the experiencer attribute:

{
"label": "E1",
"spans": [ .. ],
"section_name": "INTRO",
"attributes": {
"experiencer": "patient"
},
"concept_links": [
"Csnomed1"
],
"locations": [ .. ],
"entity_type": { .. },
"text": [ "hepatitis" ]
}

The reason for the switch to an attribute is to provide simpler support for assumed entities like patient or family or provider.

Future versions of the NLP API will move to using the experiencer relation for only matched experiencers that have explicit matched spans of text. For example, in grandmother has alzheimers the experiencer relation links the mention grandmother to alzheimers and since it is a matched span grandmother is also assigned the SNOMED concept ID 113157001 for Grandmother (person). This allows for searches on precise person concept IDs. On the other hand, the experiencer attribute for the same sentence would be the string grandmother and the experiencer attribute makes it easier to limit searches to entities that are experienced by the patient and removes the need for any assumed experiencer entities (which we plan to deprecate and remove in future releases).

The JSON schema for the experiencer attribute is defined as a string datatype. The output will be the string "patient" to refer to the patient. When the experiencer is family, the output is a string value like "mother", "father" or "mother and father". Healthcare provider experiencers are referred to as the string "provider" for activities in a healthcare setting.

Here are some examples:

mother and father have h/o cad.

This has the following experiencer attribute:

{
"label": "E9",
"spans": [ .. ],
"section_name": "INTRO",
"attributes": {
"experiencer": "mother and father"
},
"concept_links": [ .. ],
"locations": [ .. ],
"entity_type": { .. },
"text": [ "cad" ]
}

For the following example:

The staff has verified that the instrument, sponge, and needle counts
were correct.

This has the following experiencer attribute for the healthcare activity of counting equipment:

{
"label": "E11",
"spans": [ .. ],
"section_name": "INTRO",
"attributes": {
"experiencer": "provider"
},
"concept_links": [ .. ],
"locations": [ .. ],
"entity_type": { .. },
"text": [ "instrument, sponge, and needle counts" ]
}

Entity Factuality Attribute

A new attribute called factuality is generated for each entity mention when enabled using the processing feature entity-factuality.

The main intention is to distinguish factual statements from broadly hypothetical statements or generic statements.

  • hypothetical: if the entity is hypothetical in any way.
    • part of an if statement.
    • a question for a radiologist or pathologist, e.g. “rule out appendicitis”.
    • scheduled or might occur in the future.
    • part of a differential diagnosis.
    • declared by the patient or family or friends, e.g. “patient’s mother said he had hepatitis last month”.
    • part of a question being asked of the patient, e.g. hopelessness in “Do you have feelings of hopelessness?” is part of a question.
    • part of PRN indications from medication prescriptions.
  • generic: if the entity is part of a general knowledge statement rather than applicable to the patient.
    • guidance, counseling or educational statement.
    • expected ranges for a lab test or a guideline or legalese.
    • definition, a quote from a textbook or journal article.
    • part of a list of criteria, or explanatory text rather than an actual patient finding.
  • factual: when none of the above is applicable, e.g. in “the patient has CAD”, CAD is factual.

For example, for the input:

Please call your doctor if you have severe pain, persistent nausea,
vomiting, or any other concerns.

The factuality attribute in this case for the entity severe pain would be hypothetical:

{
"label": "E1",
"spans": [ .. ],
"section_name": "INTRO",
"attributes": {
"factuality": "hypothetical"
},
"concept_links": [ .. ],
"locations": [ .. ],
"entity_type": { .. },
"text": [ "severe pain" ]
}

For example, for the input:

Eating 5 servings of fresh food per day can help people lower their
blood pressure.

The factuality attribute in this case for the entity blood pressure would be generic:

{
"label": "E9",
"spans": [ .. ],
"section_name": "INTRO",
"attributes": {
"factuality": "generic"
},
"concept_links": [ .. ],
"locations": [ .. ],
"entity_type": { .. },
"text": [ "blood pressure" ]
}

In most cases where a patient’s disorders, symptoms, and other entities are mentioned the factuality attribute would be factual.

The factuality attribute overlaps with some other processing features:

  • uncertainty, which comes from the entity-uncertainty processing feature, overlaps with the hypothetical label in factuality.
  • question_status, which comes from the entity-question-status processing feature, overlaps with the hypothetical label in factuality.
  • guidance, which comes from the entity-guidance processing feature, overlaps with the generic label in factuality.

The aim of the factuality attribute is to provide a single easy search that can eliminate many individual cases of non-factual uses of an entity based on the context. It is much more general and more widely applicable, e.g. question_status is highly Radiology-focused and limited to Indication sections in radiology reports.

Based on feedback, we may choose to deprecate the processing features and output attributes listed above if factuality, which is a more generalized attribute, ends up being more suitable for all the use cases.

In the NLP API v2.36 we introduced concept links associated with relations, specifically for Qualifier relations and Anatomic Site relations.

In this release, we extend relation concept links to Experiencer relations. As before, the concept ID associated with the combined string from the two arguments in the relation is added to the list "concept_links".

For example, for the input:

Family history of cardiovascular disease.

the Experiencer relation and its concept link are:

{
"label": "REX0",
"attributes": { .. },
"args": {
"experiencer": {
"ref": "E1",
"text": [ "Family history of" ]
},
"experienced": {
"ref": "E0",
"text": [ "cardiovascular disease" ]
}
},
"concept_links": [ "Csnomed2" ]
}
...
{
"label": "Csnomed2",
"concept_id": "266894000",
"description": "Family history: Cardiovascular disease (situation)"
}

For cases where a family member is the experiencer argument, the concept link value for the Experiencer relation includes a family history concept associated with the experienced entity. For example, in the following input father is the experiencer of coronary artery disease.

father has had coronary artery disease.

The Experiencer relation and its concept link are:

{
"label": "REX1",
"attributes": { .. },
"args": {
"experiencer": {
"ref": "E2",
"text": [ "father" ]
},
"experienced": {
"ref": "E3",
"text": [ "coronary artery disease" ]
}
},
"concept_links": [ "Csnomed5" ]
}
...
{
"label": "Csnomed5",
"concept_id": "430091005",
"description": "Family history of coronary arteriosclerosis (situation)"
}

Only links to the SNOMED ontology are produced for Experiencer relations. However, all the ICD-10-CM concepts that are retrieved from the SNOMED concept ID are also added to the list of "concept_links".

Report Kind Detection

The report kind of a document is the combination of the document category and subcategory, for example, the category Radiology with the subcategory CT.

In previous releases, the report kind had to be supplied as part of the input, either in the MIME multipart headers for the document or as fields on the document in the JSON input format. In this release, both category and subcategory are optional in the NLP API specification. When they are not supplied, the NLP API detects the report kind automatically and the detected values are reported in the output.

The document attributes in the NLP API JSON output record how each value was obtained using a method field: manual when the value was set explicitly in the input, and automatic when it was detected by the NLP API. For a document submitted without a category or subcategory, the output is:

{
"id": "doc1",
"attributes": {
"category": {
"method": "automatic",
"value": "Radiology"
},
"subcategory": {
"method": "automatic",
"value": "CT"
}
},
"processing_status": { .. }
}

Automatically detected values are drawn from the same lists of allowed categories and subcategories that are accepted in the input; see the full list of values for the category part header and subcategory part header in the NLP API submit call. A report kind that is supplied in the input is always used as given and is reported with a method of manual.

Automatic detection is not enabled in every installation of the NLP API. Where it is disabled, the report kind supplied in the input is used.

Document Infer Structure

New processing feature document-infer-structure rewrites the input text to restore structure such as tables and line breaks before the document is processed. It is intended for extremely poorly formatted inputs where newlines are no longer part of the document and any markings that indicated table structure have also been stripped out. Such documents lose the layout that NLP API relies on to find sections and to extract relations, in particular measurement relations in tabular data.

This feature applies to text input only and is not run by default; it has to be requested explicitly. It is not intended for documents that already carry their original formatting.

For example, for an input where the line and column structure of a results table has been lost:

LABORATORY RESULTS Test Result Unit Sodium 138 mmol/L Potassium 4.1
mmol/L Creatinine 1.2 mg/dL

the feature infers the rows and columns of the table and writes it back into the document text in markdown format:

LABORATORY RESULTS
| Test | Result | Unit |
| :--------- | :----- | :----- |
| Sodium | 138 | mmol/L |
| Potassium | 4.1 | mmol/L |
| Creatinine | 1.2 | mg/dL |

Because the feature replaces the document text, the modified text is provided in the text field of the document in the NLP API JSON output:

{
"id": "doc1",
"attributes": { .. },
"text": "LABORATORY RESULTS\n\n| Test | Result | Unit |\n ..",
"processing_status": { .. }
}

The text change is not recoverable from the input, so the returned text is the text that all the spans and locations in the rest of the output refer to. Consumers that map output offsets back to their own copy of the document must use the returned text rather than the text that was submitted.

If the input contains datetimes as column headers, then this feature copies them into each cell in that column in order to allow the temporality feature to associate each measurement (for instance) with a datetime.

For example, for an input where the column headers are datetimes:

Test 2021-08-23 2022-09-19 Sodium 138 130 Potassium 4.1 4.2
Creatinine 1.2 1.1

The document-infer-structure feature produces the following markdown table (note the repeated datetimes in each cell):

| Test | 2021-08-23 | 2022-09-19 |
| :--------- | :------------- | :------------- |
| Sodium | 138 2021-08-23 | 130 2022-09-19 |
| Potassium | 4.1 2021-08-23 | 4.2 2022-09-19 |
| Creatinine | 1.2 2021-08-23 | 1.1 2022-09-19 |

This capability enables each test in the table above to be associated with a value (as a measurement relation) and the datetime when the test occurred (as a temporality relation).

Changes

Ontology updates

The NLP API JSON output lists the ontology versions under "ontology_versions".

  • SNOMED, ICD-10, and ICD-10-CM ontologies: US Edition 2026-03-01.
  • UMLS ontologies (NCI, LOINC, and HGNC): 2026-05-04-AA release.
  • RxNorm: 2025-10-06 edition.
  • Remove DrugBank as a source for RxNorm.
  • RadLex: v4.3 2025-12-01.
  • MEDCIN: 2025-11-21 release.

MEDCIN updates

  • The processing feature entity-contextual-validity is enabled for the MEDCIN ontology.
  • Updated SNOMED-MEDCIN ontology with more descriptive fully specified names (FSNs) by including specialty and Quippe Group ID.
  • SNOMED-MEDCIN ontology filtered to remove non-clinical semantic types such as body structure, person, and geographic location.
  • Enable SNOMED-MEDCIN mapping for entity matches that occur outside a labeled section (i.e., in the document introduction).
  • MEDCIN entity concept links are now also found by mapping from SNOMED concepts, improving MEDCIN coverage.
  • MEDCIN concept IDs for relation arguments are now set to unknown when a mapping is not available.
  • Fix MEDCIN section labels that were incorrectly generated from duplicate concepts with prefixes.

Negation

  • Update negation finding for presents with: this phrase is now treated as asserting rather than negating an entity.
  • Add clear as a negation scope delimiter in comma-separated lists.
  • OP clear is treated as asserted when it appears in a list context.
  • Improved negation handling for entity names that contain the word negative (e.g., coag negative staph), reducing false positive negations.
  • Improved negation handling for absence of.
  • Improved negation handling for does report.

Section parsing

  • Improved section heading finder.

Bug fixes

  • Fix erroneous entity matches: unwanted concept types are now filtered out and shorter matches such as jaw are now correctly included.
  • Fix erroneous concept link from created to creatinine measurement concepts.
  • Fix bug where concept links skipped the filtering step when being applied to concatenated relation arguments.
  • Fix so that the input report kind is used when report kind auto-detection is disabled.
  • Prevent any self-referential relations.
  • SNOMED annotations that are determined to be incorrect via entity-contextual-validity are not mapped to ICD-10 or ICD-10-CM.
  • Remove spurious contraction matches in entity linking.

Model updates

  • New fast entity linking approach (when the requested processing features are ontology only; invoked without relation finding or confidence scores).
  • Confidence scores now use the value from the disambiguation model when available.
  • New unified model for relation finding that replaces previous relation models for anatomicsite-relations, experiencer-relations, followup-relations, measurement-relations, imagelink-relations, qualifier-relations, and temporality-relations.
  • Added relation ontology info for ICD-10 and ICD-10-CM.
  • Auto-detected report kinds are marked as such in the output.
  • Quantization for the entity concept link confidence score model is now enabled by default, reducing memory requirements.

Measurement relation

  • The new unified relation model significantly improves recall on measurements found in structured data such as tables.

Qualifier relation

  • No more qualifier-value to measurement-value relation arcs in qualifier relation output.
  • chronic is now only produced as part of the qualifier relation output rather than the temporality relation output.

Experiencer relation

  • Add relation concept links for matched experiencer relations (not assumed experiencers). This captures family history concepts on the experiencer relation, e.g. father has had coronary artery disease links to the SNOMED concept Family history of coronary arteriosclerosis (situation) 430091005.
  • Improvements to experiencer subject pronoun suppression.
  • Remove link to associated finding concept in history of... relations.

Temporality relation

  • chronic is no longer produced as part of the temporality relation output; see the Qualifier relation change above.

Python requirements

  • Minimum Python version required is v3.11.

Python SDK Updates

The latest NLP API Python SDK at the time of release is version 7.1.0. Refer to the changelog for the Python SDK for a full explanation of the updates made since the last release. You will need to use version 5.7.0 or later of the Python SDK to send requests to the NLP API v2.37 but if you want to use the new features explained above you will need to use at least version 7.1.0.

New features in the Python SDK

To use existing NLP API databases with the new Python SDK you must do a data migration using the Python database client migrate subcommand:

emtellipro-db-client migrate --database postgresql://username:password@hostname:port/example_db

Entity Mentions Comparison — v2.36 to v2.37

This comparison was done using 100K Discharge Summaries. Only the most frequent entity types are shown in this comparison.

Entities by entity type — change in current version v2.37

Entity typeCommonCommon %Distinct SNOMED concepts change %Concept-linked entities change %Polarity flips %
procedure3,966,46295.3%+3.3%+196.8%0.0782%
finding2,568,76794.0%+4.6%+37.0%1.1725%
disorder2,032,71896.2%+1.8%+14.1%0.1860%
person2,008,86998.6%+0.5%+99.6%0.0586%
observable entity1,034,22695.9%-0.1%+78.7%0.1901%
morphologic abnormality386,97594.7%+1.0%+11.1%0.2300%
physical object295,59495.2%+6.5%+30.7%0.1562%
regime/therapy240,28797.8%+2.8%+43.7%0.0651%
situation67,67466.5%+588.7%+3318.3%0.5090%
  • Common: Number of entities common to both builds: same position, same type, same concept.
  • Common %: Percentage of this type’s previous-build entities that are common to both builds.
  • Distinct SNOMED concepts change %: Change in the current version’s number of SNOMED codes: (current - previous) / previous.
  • Concept-linked entities change %: Change in the current version’s number of concept-linked entities: (current - previous) / previous.
  • Polarity flips %: Percentage of this type’s previous-build entities whose polarity changed, for example asserted to negated.
  • Reading: A plus means the current version is higher, a minus lower.

Entity span analysis by entity type

Entity typeChanged conceptRetypedOnly prevOnly currentLonger prevLonger current
procedure84,053122,3248,8879,5393,79632,474
finding55,86961,5729,47548,86914,19963,389
disorder28,27120,7021,2385,7478,10624,484
person3,55215,52110,1572,0871642,318
observable entity9,10331,9358,78913,8017972,715
morphologic abnormality75020,9531,4734984671,091
physical object5,7738,5003985,43856232
regime/therapy5363,781483921,585584
situation18411,29905,25062170,748
  • Changed concept: Entities with the same type but a different SNOMED code, either with exact match or change in span boundary.
  • Retyped: Entities given a different entity type, either with exact match or change in span boundary.
  • Only prev: Entities in the previous build with no overlapping entity in the current build.
  • Only current: Entities in the current build with no overlapping entity in the previous build.
  • Longer prev: Entities where both builds agree on type and concept and the previous build covers more characters.
  • Longer current: Entities where both builds agree on type and concept and the current build covers more characters.

Entity span length analysis

Entity typeEntities prevEntities currentAvg len prevp50 prevp95 prevAvg len currentp50 currentp95 current
procedure4,162,8804,215,6799.18.023.09.28.023.0
finding2,731,3872,880,50011.110.023.011.510.024.0
disorder2,113,7992,122,28013.712.029.013.712.029.0
person2,038,3832,024,3746.43.029.06.33.027.0
observable entity1,078,9561,082,8849.38.021.09.38.021.0
morphologic abnormality408,705404,5509.58.018.09.68.019.0
physical object310,577311,2047.97.017.08.07.017.0
regime/therapy245,622248,5069.79.021.09.79.021.0
situation101,769175,18214.914.027.016.215.027.0
  • Entities prev / current: Number of entities of this type in each build.
  • Avg len: Mean entity length in characters. Where the words sit apart, the gap between them is not counted.
  • p50: Median entity length.
  • p95: 95th percentile entity length: 1 in 20 entities is longer than this.

Benchmarking

  • Processed 1744 CCDs.
  • Total size: 34 MB; Average size: 19.5 KB.
  • NLP API deployed with 4 GPU workers.
  • 32x CPU: Intel(R) Xeon(R) Silver 4310 CPU @ 2.10 - 3.30 GHz w/18 MB Cache; 189 GB RAM.
  • 1x GPU: Nvidia L4 w/24 GB of GPU RAM.
  • Processing features: entity-polarity,entity-measurement-unit,medication-relations,measurement-relations,rxnorm-ontology,text,entity-uncertainty,snomed-ontology,snomedicd10cm-ontology,experiencer-relations,temporality-relations,anatomicsite-relations,qualifier-relations,entity-concept-link-confidence
  • Processed 1744 reports in 35:32.77s for an average processing time of 1.222921s per report.
  • Output JSON file size: 269 MB.
  • Saved 1744 documents to database in 56.89s (0.032619s per document).
  • NLP API database size using Python database client output to sqlite: 446 MB.