Skip to content

Commit

Permalink
perf: selectively perform matches
Browse files Browse the repository at this point in the history
  • Loading branch information
jeswr committed Sep 27, 2024
1 parent 373e90e commit be8a7ad
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 33 deletions.
29 changes: 21 additions & 8 deletions src/N3Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,6 @@ class DatasetCoreAndReadableStream extends Readable {
if (!this._filtered) {
const { n3Store, graph, object, predicate, subject } = this;
const newStore = this._filtered = new N3Store({ factory: n3Store._factory, entityIndex: this.options.entityIndex });
const graphs = n3Store._getGraphs(graph);

let subjectId, predicateId, objectId;

Expand All @@ -1118,15 +1117,29 @@ class DatasetCoreAndReadableStream extends Readable {
object && !(objectId = newStore._termToNumericId(object)))
return newStore;

const graphs = n3Store._getGraphs(graph);
for (const graph in graphs) {
const subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId]);
if (subjects) {
newStore._graphs[graph] = {
subjects,
predicates: indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId]),
objects: indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId]),
};
let subjects, predicates, objects;

if (!subjectId && predicateId) {
if (predicates = indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId])) {
subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId]);
objects = indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId]);
}
}
else if (objectId) {
if (objects = indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId])) {
subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId]);
predicates = indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId]);
}
}
else if (subjects = indexMatch(graphs[graph].subjects, [subjectId, predicateId, objectId])) {
predicates = indexMatch(graphs[graph].predicates, [predicateId, objectId, subjectId]);
objects = indexMatch(graphs[graph].objects, [objectId, subjectId, predicateId]);
}

if (subjects)
newStore._graphs[graph] = { subjects, predicates, objects };
}
newStore._size = null;
}
Expand Down
99 changes: 74 additions & 25 deletions test/N3Store-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import namespaces from '../src/IRIs';
import { Readable } from 'readable-stream';
import { arrayifyStream } from 'arrayify-stream';

const { namedNode } = DataFactory;
const { namedNode, quad } = DataFactory;

describe('Store', () => {
describe('The Store export', () => {
Expand Down Expand Up @@ -1991,35 +1991,84 @@ describe('Store', () => {
store.add(new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o2')));
expect([...m]).toHaveLength(3);
expect([...store.match(null, null, null, null)]).toHaveLength(3);
expect(store.match(null, null, null, null).equals(new Store([
quad(namedNode('s1'), namedNode('p1'), namedNode('o1')),
quad(namedNode('s1'), namedNode('p1'), namedNode('o3')),
quad(namedNode('s1'), namedNode('p1'), namedNode('o2')),
]))).toBe(true);
},
);

it(
'should include added elements in match if iteration has not yet started (deeply nested)',
'perform matches on an range of defined and undefined elements',
() => {
const m = store.match(null, null, null, null);
store.add(new Quad(
new NamedNode('s1'),
new NamedNode('p1'),
new Quad(new NamedNode('s1'), new NamedNode('p1'), new NamedNode('o3')),
),
);
store.add(new Quad(
new NamedNode('s1'),
new NamedNode('p1'),
new Quad(
new NamedNode('s1'),
new NamedNode('p1'),
new Quad(
new NamedNode('s1'),
new NamedNode('p1'),
new NamedNode('o3'),
),
),
),
);
expect([...m]).toHaveLength(4);
expect([...store.match(null, null, null, null)]).toHaveLength(4);
const m = new Store();
const s1 = new Store();
const p1 = new Store();
const o1 = new Store();

for (const s of ['s1', 's2', 's3']) {
for (const p of ['p1', 'p2', 'p3']) {
for (const o of ['o1', 'o2', 'o3']) {
for (const g of [namedNode('g1'), namedNode('g2'), namedNode('g3'), new DefaultGraph()]) {
if (s === 's1')
s1.add(new Quad(new NamedNode(s), new NamedNode(p), new NamedNode(o), g));

if (p === 'p1')
p1.add(new Quad(new NamedNode(s), new NamedNode(p), new NamedNode(o), g));

if (o === 'o1')
o1.add(new Quad(new NamedNode(s), new NamedNode(p), new NamedNode(o), g));

m.add(new Quad(new NamedNode(s), new NamedNode(p), new NamedNode(o), g));
}
}
}
}

expect(m.size).toBe(108);
expect(s1.size).toBe(36);
expect(p1.size).toBe(36);
expect(o1.size).toBe(36);

expect(m.match(namedNode('s1'), null, null).size).toBe(36);
expect(m.match(null, namedNode('p1'), null).size).toBe(36);
expect(m.match(null, null, namedNode('o1')).size).toBe(36);

expect(m.match(namedNode('s1'), null, null).equals(s1)).toBe(true);
expect(m.match(null, namedNode('p1'), null).equals(p1)).toBe(true);
expect(m.match(null, null, namedNode('o1')).equals(o1)).toBe(true);

expect(m.match(namedNode('s1'), namedNode('p1'), null).equals(s1.intersection(p1))).toBe(true);
expect(m.match(null, namedNode('p1'), namedNode('o1')).equals(p1.intersection(o1))).toBe(true);
expect(m.match(namedNode('s1'), null, namedNode('o1')).equals(o1.intersection(s1))).toBe(true);

expect(m.match(namedNode('sa1'), null, null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('pa1'), null).equals(new Store())).toBe(true);
expect(m.match(null, null, namedNode('oa1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('p1'), null, null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('o1'), null).equals(new Store())).toBe(true);
expect(m.match(null, null, namedNode('s1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('sa1'), namedNode('pa1'), null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('pa1'), namedNode('oa1')).equals(new Store())).toBe(true);
expect(m.match(namedNode('sa1'), null, namedNode('oa1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('p1'), namedNode('o1'), null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('o1'), namedNode('s1')).equals(new Store())).toBe(true);
expect(m.match(namedNode('o1'), null, namedNode('s1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('sa1'), namedNode('pa1'), namedNode('oa1')).equals(new Store())).toBe(true);
expect(m.match(namedNode('o1'), namedNode('s1'), namedNode('p1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('s1'), namedNode('pa1'), null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('p1'), namedNode('oa1')).equals(new Store())).toBe(true);
expect(m.match(namedNode('s1'), null, namedNode('oa1')).equals(new Store())).toBe(true);

expect(m.match(namedNode('sa1'), namedNode('p1'), null).equals(new Store())).toBe(true);
expect(m.match(null, namedNode('pa1'), namedNode('o1')).equals(new Store())).toBe(true);
expect(m.match(namedNode('sa1'), null, namedNode('o1')).equals(new Store())).toBe(true);
},
);

Expand Down

0 comments on commit be8a7ad

Please sign in to comment.