Healthcare Series — Working with SNOMED using Ruby

Siva Gollapalli
4 min readApr 3, 2024

In this blog post, let’s discuss how we can work with SNOMED and the tools around it. Please read previous blog posts, to get context about what is SNOMED.

As you are already aware SNOMED is nothing but a set of text files that are getting released by SNOMED Internationals. It consists of unique identifiers for each disease, treatment, body parts, etc, and their relationships with other identifiers. However, working with text files isn’t easy and scalable. Hence we need to process those files and build a database that would be more useful for real-world scenarios. In that process, I am building a library called snomed_model built on top of Postgres.

How can we use it?

Just like any other Ruby gem we need to install it as follows:

gem install snomed_model

After that, we have to create and migrate respective tables to store SNOMED files as follows:

rake db:create && rake db:migrate 

Now load SNOMED into the database using the following tasks:

rake snomed:load_concepts[<concept file path>] # load concepts

rake snomed:load_descriptions[<description file path>] # loads concept descriptions

rake snomed:load_relationships[<relationship file path>] # load relationships between concepts

The above tasks, just load raw data but to work with that we need to build paths such that we can query descendants, ancestors, parents, children, synonyms, etc for a given concept. To do that we can use the following task:

rake snomed:build_paths_for_sample_data # This is for sample data

To load the entire data, please use the following task:

rake snomed:build_paths # To load the entire SNOMED

Now we are ready with data. Let’s see how to query the data:

How to find descriptions?

SnomedModel::Concept.find(840539006).descriptions.pluck(:term)
["Disease caused by SARS-CoV-2",
"Disease caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Disease caused by severe acute respiratory syndrome coronavirus 2",
"COVID-19",
"Disease caused by 2019 novel coronavirus",
"Disease caused by 2019-nCoV"]

How to find synonyms?

SnomedModel::Concept.find(840539006).synonyms.pluck(:term)
["Disease caused by severe acute respiratory syndrome coronavirus 2",
"COVID-19",
"Disease caused by SARS-CoV-2",
"Disease caused by 2019 novel coronavirus",
"Disease caused by 2019-nCoV"]

If you notice when you query synonyms it omits the FSN name (“Disease caused by severe acute respiratory syndrome coronavirus 2 (disorder)) and returns the remaining values.

How to find direct ancestors & descendants?

SnomedModel::Concept.find(840539006).direct_ancestors.pluck(:term) # Returns immediate parents for a concept

=> ["Coronavirus infection", "Coronavirus infection (disorder)"]
SnomedModel::Concept.find(840539006).direct_descendant.pluck(:term) # Returns immediate children for a concept

=> ["SARS-CoV-2 viraemia",
"Dyspnoea caused by 2019-nCoV",
"Dyspnoea caused by 2019 novel coronavirus",
"Dyspnea caused by 2019 novel coronavirus",
"Dyspnea caused by SARS-CoV-2",
"Dyspnea caused by 2019-nCoV",
"Dyspnoea caused by SARS-CoV-2",
"Infection of upper respiratory tract caused by 2019-nCoV",
"Infection of upper respiratory tract caused by SARS-CoV-2",
"Infection of upper respiratory tract caused by 2019 novel coronavirus",
"Fever caused by SARS-CoV-2",
"Fever caused by 2019 novel coronavirus",
"Fever caused by 2019-nCoV",
"Severe acute respiratory syndrome coronavirus 2 viremia",
"SARS-CoV-2 viremia",
"Severe acute respiratory syndrome coronavirus 2 viraemia",
"Acute disease caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Infection of upper respiratory tract caused by severe acute respiratory syndrome coronavirus 2",
"Fever caused by severe acute respiratory syndrome coronavirus 2",
"Fever caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Dyspnea caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Dyspnoea caused by severe acute respiratory syndrome coronavirus 2",
"Dyspnea caused by severe acute respiratory syndrome coronavirus 2",
"Viremia caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Viremia caused by severe acute respiratory syndrome coronavirus 2",
"Viraemia caused by severe acute respiratory syndrome coronavirus 2",
"Acute COVID-19",
"Acute disease caused by severe acute respiratory syndrome coronavirus 2",
"Acute disease caused by 2019-nCoV",
"Acute disease caused by SARS-CoV-2",
"Acute disease caused by 2019 novel coronavirus",
"Infection of upper respiratory tract caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"Infection of lower respiratory tract caused by 2019-nCoV",
"Infection of lower respiratory tract caused by 2019 novel coronavirus",
"Infection of lower respiratory tract caused by severe acute respiratory syndrome coronavirus 2 (disorder)",
"SARS-CoV-2 breakthrough infection",
"COVID-19 breakthrough infection",
"Severe acute respiratory syndrome coronavirus 2 breakthrough infection",
"Disease caused by severe acute respiratory syndrome coronavirus 2 following administration of vaccine product against severe acute respiratory syndrome coronavirus 2 (disorder)
",
"Disease caused by severe acute respiratory syndrome coronavirus 2 following administration of vaccine product against severe acute respiratory syndrome coronavirus 2",
"Disease caused by severe acute respiratory syndrome coronavirus 2 during pregnancy (disorder)",
"Disease caused by severe acute respiratory syndrome coronavirus 2 during pregnancy",
"COVID-19 during pregnancy",
"Infection of lower respiratory tract caused by SARS-CoV-2",
"Infection of lower respiratory tract caused by severe acute respiratory syndrome coronavirus 2"]

How to find ancestors & descendants?

SnomedModel::Concept.find(840539006).ancestors.map do |c| 
c.descriptions.fsns.pluck(:term)
end # returns list of ancestors for a given concept till root concept

=> [["Disease caused by Coronaviridae (disorder)"],
["Viral disease (disorder)"],
["Infectious disease (disorder)"],
["Disease (disorder)"],
["SNOMED CT Concept (SNOMED RT+CTV3)"],
["Coronavirus infection (disorder)"],
["Clinical finding (finding)"]]

SnomedModel::Concept.find(840539006).descendant.map do |c|
c.descriptions.fsns.pluck(:term)
end # returns list of descendants till leaf node

=> [["Viremia caused by severe acute respiratory syndrome coronavirus 2 (disorder)"]]

Note: When you compare with real SNOMED data you would see very less descendants for the Covid-19 concept (840539006) because I didn’t index all necessary concepts that fall under COVID-19. When you load full concepts then you would more concepts.

This way we can query SNOMED just like another SQL table and seamlessly we can integrate it into our application.

Hope this gem will be helpful in your integrations. Let me know what kind of functionalities you would like to see in future versions.

Happy Querying : )

--

--