FHIR Chat · Concepts from RxNorm and terminology powered search · terminology

Stream: terminology

Topic: Concepts from RxNorm and terminology powered search


view this post on Zulip Josh Mandel (Mar 17 2022 at 23:10):

I've been dabbling with extracting RxNorm as an example including terms, attributes, and relationships. I will note that https://build.fhir.org/rxnorm doesn't mention attributes at all, which seems to suggest that attributes aren't available for most FHIR servers to query over. (Is this intentional?)

Working from the current prescribable file from NLM, I loaded into sqlite and use the following script to generate an ndjson.gz file ( 4.5MB):

Generate ndjson file

Example concept representation (shown with jq invocation)

This isn't directly useful, but I think the JSON model is the same kind of thing as the "Concept" resource that @nicola (RIO/SS) has described.

view this post on Zulip Peter Jordan (Mar 18 2022 at 03:49):

Interesting. I had a tentative stab at doing this on Terminz 2-3 years ago - the result can be obtained from here
It uses the 01032022 version of RxNorm (I only update it sporadically). Many of the property types are incorrect, but this was only meant as a 'starter for 10' to take to a Connectathon.

view this post on Zulip Michael Lawley (Mar 22 2022 at 06:54):

If you could tweak that sqlite to generate objects more like:

{
    "code": "828269",
    "display": "loratadine 10 MG 24HR Oral Capsule",
    "designation": [
        {
            "use": { "code": "PSN", "system": "???" },
            "value": "loratadine 10 MG 24HR Oral Capsule"
        },
        {
            "use": { "code": "SCD", "system": "???" },
            "value": "loratadine 10 MG Oral Capsule"
        },
        {
            "use": { "code": "SY", "system": "???" },
            "value": "loratadine 10 MG 24HR Oral Capsule"
        }
    ],
    "property": [
        {"code": "NDC", "valueCode": "11673098607"},
        {"code": "NDC", "valueCode": "11673098630"},
        {"code": "NDC", "valueCode": "11822044600"},
        {"code": "NDC", "valueCode": "11822202203"},
        {"code": "NDC", "valueCode": "21130019502"},
        {"code": "NDC", "valueCode": "25000002108"},
        {"code": "NDC", "valueCode": "25000002113"},
        {"code": "NDC", "valueCode": "25000002121"},
        {"code": "NDC", "valueCode": "25000002134"},
        {"code": "NDC", "valueCode": "25000002136"},
        {"code": "NDC", "valueCode": "25000002146"},
        {"code": "NDC", "valueCode": "36800075539"},
        {"code": "NDC", "valueCode": "36800075552"},
        {"code": "NDC", "valueCode": "41226068630"},
        {"code": "NDC", "valueCode": "49483068607"},
        {"code": "NDC", "valueCode": "49483068630"},
        {"code": "NDC", "valueCode": "49738068607"},
        {"code": "NDC", "valueCode": "49738068630"},
        {"code": "NDC", "valueCode": "50804084010"},
        {"code": "NDC", "valueCode": "53943011613"},
        {"code": "NDC", "valueCode": "55910062939"},
        {"code": "NDC", "valueCode": "55910062952"},
        {"code": "NDC", "valueCode": "59556088201"},
        {"code": "NDC", "valueCode": "59556088281"},
        {"code": "NDC", "valueCode": "63868066910"},
        {"code": "NDC", "valueCode": "68016005510"},
        {"code": "NDC", "valueCode": "69452021103"},
        {"code": "NDC", "valueCode": "69452021107"},
        {"code": "NDC", "valueCode": "69452021116"},
        {"code": "NDC", "valueCode": "69452021126"},
        {"code": "NDC", "valueCode": "69452028317"},
        {"code": "NDC", "valueCode": "69452028319"},
        {"code": "NDC", "valueCode": "69452028325"},
        {"code": "NDC", "valueCode": "69842068607"},
        {"code": "NDC", "valueCode": "69842068630"},
        {"code": "NDC", "valueCode": "69842068660"},
        {"code": "NDC", "valueCode": "70000021701"},
        {"code": "NDC", "valueCode": "72288044639"},
        {"code": "NDC", "valueCode": "79481044600"},
        {"code": "RXN_AI", "valueString": "{316167} 28889"},
        {"code": "RXN_AM", "valueString": "{316167} 28889"},
        {"code": "RXN_AVAILABLE_STRENGTH", "valueString": "10 MG"},
        {"code": "RXN_BOSS_FROM", "valueString": "{316167} AI"},
        {"code": "RXN_HUMAN_DRUG", "valueString": "US"},
        {"code": "RXTERM_FORM", "valueString": "Cap"},
        {"code": "consists_of", "valueCode": "316167"},
        {"code": "has_dose_form", "valueCode": "316965"},
        {"code": "has_tradename", "valueCode": "836338"},
        {"code": "parent", "valueCode": "828268"},
        {"code": "parent", "valueCode": "1165336"},
        {"code": "parent", "valueCode": "1165337"}
      ]
  }

Then it would drop right in to CodeSystem

view this post on Zulip Michael Lawley (Mar 22 2022 at 06:57):

(I don't know RxNorm, so I've just guessed types for the properties above and that "PSN" might mean preferred synonym, and hence be the thing to use for "display")

view this post on Zulip Josh Mandel (Mar 22 2022 at 12:54):

Cool! Sure, I'll give that a shot. I see I should be using word "designation" above. Quick notes

  • PSN is a "prescribable name" suitable for electronic prescribing UIs

  • To my knowledge RxNorm only models attributes as strings, so even NDC codes would use valueString

QQ: is there a way to differentiate in FHIR between an attribute with a coded value vs a relationship to a concept? Like... use http://build.fhir.org/codesystem-definitions.html#CodeSystem.property.type of valueCode for within-CodeSystem relationships, and use Codings got other coded attributes? Or is there a way to express this distinction explicitly?

view this post on Zulip Josh Mandel (Mar 22 2022 at 18:38):

Here's an updated script that makes the changes you suggested (although I don't re-name "isa", and I use valueString for all attributes and valueCode for all relations)

Generation

Example query

view this post on Zulip Michael Lawley (Mar 24 2022 at 07:05):

Thank you, that is an awesome leg up!

view this post on Zulip Michael Lawley (Mar 24 2022 at 14:08):

Boilerplate and tweaks for an actual CodeSystem

As a first-cut, this is usable, promising, and only 5.5M compressed.

Looking at https://www.hl7.org/fhir/rxnorm.html#4.3.2.3 there's a more explicit spec for identifying the display term, as well as a general filter here https://www.hl7.org/fhir/rxnorm.html#filters for identifying valid(?) CUIs that probably need to be factored in and then it'd be nice to have a standard transform into a CodeSystem representation.

view this post on Zulip Josh Mandel (Mar 24 2022 at 14:42):

I was a bit puzzled by https://www.hl7.org/fhir/rxnorm.html as a whole, so I decided to just think about how I would want to represent RxNorm concepts on my own as a first pass. The SQL queries listed on that page for generating display names, for example, only match concepts for a couple of types. They omit about a dozen types including branded and generic drug packs, branded and generic ingredients, precise ingredients, and so on. I'm also not sure why the SCD/SBD designation afeknfsy would be preferred to a prescribable designation string for example. This might be reasonable but I don't know whether this was a considered decision or just a default choice.

(I did submit a Jira issue asking why RxNorm attributes are not included in that page, but I realize I don't have full context for the choices made in that page.)

view this post on Zulip Josh Mandel (Mar 24 2022 at 14:45):

I will noodle on suggestions for mapping a file like this into a standard CodeSystem resource. The main decision I see is whether to include the additional framing metadata (URL, publisher, version, etc) as a headerline in this GZip ndjson file or as a separate companion CodeSystem (sans concepts) JSON file. I tend toward the latter.

view this post on Zulip Josh Mandel (Mar 24 2022 at 18:09):

https://build.fhir.org/rxnorm specifies version as

Where a version is used, it should be the date of release, encoded as in the download files, e.g. "07092014"

... but this doesn't distinguish between different releases like Full releases vs Current Prescribable Content releases. So I'm going to use a modified convention based on RxNorm filenames (with the RxNorm_ prefix and .zip suffix stripped).

view this post on Zulip Josh Mandel (Mar 24 2022 at 18:41):

One thought is that for publication, separating the CodeSystem from the Concepts array as follows may be a good idea:

CodeSystem as small FHIR JSON file

...this then links out to a concepts file via .extension.valueUrl (example above uses IPFS; can be resolved via ipfs get QmdcesSyDm12aSjfg1fFR28Yhfi6yC6nRxcNJkazU2zN5r/concepts/rxnorm/full_prescribe_03072022.ndjson.gz or with a web gateway like https://cloudflare-ipfs.com/ipfs/QmdcesSyDm12aSjfg1fFR28Yhfi6yC6nRxcNJkazU2zN5r/concepts/rxnorm/full_prescribe_03072022.ndjson.gz). I'm thinking this would make it easier for servers to associate content with the "scaffold" as needed.

view this post on Zulip Michael Lawley (Mar 24 2022 at 19:53):

I'm not at all familiar with RxNorm details, so the rxnorm.html page was the best I had to go on, but I do get the sense that it's not mature.
It would be great to get people expert in the content itself involved in reviewing it and filling in the gaps.

view this post on Zulip Michael Lawley (Mar 24 2022 at 19:55):

On the version topic, whether rxnorm uses date strings in the form DDMMYYYY or MMDDYYYY ( I guess the latter since it's the US), these are bad for sorting -- it would be far better to base them on YYYYMMDD so that a natural lexical ordering also matches date ordering.
Also I did wonder about the Full releases vs Current Prescribable Content release and how these relate to each other - are they just parallel versions where one is a strict subset of the other?

view this post on Zulip Josh Mandel (Mar 24 2022 at 19:57):

On the version topic, whether rxnorm uses date strings in the form DDMMYYYY or MMDDYYYY ( I guess the latter since it's the US), these are bad for sorting -- it would be far better to base them on YYYYMMDD so that a natural lexical ordering also matches date ordering.

100%. The current rxnorm.html page establishes this convention as a direct reflection of NLM's filename conventions.

view this post on Zulip Josh Mandel (Mar 24 2022 at 19:57):

I did wonder about the Full releases vs Current Prescribable Content release and how these relate to each other - are they just parallel versions where one is a strict subset of the other?

Yes, Current Prescribable should be a strict subset of Full. It's licensed more liberally, excludes attributes sourced from third-party drug terminologies, and excludes retired concepts. (At least, that's my rough understanding.)

view this post on Zulip Michael Lawley (Mar 24 2022 at 20:06):

I'm not sure why you want to separate the metadata parts from the concepts though. (Part of) the metadata changes every release and it's not a significant addition?

view this post on Zulip Josh Mandel (Mar 24 2022 at 20:09):

I'm only looking to separate them insofar as I want to support things like

  • POSTing a small resource to a server and letting the server resolve concepts asynchronously in the background
  • Streaming processing of concepts one by one

But maybe I'll try for a "belt and suspenders" and throw the "shell" CodeSystem into the first line of the ndjson.gz file

view this post on Zulip Craig McClendon (Mar 24 2022 at 21:26):

Not sure if this is helpful, but throwing it out there in case it is..
The OMOP/OHDSI terminology downloads include RxNorm (300.3K concepts) in the omop terminology schema.
It's an easy schema to query.
I ran a few queries to see what's there and it appears to capture the hierarchies and many relationships.

These are all the relationship types I see for it for one direction of the relationship (with counts):
Has dose form group 39179
Has form 3145
Has marketed form 343467
Has precise ing 14138
Has quantified form 20342
Has tradename 378819
Is a 8
Mapped from 1092880
Maps to 200375
Precise ing of 14138
Quantified form of 6446
RxNorm - ATC 30084
RxNorm - ATC pr lat 5078
RxNorm - ATC pr up 3622
RxNorm - ATC sec lat 1278
RxNorm - ATC sec up 36571
RxNorm - SNOMED eq 21148
RxNorm dose form of 1758063
RxNorm has dose form 105946
RxNorm has ing 87212
RxNorm ing of 260090
RxNorm inverse is a 243613
RxNorm is a 219049
Subsumes 4
Tradename of 105457

view this post on Zulip Josh Mandel (Mar 24 2022 at 22:11):

Indeed -- the releases in OMOP do a good job covering core vocabularies used in profiles like US Core

view this post on Zulip Josh Mandel (Mar 24 2022 at 22:14):

Attributes and relationships are well accounted for. The distribution mechanism relies https://athena.ohdsi.org/vocabulary/list or something similar to centrally/consistently allocate identifiers for each code system, which makes it a bit harder to manage in an environment where different publishers manage their own process. (While this thread is focused on rxnorm, the capability I'm driving at here is a general-purpose distribution mechanism for CodeSystems that can easily be loaded into a FHIR server. Using OMOP table structures is certainly a possibility there, but it require working through a bit of mapping into the FHIR structures on the receiving side, and I'm wondering whether it's possible to do something more "fhir native".)

view this post on Zulip Josh Mandel (Mar 24 2022 at 22:15):

I've captured my current thinking in https://github.com/jmandel/fhir-concept-publication-demo which has examples of:

  • CodeSystem JSON file with all concepts embedded
  • CodeSystem JSON "shell" with a pointer to concepts in an ndjson file
  • ndjson file where the first line is a CodeSystem and each subsequent line is a Concept

view this post on Zulip Michael Lawley (Mar 25 2022 at 00:05):

@Craig McClendon can you explain what's going on with "Is a" and "RxNorm is a" (and, I guess, "Subsumes" and "RxNorm inverse is a") -- why are these separate?

view this post on Zulip Craig McClendon (Mar 25 2022 at 13:54):

@Michael Lawley I don't know enough about RxNorm to tell you much. 'Is a' has only 8 relationships, 'Subsumes' 4. Here are some samples of the codes that match those relationships (columns below are concept1_id , concept1_name, concept2_id, concept2_name)

'Is a'
40220901    influenza A virus (H5N1) antigen    21601333    Influenza vaccines
42903441    influenza A virus   21601333    Influenza vaccines
42903442    influenza B virus   21601333    Influenza vaccines
42903696    immunoglobulin M, human 21601255    Immunoglobulins, normal human
43531966    immunoglobulin A    21601255    Immunoglobulins, normal human
44814323    hepatitis C virus   21601337    Hepatitis vaccines
19117912    immunoglobulin G    21601255    Immunoglobulins, normal human
19013765    respiratory syncytial virus immune globulin intravenous 21601276    Other immunoglobulins

'Subsumes'
1311078 cytarabine  2718853 Injection, cytarabine liposome, 10 mg
1338512 doxorubicin 43533290    Injection, doxorubicin hydrochloride, liposomal, imported lipodox, 10 mg
1338512 doxorubicin 44786607    Injection, doxorubicin hydrochloride, liposomal, not otherwise specified, 10 mg
1717240 amphotericin B  2718244 Injection, amphotericin b liposome, 10 mg

'RxNorm inverse is a'
739473  relugolix Oral Product  739475  relugolix Oral Tablet
739473  relugolix Oral Product  739476  relugolix 120 MG Oral Tablet
...

view this post on Zulip Robert McClure (Apr 01 2022 at 20:21):

Catching up on zulip... I am not an RxNorm technical expert; don't even have it loaded in a DB (that may be coming soon ;-) BUT wrt @Craig McClendon relationship list above, I don't think any of those codes are RxNorm concept identifiers, IE; RxCUIs. They might be atom identifiers. And even then, remember that RxNorm only represents drug elements, so things like viruses and Influenza vaccines likely are external information included in the files. It does include information (limited) representing drug classes. For example relugolix Oral Product has [RxCUI = 2472780].

view this post on Zulip Craig McClendon (Apr 01 2022 at 20:34):

That's my mistake @Robert McClure - I listed the primary keys and not the concept codes above. The RxCUI 2472780 is indeed associated with Relugolix Oral Product in the Athena database.

view this post on Zulip Craig McClendon (Apr 01 2022 at 20:43):

If anyone is interested, you can use the Athena web UI to browse and see what all is in it. I think this link should work: https://athena.ohdsi.org/search-terms/terms?query


Last updated: Apr 12 2022 at 19:14 UTC