Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 238x 238x 238x 238x 238x 54735x 54735x 54735x 54735x 54735x 11735x 54735x 54735x 54735x 54735x 54735x 54735x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 25489x 202016x 138349x 2x 2x 2x 2x 1x 2x 2x 2x 228434x 228434x 193369x 212403x 191679x 54735x 106550x 25489x 10x 10x | import * as rdfjs from '@rdfjs/types';
/**
* A multi-dimensional index over RDF triples for O(1) pattern lookups.
*
* Maintains three access paths:
* - by predicate → subject → set of objects
* - by predicate → object → set of subjects
* - by subject → set of predicates (for property chain and key joins)
*
* The index is used by the semi-naive fixpoint engine to perform joins
* efficiently without scanning the full working store.
*/
export class TripleIndex {
/** predicate → subject → objects */
readonly byPredSubj = new Map<string, Map<string, Set<rdfjs.Quad_Object>>>();
/** predicate → object → subjects */
readonly byPredObj = new Map<string, Map<string, Set<rdfjs.Quad_Subject>>>();
/** subject → predicate → objects */
readonly bySubjPred = new Map<string, Map<string, Set<rdfjs.Quad_Object>>>();
/** object (URI/bnode) → predicate → subjects */
readonly byObjPred = new Map<string, Map<string, Set<rdfjs.Quad_Subject>>>();
/** subject value → subject term (for term recovery in pairs()) */
private readonly bySubjTerm = new Map<string, rdfjs.Quad_Subject>();
add(quad: rdfjs.Quad): boolean {
const s = quad.subject.value;
const p = quad.predicate.value;
const o = quad.object;
const ov = o.value;
if (!this.bySubjTerm.has(s)) {
this.bySubjTerm.set(s, quad.subject);
}
// byPredSubj
let bySubj = this.byPredSubj.get(p);
if (!bySubj) { bySubj = new Map(); this.byPredSubj.set(p, bySubj); }
let objs = bySubj.get(s);
if (!objs) { objs = new Set(); bySubj.set(s, objs); }
const isNew = !this._hasObject(objs, o);
if (!isNew) return false;
objs.add(o);
// byPredObj
let byObj = this.byPredObj.get(p);
if (!byObj) { byObj = new Map(); this.byPredObj.set(p, byObj); }
let subjs = byObj.get(ov);
if (!subjs) { subjs = new Set(); byObj.set(ov, subjs); }
subjs.add(quad.subject);
// bySubjPred
let predMap = this.bySubjPred.get(s);
if (!predMap) { predMap = new Map(); this.bySubjPred.set(s, predMap); }
let objsS = predMap.get(p);
if (!objsS) { objsS = new Set(); predMap.set(p, objsS); }
objsS.add(o);
// byObjPred
let objPredMap = this.byObjPred.get(ov);
if (!objPredMap) { objPredMap = new Map(); this.byObjPred.set(ov, objPredMap); }
let subjsO = objPredMap.get(p);
if (!subjsO) { subjsO = new Set(); objPredMap.set(p, subjsO); }
subjsO.add(quad.subject);
return true;
}
/** Look up all objects for a given predicate + subject. */
getObjects(predicate: string, subject: string): ReadonlySet<rdfjs.Quad_Object> {
return this.byPredSubj.get(predicate)?.get(subject) ?? _empty;
}
/** Look up all subjects for a given predicate + object value. */
getSubjects(predicate: string, objectValue: string): ReadonlySet<rdfjs.Quad_Subject> {
return this.byPredObj.get(predicate)?.get(objectValue) ?? _emptySubj;
}
/** Look up all objects a subject has for a given predicate. */
getObjectsForSubject(subject: string, predicate: string): ReadonlySet<rdfjs.Quad_Object> {
return this.bySubjPred.get(subject)?.get(predicate) ?? _empty;
}
/** Look up all subjects that have a given object for a given predicate. */
getSubjectsForObject(objectValue: string, predicate: string): ReadonlySet<rdfjs.Quad_Subject> {
return this.byObjPred.get(objectValue)?.get(predicate) ?? _emptySubj;
}
/** Iterate all (subject, object) pairs for a given predicate. */
*pairs(predicate: string): Iterable<[rdfjs.Quad_Subject, rdfjs.Quad_Object]> {
const bySubj = this.byPredSubj.get(predicate);
if (!bySubj) return;
for (const [sv, objs] of bySubj) {
const subjectTerm = this.bySubjTerm.get(sv)!;
for (const obj of objs) {
yield [subjectTerm, obj];
}
}
}
/** Check if the index contains a triple with this predicate, subject, and object value. */
has(predicate: string, subject: string, objectValue: string): boolean {
const objs = this.byPredSubj.get(predicate)?.get(subject);
if (!objs) return false;
for (const o of objs) {
if (o.value === objectValue) return true;
}
return false;
}
private _hasObject(set: Set<rdfjs.Quad_Object>, obj: rdfjs.Quad_Object): boolean {
for (const o of set) {
if (o.value === obj.value && o.termType === obj.termType) return true;
}
return false;
}
}
const _empty: ReadonlySet<rdfjs.Quad_Object> = new Set();
const _emptySubj: ReadonlySet<rdfjs.Quad_Subject> = new Set();
|