Skip to content

Commit

Permalink
perf: selectively perform matches (#458)
Browse files Browse the repository at this point in the history
* perf: selectively perform matches

* chore: rename graph -> graphKey

* chore: re-introduce deeply-nested test
  • Loading branch information
jeswr authored Sep 27, 2024
1 parent 35d7142 commit ce6794f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 12 deletions.
31 changes: 22 additions & 9 deletions src/N3Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,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 @@ -1133,15 +1132,29 @@ class DatasetCoreAndReadableStream extends Readable {
object && !(objectId = newStore._termToNumericId(object)))
return newStore;

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]),
};
const graphs = n3Store._getGraphs(graph);
for (const graphKey in graphs) {
let subjects, predicates, objects;

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

if (subjects)
newStore._graphs[graphKey] = { subjects, predicates, objects };
}
newStore._size = null;
}
Expand Down
82 changes: 79 additions & 3 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,6 +1991,11 @@ 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);
},
);

Expand All @@ -2016,10 +2021,81 @@ describe('Store', () => {
new NamedNode('o3'),
),
),
),
);
));
expect([...m]).toHaveLength(4);
expect([...store.match(null, null, null, null)]).toHaveLength(4);
});

it(
'perform matches on an range of defined and undefined elements',
() => {
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 ce6794f

Please sign in to comment.