Skip to content

Commit

Permalink
identify pathfinder queries. identify templates
Browse files Browse the repository at this point in the history
  • Loading branch information
rjawesome committed Mar 23, 2024
1 parent 559de80 commit 52bc25d
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
61 changes: 59 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ export default class TRAPIQueryHandler {

async _processQueryGraph(queryGraph: TrapiQueryGraph): Promise<QEdge[]> {
try {
const queryGraphHandler = new QueryGraph(queryGraph, this.options.schema);
const queryGraphHandler = new QueryGraph(queryGraph, this.options.schema, this._queryIsPathfinder());
const queryEdges = await queryGraphHandler.calculateEdges();
this.logs = [...this.logs, ...queryGraphHandler.logs];
return queryEdges;
Expand Down Expand Up @@ -509,6 +509,12 @@ export default class TRAPIQueryHandler {
}
}

_queryIsPathfinder(): boolean {
const inferredEdgeCount = Object.values(this.queryGraph.edges).reduce((i, edge) => i + (edge.knowledge_type === 'inferred' ? 1 : 0), 0);
const pinnedNodes = Object.values(this.queryGraph.nodes).reduce((i, node) => i + (node.ids != null ? 1 : 0), 0);
return inferredEdgeCount === 3 && pinnedNodes == 2 && Object.keys(this.queryGraph.edges).length === 3 && Object.keys(this.queryGraph.nodes).length === 3;
}

_queryUsesInferredMode(): boolean {
const inferredEdge = Object.values(this.queryGraph.edges).some((edge) => edge.knowledge_type === 'inferred');
return inferredEdge;
Expand All @@ -519,7 +525,50 @@ export default class TRAPIQueryHandler {
return oneHop;
}

async _handleInferredEdges(): Promise<void> {
async _handlePathfinder(): Promise<void> {
const [unpinnedNodeId, unpinnedNode] = Object.entries(this.queryGraph.nodes).find(([_, node]) => !node.ids);
// remove unpinned node & all edges involving unpinned node for now
delete this.queryGraph.nodes[unpinnedNodeId];
const intermediateEdges = Object.entries(this.queryGraph.edges).filter(([_, edge]) => edge.subject === unpinnedNodeId || edge.object === unpinnedNodeId);
const mainEdge = Object.entries(this.queryGraph.edges).find(([_, edge]) => edge.subject !== unpinnedNodeId && edge.object !== unpinnedNodeId);

// intermediateEdges should be in order of n0 -> un & un -> n1
if (intermediateEdges[0][1].subject === unpinnedNodeId) {
let temp = intermediateEdges[0];
intermediateEdges[0] = intermediateEdges[1];
intermediateEdges[1] = temp;
}

// remove intermediates for creative execution
intermediateEdges.forEach(([edgeId, _]) => delete this.queryGraph.edges[edgeId]);

if (Object.keys(this.queryGraph.edges).length !== 1) {
const message = 'Pathfinder Mode needs exactly one edge between nodes with IDs. Your query terminates.';
debug(message);
this.logs.push(new LogEntry('WARNING', null, message).getLog());
return;
}

if (intermediateEdges[0][1].subject !== mainEdge[1].subject || intermediateEdges[1][1].object !== mainEdge[1].object || intermediateEdges[0][1].object !== unpinnedNodeId || intermediateEdges[1][1].subject !== unpinnedNodeId) {
const message = 'Intermediate edges for Pathfinder are incorrect. Your query terminates.';
debug(message);
this.logs.push(new LogEntry('WARNING', null, message).getLog());
return;
}

// test
console.log("recognized pathfinder");

// run creative mode
await this._handleInferredEdges(true);
const creativeResponse = this.getResponse();

// restore query graph
this.queryGraph.nodes[unpinnedNodeId] = unpinnedNode;
intermediateEdges.forEach(([edgeId, edge]) => this.queryGraph.edges[edgeId] = edge);
}

async _handleInferredEdges(pathfinder = false): Promise<void> {
if (!this._queryIsOneHop()) {
const message = 'Inferred Mode edges are only supported in single-edge queries. Your query terminates.';
debug(message);
Expand All @@ -534,6 +583,7 @@ export default class TRAPIQueryHandler {
this.path,
this.predicatePath,
this.includeReasoner,
pathfinder
);
const inferredQueryResponse = await inferredQueryHandler.query();
if (inferredQueryResponse) {
Expand Down Expand Up @@ -668,6 +718,13 @@ export default class TRAPIQueryHandler {
}
debug(`(3) All edges created ${JSON.stringify(queryEdges)} `);

if (this._queryIsPathfinder()) {
const span2 = Telemetry.startSpan({ description: 'pathfinderExecution' });
await this._handlePathfinder();
span2?.finish();
return;
}

if (this._queryUsesInferredMode()) {
const span2 = Telemetry.startSpan({ description: 'creativeExecution' });
await this._handleInferredEdges();
Expand Down
7 changes: 5 additions & 2 deletions src/inferred_mode/inferred_mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default class InferredQueryHandler {
path: string;
predicatePath: string;
includeReasoner: boolean;
pathfinder: boolean;
CREATIVE_LIMIT: number;
constructor(
parent: TRAPIQueryHandler,
Expand All @@ -60,6 +61,7 @@ export default class InferredQueryHandler {
path: string,
predicatePath: string,
includeReasoner: boolean,
pathfinder: boolean
) {
this.parent = parent;
this.queryGraph = queryGraph;
Expand All @@ -68,6 +70,7 @@ export default class InferredQueryHandler {
this.path = path;
this.predicatePath = predicatePath;
this.includeReasoner = includeReasoner;
this.pathfinder = pathfinder;
this.CREATIVE_LIMIT = process.env.CREATIVE_LIMIT ? parseInt(process.env.CREATIVE_LIMIT) : 500;
}

Expand Down Expand Up @@ -107,7 +110,7 @@ export default class InferredQueryHandler {
Object.values(this.queryGraph.nodes).reduce((sum, node) => {
return typeof node.ids !== 'undefined' ? sum + node.ids.length : sum;
}, 0);
if (tooManyIDs) {
if (tooManyIDs && !this.pathfinder) {
const message = 'Inferred Mode queries with multiple IDs are not supported. Your query terminates.';
this.logs.push(new LogEntry('WARNING', null, message).getLog());
debug(message);
Expand Down Expand Up @@ -195,7 +198,7 @@ export default class InferredQueryHandler {
}, []);
return [...arr, ...objectCombos];
}, []);
const templates = await getTemplates(lookupObjects);
const templates = await getTemplates(lookupObjects, this.pathfinder);

const logMessage = `Got ${templates.length} inferred query templates.`;
debug(logMessage);
Expand Down
4 changes: 3 additions & 1 deletion src/inferred_mode/template_lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface TemplateGroup {
object: string[];
qualifiers?: CompactQualifiers;
templates: string[];
pathfinder: boolean;
}

export interface CompactEdge {
Expand All @@ -34,7 +35,7 @@ export interface CompactEdge {
qualifiers: CompactQualifiers;
}

export async function getTemplates(lookups: TemplateLookup[]): Promise<MatchedTemplate[]> {
export async function getTemplates(lookups: TemplateLookup[], pathfinder = false): Promise<MatchedTemplate[]> {
async function getFiles(dir: string): Promise<string[]> {
const rootFiles = await fs.readdir(path.resolve(dir));
return await async.reduce(rootFiles, [] as string[], async (arr, fname: string) => {
Expand All @@ -57,6 +58,7 @@ export async function getTemplates(lookups: TemplateLookup[]): Promise<MatchedTe
const matchingTemplatePaths: string[] = templateGroups.reduce((matches: string[], group: TemplateGroup) => {
const lookupMatch = lookups.some((lookup) => {
return (
group.pathfinder === pathfinder &&
group.subject.includes(lookup.subject) &&
group.object.includes(lookup.object) &&
group.predicate.includes(lookup.predicate) &&
Expand Down
8 changes: 5 additions & 3 deletions src/query_graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export default class QueryGraph {
queryGraph: TrapiQueryGraph;
schema: any;
logs: StampedLog[];
skipCycleDetection: boolean;
nodes: { [QNodeID: string]: QNode };
edges: { [QEdgeID: string]: QEdge };
constructor(queryGraph: TrapiQueryGraph, schema: any) {
constructor(queryGraph: TrapiQueryGraph, schema: any, skipCycleDetection = false) {
this.queryGraph = queryGraph;
this.schema = schema;
this.skipCycleDetection = skipCycleDetection;
this.logs = [];
}

Expand Down Expand Up @@ -93,7 +95,7 @@ export default class QueryGraph {
}

for (const firstNode in nodes) {
if (nodes[firstNode].visited === true) continue;
if (nodes[firstNode].visited == true) continue;
const stack: { curNode: string; parent: string | number }[] = [{ curNode: firstNode, parent: -1 }];
nodes[firstNode].visited = true;
while (stack.length !== 0) {
Expand Down Expand Up @@ -191,7 +193,7 @@ export default class QueryGraph {
this._validateNodeProperties(queryGraph);
this._validateEdgeProperties(queryGraph);
this._validateBatchSize(queryGraph);
this._validateCycles(queryGraph);
!this.skipCycleDetection && this._validateCycles(queryGraph);
this._validateNoDuplicateQualifierTypes(queryGraph);
}

Expand Down

0 comments on commit 52bc25d

Please sign in to comment.