Skip to content

Commit d756523

Browse files
committed
implement search with own custom planner
1 parent bcdd8fe commit d756523

10 files changed

Lines changed: 559 additions & 704 deletions

index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const pump = require('pump')
44
const utils = require('./lib/utils')
55
const Variable = require('./lib/Variable')
66
const HyperdbDiffTransform = require('./lib/HyperdbDiffTransform')
7-
const planner = require('./lib/queryPlanner')
7+
const JoinStream = require('./lib/JoinStream')
8+
const planner = require('./lib/planner')
89

910
function Graph (db, opts) {
1011
if (!(this instanceof Graph)) return new Graph(db, opts)
@@ -54,8 +55,7 @@ Graph.prototype.searchStream = function (query, options) {
5455
const plannedQuery = planner(query)
5556

5657
var streams = plannedQuery.map((triple) => {
57-
const stream = triple.stream
58-
return stream({ triple: utils.filterTriple(triple), db: this, index: triple.index })
58+
return new JoinStream({ triple, db: this })
5959
})
6060

6161
streams[0].start = true

lib/SortJoinStream.js

Lines changed: 0 additions & 132 deletions
This file was deleted.

lib/planner.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
const utils = require('./utils')
3+
4+
function planner (query) {
5+
if (query.length === 1) return query
6+
// first group queries based on number of variables.
7+
const solved = new Set()
8+
var grouped = query.reduce((ordered, q) => {
9+
const variables = utils.variableNames(q)
10+
if (ordered[variables.length]) {
11+
ordered[variables.length].push({
12+
query: q,
13+
names: variables
14+
})
15+
} else {
16+
ordered[variables.length] = [{
17+
query: q,
18+
names: variables
19+
}]
20+
}
21+
if (variables.length === 1) {
22+
solved.add(variables[0])
23+
}
24+
return ordered
25+
}, [])
26+
// then order vars > 1 by if they occur in
27+
const orderedQueries = grouped[1] ? grouped[1].map(v => v.query) : []
28+
29+
for (let i = 2; i < grouped.length; i++) {
30+
if (grouped[i] === undefined) continue
31+
while (grouped[i].length > 0) {
32+
// get the next easiest to solve
33+
// or the one that makes the rest easiest to solve
34+
grouped[i].sort((a, b) => {
35+
// number of unsolved variables
36+
let unsolvedA = a.names.filter(name => !solved.has(name))
37+
let unsolvedB = b.names.filter(name => !solved.has(name))
38+
if (unsolvedA.length < unsolvedB.length) return -1
39+
if (unsolvedA.length > unsolvedB.length) return 1
40+
// calculate how many unsolved vars it has in common with others in the group
41+
// should this be a vector? many vars is better than solving 1 lots.
42+
let sharedUnsolvedA = 0
43+
let sharedUnsolvedB = 0
44+
grouped[i].forEach(v => {
45+
v.names.forEach((name) => {
46+
if (solved.has(name)) return
47+
if (v !== a && a.names.includes(name)) sharedUnsolvedA++
48+
if (v !== b && b.names.includes(name)) sharedUnsolvedB++
49+
})
50+
})
51+
if (sharedUnsolvedA > sharedUnsolvedB) return -1
52+
if (sharedUnsolvedA < sharedUnsolvedB) return 1
53+
return 0
54+
})
55+
const next = grouped[i].shift()
56+
orderedQueries.push(next.query)
57+
next.names.forEach(n => solved.add(n))
58+
}
59+
}
60+
return orderedQueries
61+
};
62+
63+
module.exports = planner

lib/queryPlanner.js

Lines changed: 0 additions & 103 deletions
This file was deleted.

lib/utils.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ function objectMask (criteria, obj) {
139139
}, {})
140140
};
141141

142+
function variableNames (obj) {
143+
return Object.keys(obj)
144+
.filter(key => hasKey(key) && keyIsAVariable(obj[key]))
145+
.map(key => obj[key].name)
146+
};
147+
142148
function queryMask (object) {
143149
return objectMask(keyIsNotAObject, object)
144150
};
@@ -150,15 +156,14 @@ function maskUpdater (pattern) {
150156
const variables = variablesMask(pattern)
151157
return (solution, mask) => {
152158
const maskCopy = Object.assign({}, mask)
153-
return Object.keys(variables).reduce((newMask, key) => {
154-
const variable = variables[key]
155-
if (variable.isBound(solution)) {
156-
newMask[key] = solution[variable.name]
157-
}
158-
// fix this
159-
newMask.filter = pattern.filter
160-
return newMask
161-
}, maskCopy)
159+
return Object.keys(variables)
160+
.reduce((newMask, key) => {
161+
const variable = variables[key]
162+
if (variable.isBound(solution)) {
163+
newMask[key] = solution[variable.name]
164+
}
165+
return newMask
166+
}, maskCopy)
162167
}
163168
}
164169

@@ -196,6 +201,7 @@ module.exports = {
196201
createQuery,
197202
queryMask,
198203
variablesMask,
204+
variableNames,
199205
maskUpdater,
200206
matcher,
201207
materializer

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"standard": "^10.0.3"
1616
},
1717
"scripts": {
18-
"test": "mocha test",
19-
"ttd": "mocha test -w"
18+
"test": "mocha test/**.spec.js",
19+
"ttd": "mocha test/**.spec.js -w"
2020
},
2121
"author": "Benjamin Forster",
2222
"license": "MIT"

0 commit comments

Comments
 (0)