NLM UMLS MRREL 损坏/不完整

NLM UMLS MRREL is broken / incomplete

几十年来,我一直在使用统一医学语言系统 (UMLS)。但多年来(自 2017 年以来)我一直意识到 MRREL table 存在严重缺陷。我想知道这怎么可能?

我有很多例子,但我只是让它变得非常简单。 ATC 代码是一棵简单的树。在许多其他类别中,有一个 top-level 类别 'G' (CUI: C3653431) 和另一个 'C' (CUI: C3540036)。

为了绝对确定我不会因为导入关系数据库的过程而丢失任何东西,我正在检查来自 UMLS 分发的原始文件:

(  unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.aa.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ab.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ac.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ad.gz |zcat ; 
) |egrep 'C3540036|C3653431'

这是我得到的:

|||PAR|C3540036|A22726695||inverse_isa|R162880348||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162896206||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162888235||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162884662||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162904098||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162892260||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162895918||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162895969||||||N||
|||PAR|C3540036|A22726695||inverse_isa|R162884408||||||N||
|||CHD|C3540036|A22726695||isa|R162905548||||||N||
|||CHD|C3653431|A22724193||isa|R145149031||||||N||
C3540036|A22726695|AUI|CHD|C0001645|A22729715|AUI|isa|R162894118||ATC||||N||
C3653431|A22724193|AUI|CHD|C3653561|A22721518|AUI|isa|R145152424||ATC||||N||
|||PAR|C3653431|A22724193||inverse_isa|R145147348||||||N||
|||PAR|C3653431|A22724193||inverse_isa|R145150236||||||N||
|||PAR|C3653431|A22724193||inverse_isa|R145153001||||||N||
|||PAR|C3653431|A22724193||inverse_isa|R162904046||||||N||

为什么每个顶级 ATC 类别只有一个 link?

但 C06、C05 (CUI: C0304533)、G02 (CUI: C3653939) 等在哪里?

让我们反过来搜索:

(  unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.aa.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ab.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ac.gz |zcat ;
   unzip -p 2021AA-full/2021aa-2-meta.nlm 2021AA/META/MRREL.RRF.ad.gz |zcat ; 
) |egrep 'C0001645|C0304533|C3653561|C3653939' \
|fgrep '|ATC|' 

这次我从源 ATC 中过滤掉除 MRREL 之外的所有内容。首先是C07

的C07AAchild
C0001645|A22726519|AUI|CHD|C0304515|A22728404|AUI|isa|R145146143||ATC||||N||
C0001645|A22729715|AUI|CHD|C0001645|A22726519|AUI|isa|R162909942||ATC||||N||

看上面竟然还有一个循环!而C07的其他children呢?无处。 C07 的唯一另一行是我们已经拥有的 link 到 C。

C3540036|A22726695|AUI|CHD|C0001645|A22729715|AUI|isa|R162894118||ATC||||N||

还有C05?只有一个 child C05B,但没有 parent link 到 C 或任何其他 child!

C0304533|A22730499|AUI|CHD|C0360720|A22722089|AUI|isa|R162902080||ATC||||N||

现在是 G02 和它的 3 个(当然更多)children:

C3653939|A22723315|AUI|CHD|C3653712|A22724891|AUI|isa|R162905420||ATC||||N||
C3653939|A22731353|AUI|CHD|C3653306|A22721882|AUI|isa|R162890442||ATC||||N||
C3653939|A22722139|AUI|CHD|C0164398|A22725073|AUI|member_of|R162897807||ATC||||N||

然后我们有反 links,它们实际上不是来自 ATC,这些概念来自 SNOMED 和其他来源:

C0164398|A22725073|AUI|PAR|C3653939|A22722139|AUI|has_member|R162896052||ATC||||N||
C0754280|A26456152|AUI|PAR|C3653939|A22722139|AUI|has_member|R171341743||ATC||||N||
C1721339|A32510681|AUI|PAR|C3653939|A22722139|AUI|has_member|R202594180||ATC||||N||
C3652943|A22728555|AUI|PAR|C3653939|A22722139|AUI|has_member|R162895991||ATC||||N||
C3652944|A22730286|AUI|PAR|C3653939|A22722139|AUI|has_member|R162884649||ATC||||N||

这里是 G 到 G03

C3653431|A22724193|AUI|CHD|C3653561|A22721518|AUI|isa|R145152424||ATC||||N||

这里也不是 ATC link,目标在 SNOMED 和其他来源中,但不在 ATC 中:

C3653561|A22721518|AUI|CHD|C0002844|A22722789|AUI|isa|R145149338||ATC||||N||

所以这完全是随机的。

我记得几十年前,MRREL 对于所有关系都有两个方向,这是非常多余的。但现在不是了。这是怎么回事?

我已经向 NLM 发送了一份问题报告,他们回复说 UMLS-Full.zip 中以 .nlm 结尾的文件还包含 UMLS 数据表,但不知何故不完整,并且有一个需要他们的 MetamorphoSys 程序 assemble 正确的文件。

他们似乎对行进行了一些数据压缩(无论出于何种原因),通过这些压缩他们可以将 MRREL 文件的大小减少大约 20%。

  • MRREL.RRF 来自 metathesaurus 分布 5,137,657,601 字节

  • MRREL.RRF 来自 UMLS-Full .nlm 文件 3,662,797,614 字节

    $头MRREL.RRF.met C0000005|A13433185|SCUI|RB|C0036775|A7466261|SCUI||R86000559||MSHFRE|MSHFRE|||N|| C0000005|A26634265|SCUI|RB|C0036775|A0115649|SCUI||R31979041||MSH|MSH|||N|| C0000039|A0016515|AUI|SY|C0000039|A11754881|AUI|translation_of|R101808683||MSHSWE|MSHSWE|||N|| C0000039|A0016515|AUI|SY|C0000039|A12080359|AUI|sort_version_of|R64565540||MSH|MSH|||N|| C0000039|A0016515|AUI|SY|C0000039|A12091182|AUI|entry_version_of|R64592881||MSH|MSH|||N|| C0000039|A0016515|AUI|SY|C0000039|A13042554|AUI|translation_of|R193408122||MSHCZE|MSHCZE|||N|| C0000039|A0016515|AUI|SY|C0000039|A13096036|AUI|translation_of|R73331672||MSHPOR|MSHPOR|||N|| C0000039|A0016515|AUI|SY|C0000039|A1317708|AUI|permuted_term_of|R28482432||MSH|MSH|||N|| C0000039|A0016515|AUI|SY|C0000039|A18972171|AUI|translation_of|R124061564||MSHPOL|MSHPOL|||N|| C0000039|A0016515|AUI|SY|C0000039|A28315139|AUI||R173174221||RXNORM|RXNORM|||N||

    $ 头 MRREL.RRF.nlm C0000005|A13433185|SCUI|RB|C0036775|A7466261|SCUI||R86000559||MSHFRE||||N|| C0000005|A26634265|SCUI|RB|C0036775|A0115649|SCUI||R31979041||MSH||||N|| C0000039|A0016515|AUI|SY|C0000039|A11754881|AUI|translation_of|R101808683||MSHSWE||||N|| C0000039|A0016515|AUI|SY|C0000039|A12080359|AUI|sort_version_of|R64565540||MSH||||N|| |||SY|C0000039|A12091182||entry_version_of|R64592881||||||N|| C0000039|A0016515|AUI|SY|C0000039|A13042554|AUI|translation_of|R193408122||MSHCZE||||N|| C0000039|A0016515|AUI|SY|C0000039|A13096036|AUI|translation_of|R73331672||MSHPOR||||N|| C0000039|A0016515|AUI|SY|C0000039|A1317708|AUI|permuted_term_of|R28482432||MSH||||N|| C0000039|A0016515|AUI|SY|C0000039|A18972171|AUI|translation_of|R124061564||MSHPOL||||N|| C0000039|A0016515|AUI|SY|C0000039|A28315139|AUI||R173174221||RXNORM||||N||

您可以看到如何通过将前几列复制到空列来从第 4 行生成第 5 行。

这似乎是问题所在。

我遇到了同样的问题。感谢您的自动回复!

我想确保他们用以前的项目填充空项目,是的,他们这样做了。 例如,这是解析 MRREL 的代码的摘录:

(文件第 2865-2891 行:gov.nih.nlm.umls.meta/src/gov/nih/nlm/umls/meta/io/RRFConceptInputStream.java)

        //
        // Process matching line
        //
        else if (line.startsWith(concept.getUi())
                || (prevCui != null && line.startsWith("|") && prevCui.equals(concept
                        .getUi()))) {

            //
            // Parse line and count fields
            // CUI1,AUI1,STYPE1,REL,CUI2,AUI2,STYPE2,RELA,RUI,SRUI,SAB,SL,RG,DIR,SUPPRESS,CVF
            //
            String[] tokens = FieldedStringTokenizer.split(line, "|", 17);

            // Set blank fields based on prev values.
            if (tokens[0].equals("")) {
                tokens[0] = prevCui;
                tokens[1] = prevAui;
                tokens[2] = prevStype1;
                tokens[6] = prevStype2;
                tokens[10] = prevSab;
            } else {
                prevCui = tokens[0];
                prevAui = tokens[1];
                prevStype1 = tokens[2];
                prevStype2 = tokens[6];
                prevSab = tokens[10];
            }