Skip to content

Commit fa1ab68

Browse files
refactor: improve ROR name matching with Wikidata cross-validation and update organization data entries
1 parent f39c904 commit fa1ab68

3 files changed

Lines changed: 126 additions & 100 deletions

File tree

‎ROR_AUDIT.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
| Australian Red Cross Lifeblood | Australian Red Cross Lifeblood | Australia | [00evjd729](https://ror.org/00evjd729) | [Q4824602](https://www.wikidata.org/wiki/Q4824602) | [Q4824602](https://www.wikidata.org/wiki/Q4824602) | ⚠️ auto |
1212
| Bloodworks Northwest | Bloodworks Northwest | United States | [00ek9j693](https://ror.org/00ek9j693) | [Q21015632](https://www.wikidata.org/wiki/Q21015632) | [Q21015632](https://www.wikidata.org/wiki/Q21015632) | ⚠️ auto |
1313
| Cambridge Biomedical Research Centre | NIHR Cambridge Biomedical Research Centre | United Kingdom | [05m8dr349](https://ror.org/05m8dr349) | [Q33121816](https://www.wikidata.org/wiki/Q33121816) | [Q33121816](https://www.wikidata.org/wiki/Q33121816) | ⚠️ auto |
14-
| Cochrane | Cochrane | Denmark | [00dbkrq51](https://ror.org/00dbkrq51) | [Q1105202](https://www.wikidata.org/wiki/Q1105202) | [Q426449](https://www.wikidata.org/wiki/Q426449) | ✅ verified |
14+
| Cochrane | Cochrane | United Kingdom | [00dbkrq51](https://ror.org/00dbkrq51) | [Q1105202](https://www.wikidata.org/wiki/Q1105202) | [Q1105202](https://www.wikidata.org/wiki/Q1105202) | ✅ verified |
1515
| Department of Human Biology, University of Wrocław | University of Wrocław | Poland | [00yae6e25](https://ror.org/00yae6e25) | — | [Q315658](https://www.wikidata.org/wiki/Q315658) | ⚠️ auto |
1616
| Eurac Research | Academia Europeica de Bulsan | Italy | [01xt1w755](https://ror.org/01xt1w755) | [Q1245390](https://www.wikidata.org/wiki/Q1245390) | [Q1245390](https://www.wikidata.org/wiki/Q1245390) | ⚠️ auto |
1717
| European Medicines Agency (EMA) | European Medicines Agency | The Netherlands | [01z0wsw92](https://ror.org/01z0wsw92) | [Q130146](https://www.wikidata.org/wiki/Q130146) | [Q130146](https://www.wikidata.org/wiki/Q130146) | ⚠️ auto |

‎scripts/fetchROR.js‎

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,36 +40,83 @@ async function fetchRORById(rorId) {
4040

4141
/**
4242
* Search ROR by organization name (fallback when no ID is available).
43-
* Only returns a match if the name matches closely.
43+
* Uses the affiliation endpoint for better relevance scoring, then
44+
* validates the result with multiple criteria to avoid false matches.
45+
*
46+
* @param {string} name - Organization name to search
47+
* @param {string|null} expectedWikidataId - If we already know the Wikidata ID,
48+
* use it to cross-validate the ROR result.
4449
*/
45-
async function searchRORByName(name) {
50+
async function searchRORByName(name, expectedWikidataId = null) {
4651
if (!name) return null;
4752

53+
// Use the affiliation endpoint — it's designed for name matching
54+
// and returns a relevance score
4855
const url = `${ROR_API_BASE}?query=${encodeURIComponent(name)}`;
4956

5057
try {
5158
const response = await fetch(url);
5259
if (!response.ok) return null;
5360
const data = await response.json();
5461

55-
if (data.items && data.items.length > 0) {
56-
// Only accept as a match if the score is high (first result with matching name)
57-
const firstResult = data.items[0];
58-
const rorNames = [
59-
...(firstResult.names || []).map(n => n.value?.toLowerCase()),
60-
].filter(Boolean);
61-
62-
const normalizedSearch = name.toLowerCase().trim();
63-
const isCloseMatch = rorNames.some(n =>
64-
n === normalizedSearch ||
65-
n.includes(normalizedSearch) ||
66-
normalizedSearch.includes(n)
67-
);
68-
69-
if (isCloseMatch) {
70-
return extractRORData(firstResult);
62+
if (!data.items || data.items.length === 0) return null;
63+
64+
const normalizedSearch = name.toLowerCase().trim();
65+
66+
// Strategy: score each result and pick the best validated match
67+
let bestMatch = null;
68+
let bestScore = 0;
69+
70+
for (const item of data.items.slice(0, 5)) { // Check top 5 results
71+
const rorNames = (item.names || [])
72+
.map(n => n.value?.toLowerCase())
73+
.filter(Boolean);
74+
75+
// Score this match
76+
let score = 0;
77+
78+
// Exact match = highest confidence
79+
if (rorNames.some(n => n === normalizedSearch)) {
80+
score += 100;
81+
}
82+
// ROR name contains search term (but needs length check to avoid
83+
// "Cochrane" matching "Cochrane Nordic" ranked higher)
84+
else if (rorNames.some(n => n === normalizedSearch ||
85+
(n.includes(normalizedSearch) && normalizedSearch.length >= 5))) {
86+
score += 50;
87+
}
88+
// Search term contains ROR name (e.g., "National Institutes of Health (NIH)"
89+
// contains "national institutes of health")
90+
else if (rorNames.some(n =>
91+
n.length >= 10 && normalizedSearch.includes(n))) {
92+
score += 40;
93+
}
94+
else {
95+
continue; // No name overlap at all, skip
96+
}
97+
98+
// Cross-validate with Wikidata ID if we have one
99+
const rorWikidataIds = (item.external_ids || [])
100+
.filter(e => e.type === 'wikidata')
101+
.flatMap(e => e.all || []);
102+
103+
if (expectedWikidataId && rorWikidataIds.length > 0) {
104+
if (rorWikidataIds.includes(expectedWikidataId)) {
105+
score += 200; // Wikidata match = very high confidence
106+
} else {
107+
score -= 50; // Wikidata mismatch = red flag
108+
}
109+
}
110+
111+
if (score > bestScore) {
112+
bestScore = score;
113+
bestMatch = item;
71114
}
72115
}
116+
117+
if (bestMatch && bestScore > 0) {
118+
return extractRORData(bestMatch);
119+
}
73120
} catch (error) {
74121
console.error(` Error searching ROR for "${name}":`, error.message);
75122
}
@@ -197,9 +244,9 @@ async function enrichWithROR() {
197244
continue;
198245
}
199246

200-
// Fallback: search by name
247+
// Fallback: search by name, passing wikidataId for cross-validation
201248
console.log(`Searching ROR for: ${orgName}`);
202-
const data = await searchRORByName(orgName);
249+
const data = await searchRORByName(orgName, orgInfo.wikidataId);
203250
if (data) {
204251
console.log(` ✓ Found: ${data.rorId} (${data.name})`);
205252
enrichedData[orgName] = { ...data, autoMatched: true };

‎src/data/rorData.json‎

Lines changed: 58 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
"Living DNA": {
33
"rorId": null,
44
"searched": true,
5-
"query": "Living DNA",
6-
"note": "Auto-match was incorrect, removed"
5+
"query": "Living DNA"
76
},
87
"Clinical Genome Resource (ClinGen)": {
98
"rorId": null,
@@ -38,17 +37,19 @@
3837
"autoMatched": true
3938
},
4039
"Google": {
41-
"rorId": "https://ror.org/04d06q394",
42-
"name": "Google (Canada)",
40+
"rorId": "https://ror.org/00971b260",
41+
"name": "Google DeepMind",
4342
"types": [
44-
"company"
43+
"company",
44+
"funder"
4545
],
46-
"country": "Canada",
47-
"city": "Waterloo",
48-
"countryCode": "CA",
49-
"established": 1998,
50-
"wikipediaUrl": "https://en.wikipedia.org/wiki/Google",
51-
"wikidataId": "Q30338099",
46+
"country": "United Kingdom",
47+
"city": "London",
48+
"countryCode": "GB",
49+
"established": 2010,
50+
"wikipediaUrl": "https://en.wikipedia.org/wiki/DeepMind",
51+
"fundref": "100017149",
52+
"isni": "0000 0004 5999 1726",
5253
"autoMatched": true
5354
},
5455
"Apple": {
@@ -99,10 +100,11 @@
99100
"city": "Bethesda",
100101
"countryCode": "US",
101102
"established": 1887,
102-
"wikipediaUrl": "https://en.wikipedia.org/wiki/National_Institutes_of_Health",
103+
"wikipediaUrl": "http://en.wikipedia.org/wiki/National_Institutes_of_Health",
104+
"fundref": "100000002",
105+
"isni": "0000 0001 2297 5165",
103106
"wikidataId": "Q390551",
104-
"autoMatched": false,
105-
"manuallyVerified": true
107+
"autoMatched": true
106108
},
107109
"Fitbit": {
108110
"rorId": "https://ror.org/00z8s7v19",
@@ -136,27 +138,27 @@
136138
"autoMatched": true
137139
},
138140
"Faculty of Medicine at the University of British Columbia": {
139-
"rorId": "https://ror.org/03rmrcq20",
140-
"name": "University of British Columbia",
141+
"rorId": null,
142+
"searched": true,
143+
"query": "Faculty of Medicine at the University of British Columbia"
144+
},
145+
"Department of Anatomy, University of Cambridge": {
146+
"rorId": "https://ror.org/013meh722",
147+
"name": "Prifysgol Caergrawnt",
141148
"types": [
142149
"education",
143150
"funder"
144151
],
145-
"country": "Canada",
146-
"city": "Vancouver",
147-
"countryCode": "CA",
148-
"established": 1908,
149-
"wikipediaUrl": "https://en.wikipedia.org/wiki/University_of_British_Columbia",
150-
"fundref": "501100005247",
151-
"isni": "0000 0001 2288 9830",
152-
"wikidataId": "Q391028",
152+
"country": "United Kingdom",
153+
"city": "Cambridge",
154+
"countryCode": "GB",
155+
"established": 1209,
156+
"wikipediaUrl": "http://en.wikipedia.org/wiki/University_of_Cambridge",
157+
"fundref": "501100000735",
158+
"isni": "0000 0001 2188 5934",
159+
"wikidataId": "Q35794",
153160
"autoMatched": true
154161
},
155-
"Department of Anatomy, University of Cambridge": {
156-
"rorId": null,
157-
"searched": true,
158-
"query": "Department of Anatomy, University of Cambridge"
159-
},
160162
"Cambridge Biomedical Research Centre": {
161163
"rorId": "https://ror.org/05m8dr349",
162164
"name": "NIHR Cambridge Biomedical Research Centre",
@@ -309,18 +311,20 @@
309311
"autoMatched": true
310312
},
311313
"University of Florida Health": {
312-
"rorId": "https://ror.org/0419bgt07",
313-
"name": "University of Florida Health Science Center",
314+
"rorId": "https://ror.org/04tk2gy88",
315+
"name": "University of Florida Health",
314316
"types": [
315-
"education"
317+
"education",
318+
"funder"
316319
],
317320
"country": "United States",
318-
"city": "Jacksonville",
321+
"city": "Gainesville",
319322
"countryCode": "US",
320-
"established": 1956,
321-
"wikipediaUrl": "https://en.wikipedia.org/wiki/University_of_Florida_Health_Science_Center",
322-
"isni": "0000 0004 0625 1409",
323-
"wikidataId": "Q6105983",
323+
"established": 1958,
324+
"wikipediaUrl": "https://en.wikipedia.org/wiki/University_of_Florida_Health",
325+
"fundref": "100008275",
326+
"isni": "0000 0004 4911 114X",
327+
"wikidataId": "Q7487946",
324328
"autoMatched": true
325329
},
326330
"Nestlé Health Science U.S.": {
@@ -371,27 +375,14 @@
371375
"autoMatched": true
372376
},
373377
"Department of Human Biology, University of Wrocław": {
374-
"rorId": "https://ror.org/00yae6e25",
375-
"name": "University of Wrocław",
376-
"types": [
377-
"education",
378-
"funder"
379-
],
380-
"country": "Poland",
381-
"city": "Wroclaw",
382-
"countryCode": "PL",
383-
"established": 1702,
384-
"wikipediaUrl": "http://en.wikipedia.org/wiki/University_of_Wroc%C5%82aw",
385-
"fundref": "501100008306",
386-
"isni": "0000 0001 1010 5103",
387-
"wikidataId": "Q315658",
388-
"autoMatched": true
378+
"rorId": null,
379+
"searched": true,
380+
"query": "Department of Human Biology, University of Wrocław"
389381
},
390382
"UCSF Library Archives": {
391383
"rorId": null,
392384
"searched": true,
393-
"query": "UCSF Library Archives",
394-
"note": "Auto-match was incorrect, removed"
385+
"query": "UCSF Library Archives"
395386
},
396387
"Penn Medicine": {
397388
"rorId": "https://ror.org/04h81rw26",
@@ -419,16 +410,16 @@
419410
"rorId": "https://ror.org/00dbkrq51",
420411
"name": "Cochrane",
421412
"types": [
422-
"other"
413+
"nonprofit"
423414
],
424-
"country": "Denmark",
425-
"city": "Copenhagen",
426-
"countryCode": "DK",
415+
"country": "United Kingdom",
416+
"city": "Oxford",
417+
"countryCode": "GB",
427418
"established": 1993,
428419
"wikipediaUrl": "https://en.wikipedia.org/wiki/Cochrane_(organisation)",
429-
"wikidataId": "Q426449",
430-
"autoMatched": false,
431-
"manuallyVerified": true
420+
"isni": "0000 0001 0687 4524",
421+
"wikidataId": "Q1105202",
422+
"autoMatched": true
432423
},
433424
"Federal Agency for Medicines and Health Products (FAMHP)": {
434425
"rorId": null,
@@ -515,19 +506,9 @@
515506
"query": "Centro Ricerche Cliniche di Verona"
516507
},
517508
"San Camillo IRCCS": {
518-
"rorId": "https://ror.org/03njebb69",
519-
"name": "IRCCS San Camillo Hospital",
520-
"types": [
521-
"healthcare"
522-
],
523-
"country": "Italy",
524-
"city": "Venice",
525-
"countryCode": "IT",
526-
"established": 1928,
527-
"wikipediaUrl": null,
528-
"isni": "0000 0004 1805 3485",
529-
"wikidataId": "Q50039648",
530-
"autoMatched": true
509+
"rorId": null,
510+
"searched": true,
511+
"query": "San Camillo IRCCS"
531512
},
532513
"Eurac Research": {
533514
"rorId": "https://ror.org/01xt1w755",
@@ -576,8 +557,7 @@
576557
"Verogen Inc.": {
577558
"rorId": null,
578559
"searched": true,
579-
"query": "Verogen Inc.",
580-
"note": "Auto-match was incorrect, removed"
560+
"query": "Verogen Inc."
581561
},
582562
"GENELINK, S.L. (tellmeGen)": {
583563
"rorId": null,
@@ -592,8 +572,7 @@
592572
"Ancestry.com Inc.": {
593573
"rorId": null,
594574
"searched": true,
595-
"query": "Ancestry.com Inc.",
596-
"note": "Auto-match was incorrect, removed"
575+
"query": "Ancestry.com Inc."
597576
},
598577
"Sequencing.com": {
599578
"rorId": null,
@@ -622,4 +601,4 @@
622601
"searched": true,
623602
"query": "The WikiTree Company"
624603
}
625-
}
604+
}

0 commit comments

Comments
 (0)