From 085d1467044306138586264c1aeed6d104700c79 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:07:57 -0400 Subject: [PATCH 1/8] feat: use lookup_and_score --- src/index.ts | 2 +- src/inferred_mode/inferred_mode.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index cc4c6e01..b81b67a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -333,7 +333,7 @@ export default class TRAPIQueryHandler { description: `Query processed successfully, retrieved ${results.length} results.`, schema_version: global.SCHEMA_VERSION, biolink_version: global.BIOLINK_VERSION, - workflow: [{ id: 'lookup' }], + workflow: [{ id: 'lookup_and_score' }], message: { query_graph: this.originalQueryGraph, knowledge_graph: this.knowledgeGraph.kg, diff --git a/src/inferred_mode/inferred_mode.ts b/src/inferred_mode/inferred_mode.ts index cd360243..db8d6a71 100644 --- a/src/inferred_mode/inferred_mode.ts +++ b/src/inferred_mode/inferred_mode.ts @@ -498,7 +498,7 @@ export default class InferredQueryHandler { description: '', schema_version: global.SCHEMA_VERSION, biolink_version: global.BIOLINK_VERSION, - workflow: [{ id: 'lookup' }], + workflow: [{ id: 'lookup_and_score' }], message: { query_graph: this.queryGraph, knowledge_graph: { From 112b775f6eafb58ce6b017ea7b1da020c03e6556 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:54:05 -0400 Subject: [PATCH 2/8] feat: node/edge bindings & auxgraph attributes --- src/index.ts | 6 +++--- src/inferred_mode/inferred_mode.ts | 9 +++++---- src/results_assembly/query_results.ts | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index cc4c6e01..30764a9a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -209,7 +209,7 @@ export default class TRAPIQueryHandler { suffix += 1; } const supportGraphID = `support${suffix}-${boundEdgeID}`; - auxGraphs[supportGraphID] = { edges: supportGraph }; + auxGraphs[supportGraphID] = { edges: supportGraph, attributes: [] }; if (!edgesIDsByAuxGraphID[supportGraphID]) { edgesIDsByAuxGraphID[supportGraphID] = new Set(); } @@ -250,7 +250,7 @@ export default class TRAPIQueryHandler { boundIDs.add(binding.id); } } else if (!boundIDs.has(nodesToRebind[binding.id].newNode)) { - newBindings.push({ id: nodesToRebind[binding.id].newNode }); + newBindings.push({ id: nodesToRebind[binding.id].newNode, attributes: [] }); boundIDs.add(nodesToRebind[binding.id].newNode); } return { boundIDs, newBindings }; @@ -272,7 +272,7 @@ export default class TRAPIQueryHandler { boundIDs.add(binding.id); } } else if (!boundIDs.has(edgesToRebind[binding.id])) { - newBindings.push({ id: edgesToRebind[binding.id] }); + newBindings.push({ id: edgesToRebind[binding.id], attributes: [] }); boundIDs.add(edgesToRebind[binding.id]); resultBoundEdgesWithAuxGraphs.add(edgesToRebind[binding.id]); } diff --git a/src/inferred_mode/inferred_mode.ts b/src/inferred_mode/inferred_mode.ts index cd360243..ec798dd6 100644 --- a/src/inferred_mode/inferred_mode.ts +++ b/src/inferred_mode/inferred_mode.ts @@ -288,8 +288,8 @@ export default class InferredQueryHandler { newResponse.message.results.forEach((result) => { const translatedResult: TrapiResult = { node_bindings: { - [qEdge.subject]: [{ id: result.node_bindings.creativeQuerySubject[0].id }], - [qEdge.object]: [{ id: result.node_bindings.creativeQueryObject[0].id }], + [qEdge.subject]: [{ id: result.node_bindings.creativeQuerySubject[0].id, attributes: [] }], + [qEdge.object]: [{ id: result.node_bindings.creativeQueryObject[0].id, attributes: [] }], }, pfocr: result.pfocr?.length ? result.pfocr : undefined, analyses: [ @@ -311,14 +311,14 @@ export default class InferredQueryHandler { // Direct edge answers stand on their own, not as an inferred edge. if (Object.keys(result.node_bindings).length == 2) { const boundEdgeID = Object.values(result.analyses[0].edge_bindings)[0][0].id; - translatedResult.analyses[0].edge_bindings = { [qEdgeID]: [{ id: boundEdgeID }] }; + translatedResult.analyses[0].edge_bindings = { [qEdgeID]: [{ id: boundEdgeID, attributes: [] }] }; } else { // Create an aux graph using the result and associate it with an inferred Edge const inferredEdgeID = `inferred-${resultCreativeSubjectID}-${qEdge.predicates[0].replace( 'biolink:', '', )}-${resultCreativeObjectID}`; - translatedResult.analyses[0].edge_bindings = { [qEdgeID]: [{ id: inferredEdgeID }] }; + translatedResult.analyses[0].edge_bindings = { [qEdgeID]: [{ id: inferredEdgeID, attributes: [] }] }; if (!combinedResponse.message.knowledge_graph.edges[inferredEdgeID]) { combinedResponse.message.knowledge_graph.edges[inferredEdgeID] = { subject: resultCreativeSubjectID, @@ -353,6 +353,7 @@ export default class InferredQueryHandler { }, [] as string[], ), + attributes: [] }; } diff --git a/src/results_assembly/query_results.ts b/src/results_assembly/query_results.ts index 026556fc..d3c104d3 100644 --- a/src/results_assembly/query_results.ts +++ b/src/results_assembly/query_results.ts @@ -452,18 +452,21 @@ export default class TrapiResultsAssembler { result.node_bindings[inputQNodeID] = Array.from(inputPrimaryCuries).map((inputPrimaryCurie) => { return { id: inputPrimaryCurie, + attributes: [], }; }); result.node_bindings[outputQNodeID] = Array.from(outputPrimaryCuries).map((outputPrimaryCurie) => { return { id: outputPrimaryCurie, + attributes: [], }; }); result.analyses[0].edge_bindings[qEdgeID] = Array.from(recordHashes).map((recordHash) => { return { id: recordHash, + attributes: [], }; }); }, From 1838d58ead6da2c0861923a530a43f6d0d6a59f0 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:55:15 -0400 Subject: [PATCH 3/8] refactor: use TRAPI types from types package --- src/cache_handler.ts | 10 +- src/graph/graph.ts | 4 +- src/graph/kg_edge.ts | 6 +- src/graph/kg_node.ts | 2 +- src/graph/knowledge_graph.ts | 2 +- src/index.ts | 2 +- src/inferred_mode/inferred_mode.ts | 23 ++-- src/inferred_mode/template_lookup.ts | 3 +- src/query_edge.ts | 2 +- src/query_graph.ts | 2 +- src/results_assembly/pfocr.ts | 2 +- src/results_assembly/query_results.ts | 2 +- src/types.ts | 148 -------------------------- src/update_nodes.ts | 2 +- 14 files changed, 33 insertions(+), 177 deletions(-) diff --git a/src/cache_handler.ts b/src/cache_handler.ts index 5b3bbbc7..a52c6d1f 100644 --- a/src/cache_handler.ts +++ b/src/cache_handler.ts @@ -9,7 +9,7 @@ import chunker from 'stream-chunker'; import { Readable, Transform } from 'stream'; import { Record, RecordPackage } from '@biothings-explorer/api-response-transform'; import { threadId } from 'worker_threads'; -import MetaKG from '../../smartapi-kg/built'; +import MetaKG from '@biothings-explorer/smartapi-kg'; import QEdge from './query_edge'; import { QueryHandlerOptions } from '@biothings-explorer/types'; @@ -113,7 +113,7 @@ export default class CacheHandler { } async categorizeEdges(qEdges: QEdge[]): Promise<{ cachedRecords: Record[]; nonCachedQEdges: QEdge[] }> { - if (this.cacheEnabled === false || process.env.INTERNAL_DISABLE_REDIS === "true") { + if (this.cacheEnabled === false || process.env.INTERNAL_DISABLE_REDIS === 'true') { return { cachedRecords: [], nonCachedQEdges: qEdges, @@ -210,7 +210,7 @@ export default class CacheHandler { } async cacheEdges(queryRecords: Record[]): Promise { - if (this.cacheEnabled === false || process.env.INTERNAL_DISABLE_REDIS === "true") { + if (this.cacheEnabled === false || process.env.INTERNAL_DISABLE_REDIS === 'true') { if (global.parentPort) { global.parentPort.postMessage({ threadId, cacheDone: true }); } @@ -257,8 +257,8 @@ export default class CacheHandler { resolve(); }); }); - if (process.env.QEDGE_CACHE_TIME_S !== "0") { - await redisClient.client.expireTimeout(redisID, process.env.QEDGE_CACHE_TIME_S || 1800); + if (process.env.QEDGE_CACHE_TIME_S !== '0') { + await redisClient.client.expireTimeout(redisID, process.env.QEDGE_CACHE_TIME_S || 1800); } } catch (error) { failedHashes.push(hash); diff --git a/src/graph/graph.ts b/src/graph/graph.ts index 018a096b..0fc57c8f 100644 --- a/src/graph/graph.ts +++ b/src/graph/graph.ts @@ -4,8 +4,8 @@ import Debug from 'debug'; import { LogEntry, StampedLog } from '@biothings-explorer/utils'; import KGNode from './kg_node'; import KGEdge from './kg_edge'; -import { Record } from '../../../api-response-transform/built'; -import { TrapiAuxiliaryGraph, TrapiResult } from '../types'; +import { Record } from '@biothings-explorer/api-response-transform'; +import { TrapiAuxiliaryGraph, TrapiResult } from '@biothings-explorer/types'; import KnowledgeGraph from './knowledge_graph'; const debug = Debug('bte:biothings-explorer-trapi:Graph'); diff --git a/src/graph/kg_edge.ts b/src/graph/kg_edge.ts index d6422ab4..b70ede02 100644 --- a/src/graph/kg_edge.ts +++ b/src/graph/kg_edge.ts @@ -1,5 +1,5 @@ -import { ProvenanceChainItem } from '@biothings-explorer/api-response-transform'; -import { TrapiAttribute } from '../types'; +import { TrapiSource } from '@biothings-explorer/types'; +import { TrapiAttribute } from '@biothings-explorer/types'; export interface KGEdgeInfo { object: string; @@ -68,7 +68,7 @@ export default class KGEdge { }); } - addSource(source: ProvenanceChainItem | ProvenanceChainItem[]): void { + addSource(source: TrapiSource | TrapiSource[]): void { if (typeof source === 'undefined') { return; } diff --git a/src/graph/kg_node.ts b/src/graph/kg_node.ts index cf16dfeb..60dac19f 100644 --- a/src/graph/kg_node.ts +++ b/src/graph/kg_node.ts @@ -1,4 +1,4 @@ -import { TrapiAttribute } from '../types'; +import { TrapiAttribute } from '@biothings-explorer/types'; export interface KGNodeInfo { label: string; diff --git a/src/graph/knowledge_graph.ts b/src/graph/knowledge_graph.ts index 0ac539cd..c495c5a2 100644 --- a/src/graph/knowledge_graph.ts +++ b/src/graph/knowledge_graph.ts @@ -9,7 +9,7 @@ import { TrapiKGNodes, TrapiQualifier, TrapiSource, -} from '../types'; +} from '@biothings-explorer/types'; import KGNode from './kg_node'; import KGEdge from './kg_edge'; import { BTEGraphUpdate } from './graph'; diff --git a/src/index.ts b/src/index.ts index cc4c6e01..57e08824 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,7 +24,7 @@ import { TrapiQueryGraph, TrapiResponse, TrapiResult, -} from './types'; +} from '@biothings-explorer/types'; import { QueryHandlerOptions } from '@biothings-explorer/types'; import BTEGraph from './graph/graph'; import QEdge from './query_edge'; diff --git a/src/inferred_mode/inferred_mode.ts b/src/inferred_mode/inferred_mode.ts index cd360243..21eef44a 100644 --- a/src/inferred_mode/inferred_mode.ts +++ b/src/inferred_mode/inferred_mode.ts @@ -6,9 +6,8 @@ import biolink from '../biolink'; import { getTemplates, MatchedTemplate, TemplateLookup } from './template_lookup'; import { scaled_sigmoid, inverse_scaled_sigmoid } from '../results_assembly/score'; import TRAPIQueryHandler from '../index'; -import { QueryHandlerOptions } from '@biothings-explorer/types'; import { - CompactQualifiers, + QueryHandlerOptions, TrapiAuxGraphCollection, TrapiEdgeBinding, TrapiKnowledgeGraph, @@ -17,7 +16,8 @@ import { TrapiQueryGraph, TrapiResponse, TrapiResult, -} from '../types'; +} from '@biothings-explorer/types'; +import { CompactQualifiers } from '../index'; const debug = Debug('bte:biothings-explorer-trapi:inferred-mode'); export interface CombinedResponse { @@ -385,9 +385,9 @@ export default class InferredQueryHandler { if (typeof combinedResponse.message.results[resultID].analyses[0].score !== 'undefined') { combinedResponse.message.results[resultID].analyses[0].score = resScore ? scaled_sigmoid( - inverse_scaled_sigmoid(combinedResponse.message.results[resultID].analyses[0].score) + - inverse_scaled_sigmoid(resScore), - ) + inverse_scaled_sigmoid(combinedResponse.message.results[resultID].analyses[0].score) + + inverse_scaled_sigmoid(resScore), + ) : combinedResponse.message.results[resultID].analyses[0].score; } else { combinedResponse.message.results[resultID].analyses[0].score = resScore; @@ -555,9 +555,11 @@ export default class InferredQueryHandler { const message = [ `Addition of ${creativeLimitHit} results from Template ${i + 1}`, Object.keys(combinedResponse.message.results).length === this.CREATIVE_LIMIT ? ' meets ' : ' exceeds ', - `creative result maximum of ${this.CREATIVE_LIMIT} (reaching ${Object.keys(combinedResponse.message.results).length + `creative result maximum of ${this.CREATIVE_LIMIT} (reaching ${ + Object.keys(combinedResponse.message.results).length } merged). `, - `Response will be truncated to top-scoring ${this.CREATIVE_LIMIT} results. Skipping remaining ${subQueries.length - (i + 1) + `Response will be truncated to top-scoring ${this.CREATIVE_LIMIT} results. Skipping remaining ${ + subQueries.length - (i + 1) } `, subQueries.length - (i + 1) === 1 ? `template.` : `templates.`, ].join(''); @@ -582,8 +584,9 @@ export default class InferredQueryHandler { const total = Object.values(mergedResultsCount).reduce((sum, count) => sum + count, 0) + Object.keys(mergedResultsCount).length; - const message = `Merging Summary: (${total}) inferred-template results were merged into (${Object.keys(mergedResultsCount).length - }) final results, reducing result count by (${total - Object.keys(mergedResultsCount).length})`; + const message = `Merging Summary: (${total}) inferred-template results were merged into (${ + Object.keys(mergedResultsCount).length + }) final results, reducing result count by (${total - Object.keys(mergedResultsCount).length})`; debug(message); combinedResponse.logs.push(new LogEntry('INFO', null, message).getLog()); } diff --git a/src/inferred_mode/template_lookup.ts b/src/inferred_mode/template_lookup.ts index 100dc5cc..e32973cb 100644 --- a/src/inferred_mode/template_lookup.ts +++ b/src/inferred_mode/template_lookup.ts @@ -2,7 +2,8 @@ import { promises as fs } from 'fs'; import path from 'path'; import async from 'async'; -import { TrapiQueryGraph, CompactQualifiers } from '../types'; +import { TrapiQueryGraph } from '@biothings-explorer/types'; +import { CompactQualifiers } from '../types'; export interface TemplateLookup { subject: string; diff --git a/src/query_edge.ts b/src/query_edge.ts index e380b51c..a9513741 100644 --- a/src/query_edge.ts +++ b/src/query_edge.ts @@ -6,7 +6,7 @@ import { Record, RecordNode, FrozenRecord } from '@biothings-explorer/api-respon import QNode from './query_node'; import { QNodeInfo } from './query_node'; import { LogEntry, StampedLog } from '@biothings-explorer/utils'; -import { TrapiAttributeConstraint, TrapiQualifierConstraint } from './types'; +import { TrapiAttributeConstraint, TrapiQualifierConstraint } from '@biothings-explorer/types'; const debug = Debug('bte:biothings-explorer-trapi:QEdge'); diff --git a/src/query_graph.ts b/src/query_graph.ts index 7a6f9d80..df95c906 100644 --- a/src/query_graph.ts +++ b/src/query_graph.ts @@ -7,7 +7,7 @@ import biolink from './biolink'; import { resolveSRI } from 'biomedical_id_resolver'; import _ from 'lodash'; import * as utils from './utils'; -import { TrapiQueryGraph } from './types'; +import { TrapiQueryGraph } from '@biothings-explorer/types'; const debug = Debug('bte:biothings-explorer-trapi:query_graph'); diff --git a/src/results_assembly/pfocr.ts b/src/results_assembly/pfocr.ts index 1afd52b4..7f68528c 100644 --- a/src/results_assembly/pfocr.ts +++ b/src/results_assembly/pfocr.ts @@ -4,7 +4,7 @@ const debug = Debug('bte:biothings-explorer-trapi:pfocr'); import { intersection } from '../utils'; import _ from 'lodash'; import { LogEntry, StampedLog } from '@biothings-explorer/utils'; -import { TrapiResult } from '../types'; +import { TrapiResult } from '@biothings-explorer/types'; // the minimum acceptable intersection size between the CURIEs // in a TRAPI result and in a PFOCR figure. diff --git a/src/results_assembly/query_results.ts b/src/results_assembly/query_results.ts index 026556fc..bc6effdd 100644 --- a/src/results_assembly/query_results.ts +++ b/src/results_assembly/query_results.ts @@ -1,5 +1,5 @@ import { LogEntry, StampedLog } from '@biothings-explorer/utils'; -import { TrapiResult } from '../types'; +import { TrapiResult } from '@biothings-explorer/types'; import Debug from 'debug'; import { zip } from 'lodash'; const debug = Debug('bte:biothings-explorer-trapi:QueryResult'); diff --git a/src/types.ts b/src/types.ts index 77ac472e..21388766 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,153 +1,5 @@ import { TrapiLog } from '@biothings-explorer/utils'; -export interface TrapiQNode { - ids?: string[]; - categories?: string[]; - is_set?: boolean; - constraints?: TrapiAttributeConstraint[]; -} - -export interface TrapiQEdge { - knowledge_type?: string; - predicates?: string[]; - subject: string; - object: string; - attribute_constraints?: TrapiAttributeConstraint[]; - qualifier_constraints?: TrapiQualifierConstraint[]; -} - -export interface TrapiQueryGraph { - nodes: { - [QNodeID: string]: TrapiQNode; - }; - edges: { - [QEdgeID: string]: TrapiQEdge; - }; -} - -export interface TrapiSource { - resource_id: string; - resource_role: string; - upstream_resource_ids?: string[]; -} - -export interface TrapiKGNodes { - [nodeID: string]: TrapiKGNode; -} - -export interface TrapiKGEdges { - [edgeID: string]: TrapiKGEdge; -} - -export interface TrapiKnowledgeGraph { - nodes: TrapiKGNodes; - edges: TrapiKGEdges; -} - -export interface TrapiKGEdge { - predicate: string; - subject: string; - object: string; - attributes?: TrapiAttribute[]; - qualifiers?: TrapiQualifier[]; - sources: TrapiSource[]; -} - -export interface TrapiKGNode { - categories: string[]; - name: string; - attributes?: TrapiAttribute[]; -} - -export interface TrapiAttribute { - attribute_type_id: string; - original_attribute_name?: string; - value: string | string[] | number | number[]; - value_type_id?: string; - attribute_source?: string | null; - value_url?: string | null; - attributes?: TrapiAttribute; - [additionalProperties: string]: string | string[] | null | TrapiAttribute | number | number[]; -} - -export interface TrapiQualifier { - qualifier_type_id: string; - qualifier_value: string | string[]; -} - -export interface TrapiQualifierConstraint { - qualifier_set: TrapiQualifier[]; -} - -export interface TrapiAttributeConstraint { - id: string; - name: string; - not: boolean; - operator: string; - value: string | string[] | number | number[]; -} - -export interface TrapiNodeBinding { - id: string; - query_id?: string; - attributes?: TrapiAttribute[]; -} - -export interface TrapiEdgeBinding { - id: string; - attributes?: TrapiAttribute[]; -} - -export interface TrapiAnalysis { - resource_id?: string; - score?: number; - edge_bindings: { - [qEdgeID: string]: TrapiEdgeBinding[]; - }; - support_graphs?: string[]; - scoring_method?: string; - attributes?: TrapiAttribute[]; -} - -export interface TrapiAuxiliaryGraph { - edges: string[]; - attributes?: TrapiAttribute[]; -} - -export interface TrapiPfocrFigure { - figureUrl: string; - pmc: string; - matchedCuries: string[]; - score: number; -} - -export interface TrapiResult { - node_bindings: { - [qNodeID: string]: TrapiNodeBinding[]; - }; - analyses: TrapiAnalysis[]; - pfocr?: TrapiPfocrFigure[]; -} - -export interface TrapiAuxGraphCollection { - [supportGraphID: string]: TrapiAuxiliaryGraph; -} - -export interface TrapiResponse { - description?: string; - schema_version?: string; - biolink_version?: string; - workflow?: { id: string }[]; - message: { - query_graph: TrapiQueryGraph; - knowledge_graph: TrapiKnowledgeGraph; - auxiliary_graphs?: TrapiAuxGraphCollection; - results: TrapiResult[]; - }; - logs: TrapiLog[]; -} - - export interface UnavailableAPITracker { [server: string]: { skip: boolean; skippedQueries: number }; } diff --git a/src/update_nodes.ts b/src/update_nodes.ts index e6df65a6..c9c30f93 100644 --- a/src/update_nodes.ts +++ b/src/update_nodes.ts @@ -3,7 +3,7 @@ import Debug from 'debug'; import { ResolverInput, SRIResolverOutput } from 'biomedical_id_resolver'; import { Record } from '@biothings-explorer/api-response-transform'; import QEdge from './query_edge'; -import { NodeNormalizerResultObj } from '../../api-response-transform/built'; +import { NodeNormalizerResultObj } from '@biothings-explorer/api-response-transform'; const debug = Debug('bte:biothings-explorer-trapi:nodeUpdateHandler'); export interface CuriesByCategory { From da17df0a33796fd8aa7dd511b89879371f4f3ab5 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:55:26 -0400 Subject: [PATCH 4/8] feat: support source_record_urls --- src/graph/kg_edge.ts | 14 +++++++++++--- src/graph/knowledge_graph.ts | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/graph/kg_edge.ts b/src/graph/kg_edge.ts index b70ede02..797c82f1 100644 --- a/src/graph/kg_edge.ts +++ b/src/graph/kg_edge.ts @@ -20,6 +20,7 @@ export default class KGEdge { resource_id: string; resource_role: string; upstream_resource_ids?: Set; + source_record_urls?: Set; }; }; }; @@ -77,19 +78,26 @@ export default class KGEdge { } source.forEach((item) => { if (!this.sources[item.resource_id]) this.sources[item.resource_id] = {}; + if (item.upstream_resource_ids && !Array.isArray(item.upstream_resource_ids)) { + item.upstream_resource_ids = [item.upstream_resource_ids]; + } + if (item.source_record_urls && !Array.isArray(item.source_record_urls)) { + item.source_record_urls = [item.source_record_urls]; + } if (!this.sources[item.resource_id][item.resource_role]) { this.sources[item.resource_id][item.resource_role] = { resource_id: item.resource_id, resource_role: item.resource_role, upstream_resource_ids: item.upstream_resource_ids ? new Set(item.upstream_resource_ids) : undefined, + source_record_urls: item.source_record_urls ? new Set(item.source_record_urls) : undefined, }; } - if (item.upstream_resource_ids && !Array.isArray(item.upstream_resource_ids)) { - item.upstream_resource_ids = [item.upstream_resource_ids]; - } item.upstream_resource_ids?.forEach((upstream) => this.sources[item.resource_id][item.resource_role].upstream_resource_ids.add(upstream), ); + item.source_record_urls?.forEach((url) => + this.sources[item.resource_id][item.resource_role].source_record_urls.add(url), + ); }); } diff --git a/src/graph/knowledge_graph.ts b/src/graph/knowledge_graph.ts index c495c5a2..12a53476 100644 --- a/src/graph/knowledge_graph.ts +++ b/src/graph/knowledge_graph.ts @@ -137,6 +137,7 @@ export default class KnowledgeGraph { const trapiSource: TrapiSource = { ...sourceObj, upstream_resource_ids: sourceObj.upstream_resource_ids ? [...sourceObj.upstream_resource_ids] : undefined, + source_record_urls: sourceObj.source_record_urls ? [...sourceObj.source_record_urls] : undefined, }; sources.push(trapiSource); }); From ded747cdfbc12e154e82a1e4b2400a533d4eb8d8 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 11 Apr 2024 17:45:25 -0400 Subject: [PATCH 5/8] feat: Add knowledge_level/agent_type to edges --- src/graph/graph.ts | 6 ++++++ src/index.ts | 4 ++++ src/inferred_mode/inferred_mode.ts | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/graph/graph.ts b/src/graph/graph.ts index 018a096b..6657ce16 100644 --- a/src/graph/graph.ts +++ b/src/graph/graph.ts @@ -104,6 +104,12 @@ export default class BTEGraph { .map((item) => { this.edges[recordHash].addAdditionalAttributes(item, record.mappedResponse[item]); }); + if (record.knowledge_level) { + this.edges[recordHash].addAdditionalAttributes('knowledge_level', record.knowledge_level); + } + if (record.agent_type) { + this.edges[recordHash].addAdditionalAttributes('agent_type', record.agent_type); + } this.edges[recordHash].addSource(record.provenanceChain); Object.entries(record.qualifiers).forEach(([qualifierType, qualifier]) => { this.edges[recordHash].addQualifier(qualifierType, qualifier); diff --git a/src/index.ts b/src/index.ts index cc4c6e01..75fee861 100644 --- a/src/index.ts +++ b/src/index.ts @@ -173,6 +173,8 @@ export default class TRAPIQueryHandler { const source = Object.entries(ontologyKnowledgeSourceMapping).find(([prefix]) => { return expanded.includes(prefix); })[1]; + subclassEdge.addAdditionalAttributes('biolink:knowledge_level', 'knowledge_assertion') + subclassEdge.addAdditionalAttributes('biolink:agent_type', 'manual_agent') subclassEdge.addSource([ { resource_id: source, resource_role: 'primary_knowledge_source' }, { @@ -221,6 +223,8 @@ export default class TRAPIQueryHandler { object: object, }); boundEdge.addAdditionalAttributes('biolink:support_graphs', [supportGraphID]); + boundEdge.addAdditionalAttributes('biolink:knowledge_level', 'logical_entailment') + boundEdge.addAdditionalAttributes('biolink:agent_type', 'automated_agent') boundEdge.addSource([ { resource_id: this.options.provenanceUsesServiceProvider diff --git a/src/inferred_mode/inferred_mode.ts b/src/inferred_mode/inferred_mode.ts index cd360243..e8acc251 100644 --- a/src/inferred_mode/inferred_mode.ts +++ b/src/inferred_mode/inferred_mode.ts @@ -332,7 +332,11 @@ export default class InferredQueryHandler { resource_role: 'primary_knowledge_source', }, ], - attributes: [{ attribute_type_id: 'biolink:support_graphs', value: [] }], + attributes: [ + { attribute_type_id: 'biolink:support_graphs', value: [] }, + { attribute_type_id: 'biolink:knowledge_level', value: "prediction" }, + { attribute_type_id: 'biolink:agent_type', value: "computational_model" }, + ], }; } let auxGraphSuffix = 0; From 1c7ecac8665a716dd59cd0f46ae1203eb43754a6 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:31:30 -0400 Subject: [PATCH 6/8] fix: condition --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index b81b67a8..a49ccecd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -333,7 +333,7 @@ export default class TRAPIQueryHandler { description: `Query processed successfully, retrieved ${results.length} results.`, schema_version: global.SCHEMA_VERSION, biolink_version: global.BIOLINK_VERSION, - workflow: [{ id: 'lookup_and_score' }], + workflow: [{ id: this.options.smartAPIID || this.options.teamName ? 'lookup' : 'lookup_and_score' }], message: { query_graph: this.originalQueryGraph, knowledge_graph: this.knowledgeGraph.kg, From 46e829894a1598700b69cdbc1f71e8112bdcf049 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:49:58 -0400 Subject: [PATCH 7/8] fix: biolink prefix --- src/graph/graph.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graph/graph.ts b/src/graph/graph.ts index 6657ce16..2124882e 100644 --- a/src/graph/graph.ts +++ b/src/graph/graph.ts @@ -105,10 +105,10 @@ export default class BTEGraph { this.edges[recordHash].addAdditionalAttributes(item, record.mappedResponse[item]); }); if (record.knowledge_level) { - this.edges[recordHash].addAdditionalAttributes('knowledge_level', record.knowledge_level); + this.edges[recordHash].addAdditionalAttributes('biolink:knowledge_level', record.knowledge_level); } if (record.agent_type) { - this.edges[recordHash].addAdditionalAttributes('agent_type', record.agent_type); + this.edges[recordHash].addAdditionalAttributes('biolink:agent_type', record.agent_type); } this.edges[recordHash].addSource(record.provenanceChain); Object.entries(record.qualifiers).forEach(([qualifierType, qualifier]) => { From ac88bfc065206b135b82f252df7a1ccf7760da1d Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:50:24 -0400 Subject: [PATCH 8/8] feat: handling for non-array values --- src/graph/knowledge_graph.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/graph/knowledge_graph.ts b/src/graph/knowledge_graph.ts index 0ac539cd..f416ba26 100644 --- a/src/graph/knowledge_graph.ts +++ b/src/graph/knowledge_graph.ts @@ -17,6 +17,8 @@ import { APIDefinition } from '@biothings-explorer/types'; const debug = Debug('bte:biothings-explorer-trapi:KnowledgeGraph'); +const NON_ARRAY_ATTRIBUTES = ['biolink:knowledge_level', 'biolink:agent_type']; + export default class KnowledgeGraph { nodes: { [nodePrimaryID: string]: TrapiKGNode; @@ -114,11 +116,14 @@ export default class KnowledgeGraph { } Object.entries(kgEdge.attributes).forEach(([key, value]) => { - if (key == 'edge-attributes') return; + if (key === 'edge-attributes') return; // if (key == 'edge-attributes') return; attributes.push({ attribute_type_id: key, - value: Array.from(value as Set), + value: // technically works for numbers as well + NON_ARRAY_ATTRIBUTES.includes(key) + ? [...(value as Set)].reduce((acc, val) => acc + val) + : Array.from(value as Set), //value_type_id: 'bts:' + key, }); });