forked from capturetechnologies/stored
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index_geo.go
84 lines (81 loc) · 2 KB
/
index_geo.go
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
package stored
import (
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/mmcloughlin/geohash"
)
// IndexGeo does all the Index does but also geo
type IndexGeo struct {
index *Index
}
// GetGeo will return elements by geo index
func (ig *IndexGeo) GetGeo(lat float64, long float64) *PromiseSlice {
i := ig.index
// Precisions
// # km
// 1 ± 2500
// 2 ± 630
// 3 ± 78
// 4 ± 20
// 5 ± 2.4
// 6 ± 0.61
// 7 ± 0.076
// 8 ± 0.019
// 9 ± 0.0024
// 10 ± 0.00060
// 11 ± 0.000074
hash := geohash.Encode(lat, long)
if i.Geo > 0 && i.Geo < len(hash) {
hash = hash[0:i.Geo] // cut hash len to match percision of index
}
neighbors := geohash.Neighbors(hash)
search := append(neighbors, hash)
p := i.object.promiseSlice()
p.doRead(func() Chain {
rangeResults := map[string]fdb.RangeResult{}
for _, geohash := range search {
sub := i.dir.Sub(geohash)
start, end := sub.FDBRangeKeys()
r := fdb.KeyRange{Begin: start, End: end}
rangeResults[geohash] = p.readTr.GetRange(r, fdb.RangeOptions{
Limit: p.limit,
Reverse: !p.reverse, // select opposite reverse
})
}
need := []*needObject{}
slice := Slice{}
return func() Chain {
for geohash, res := range rangeResults {
sub := i.dir.Sub(geohash)
rows, err := res.GetSliceWithError()
if err != nil {
return p.fail(err)
}
if len(rows) == 0 {
continue
}
//fmt.Println("[A] hash got:", sub.Bytes(), "len:", len(rows))
for _, row := range rows {
primaryTuple, err := sub.Unpack(row.Key)
if err != nil {
return p.fail(err)
}
//fmt.Println("[A] primary:", primaryTuple)
// need object here
need = append(need, i.object.need(p.readTr, i.object.sub(primaryTuple)))
}
}
return func() Chain {
for _, n := range need {
val, err := n.fetch()
if err != nil {
continue
//return p.fail(err)
}
slice.Append(val)
}
return p.done(&slice) // return frinish slice here
}
}
})
return p
}