-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathselect.js
62 lines (54 loc) · 1.7 KB
/
select.js
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
var { isExact, isRange } = require('map-filter-reduce/util')
var { has, get } = require('./util')
function max (ary, score) {
var j = -1, M = 0
for(var i = 0; i < ary.length; i++) {
var m = score(ary[i])
if(m > M) {
M = m; j = i
}
}
return ary[j]
}
module.exports = function Select (indexes, query, returnScores) {
/*
calculate scores for each index based on how well they match the query.
an index field that is _exact_ gets 2 points,
and an index field that is a range gets 1 point.
points are added together, and squared at each step,
because it's better to have range fields after exact fields.
This is really crude and could be way smarter.
for example, this doesn't go into how many records the index would return for a given query.
(you could look that up with `approximateRange` though)
*/
function getScore (k) {
var v = get(k, query)
return has(k, query) ? (
isExact(v) ? 2
: isRange(v) ? 1
: 0
) : 0
}
function exact (k) {
return has(k, query) && isExact(get(k, query))
}
function range (k) {
return has(k, query) && isRange(get(k, query))
}
var scores = {}
var index = max(indexes, function (index) {
var score = 0, new_score = 0
for(var i = 0; i < index.value.length; i++) {
new_score = getScore(index.value[i])
if(!new_score) return score //stop counting when one thing doesn't match
score = score*score + new_score
scores[index.key] = score
}
return score
})
// obviously an ugly hack, just doing this for now so that I do not have to update all the tests
if (returnScores)
return {index: index, scores: scores}
else
return index
}