github.com/dgraph-io/dgraph@v1.2.8/types/s2index_test.go (about) 1 /* 2 * Copyright 2016-2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "io" 24 "os" 25 "testing" 26 27 "github.com/golang/geo/s2" 28 "github.com/stretchr/testify/require" 29 "github.com/twpayne/go-geom" 30 "github.com/twpayne/go-geom/encoding/geojson" 31 "github.com/twpayne/go-geom/encoding/wkb" 32 ) 33 34 func loadPolygon(name string) (geom.T, error) { 35 f, err := os.Open(name) 36 if err != nil { 37 return nil, err 38 } 39 defer f.Close() 40 var b bytes.Buffer 41 _, err = io.Copy(&b, f) 42 if err != nil { 43 return nil, err 44 } 45 46 var gf geojson.Feature 47 if err := gf.UnmarshalJSON(b.Bytes()); err != nil { 48 return nil, err 49 } 50 return gf.Geometry, nil 51 } 52 53 func TestIndexCellsPoint(t *testing.T) { 54 p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518}) 55 parents, cover, err := indexCells(p) 56 require.NoError(t, err) 57 require.Len(t, parents, MaxCellLevel-MinCellLevel+1) 58 c := parents[0] 59 if c.Level() != MinCellLevel { 60 t.Errorf("Expected cell level %d. Got %d instead.", MinCellLevel, c.Level()) 61 } 62 if c.ToToken() != "808c" { 63 t.Errorf("Unexpected cell token %s.", c.ToToken()) 64 } 65 c = parents[len(parents)-1] 66 if c.Level() != MaxCellLevel { 67 t.Errorf("Expected cell level %d. Got %d instead.", MaxCellLevel, c.Level()) 68 } 69 if c.ToToken() != "808fb9f81" { 70 t.Errorf("Unexpected cell token %s.", c.ToToken()) 71 } 72 // check that all cell levels are different 73 pc := parents[0] 74 for _, c := range parents[1:] { 75 if c.Level() <= pc.Level() { 76 t.Errorf("Expected cell to have level greater than %d. Got %d", pc.Level(), c.Level()) 77 } 78 pc = c 79 } 80 81 // Check that cover only has one item 82 require.Len(t, cover, 1) 83 c = cover[0] 84 require.Equal(t, c.Level(), MaxCellLevel) 85 require.Equal(t, c.ToToken(), "808fb9f81") 86 } 87 88 func printCells(cu s2.CellUnion) { 89 for _, c := range cu { 90 cell := s2.CellFromCellID(c) 91 area := EarthArea(cell.ExactArea()) 92 r := cell.RectBound() 93 top := r.Vertex(0).Distance(r.Vertex(1)) 94 side := r.Vertex(1).Distance(r.Vertex(2)) 95 fmt.Printf("Level: %d, Cell: %s, area: %s, boundary: %s x %s\n", c.Level(), c.ToToken(), 96 area, EarthDistance(top), EarthDistance(side)) 97 } 98 } 99 100 func TestIndexCellsPolygon(t *testing.T) { 101 p, err := loadPolygon("testdata/zip.json") 102 require.NoError(t, err) 103 parents, cover, err := indexCells(p) 104 require.NoError(t, err) 105 if len(cover) > MaxCells { 106 t.Errorf("Expected less than %d cells. Got %d instead.", MaxCells, len(cover)) 107 } 108 for _, c := range cover { 109 if c.Level() > MaxCellLevel || c.Level() < MinCellLevel { 110 t.Errorf("Invalid cell level %d.", c.Level()) 111 } 112 require.Contains(t, parents, c) 113 } 114 require.True(t, len(parents) > len(cover)) 115 } 116 117 func TestIndexCellsPolygonError(t *testing.T) { 118 poly := geom.NewPolygon(geom.XY).MustSetCoords([][]geom.Coord{ 119 {{-122, 37}, {-123, 37}, {-123, 38}, {-122, 38}, {-122, 38}}}) 120 _, _, err := indexCells(poly) 121 require.Error(t, err) 122 require.Contains(t, err.Error(), "Last coordinate not same as first") 123 } 124 125 func TestKeyGeneratorPoint(t *testing.T) { 126 p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518}) 127 data, err := wkb.Marshal(p, binary.LittleEndian) 128 require.NoError(t, err) 129 130 src := ValueForType(BinaryID) 131 src.Value = data 132 gc, err := Convert(src, GeoID) 133 require.NoError(t, err) 134 g := gc.Value.(geom.T) 135 136 keys, err := IndexGeoTokens(g) 137 require.NoError(t, err) 138 require.Len(t, keys, MaxCellLevel-MinCellLevel+1+1) // +1 for the cover 139 } 140 141 func TestKeyGeneratorPolygon(t *testing.T) { 142 p, err := loadPolygon("testdata/zip.json") 143 require.NoError(t, err) 144 data, err := wkb.Marshal(p, binary.LittleEndian) 145 require.NoError(t, err) 146 147 src := ValueForType(BinaryID) 148 src.Value = data 149 gc, err := Convert(src, GeoID) 150 require.NoError(t, err) 151 g := gc.Value.(geom.T) 152 153 keys, err := IndexGeoTokens(g) 154 require.NoError(t, err) 155 require.Len(t, keys, 67) 156 } 157 158 func testCover(file string, max int) { 159 fmt.Printf("Testing %s with max %d\n", file, max) 160 p, err := loadPolygon(file) 161 if err != nil { 162 return 163 } 164 l, _ := loopFromPolygon(p.(*geom.Polygon)) 165 cu := coverLoop(l, MinCellLevel, MaxCellLevel, max) 166 printCells(cu) 167 printCoverAccuracy(l, cu) 168 } 169 170 func printCoverAccuracy(l *s2.Loop, cu s2.CellUnion) { 171 a1 := cellUnionArea(cu) 172 a2 := l.Area() 173 fmt.Printf("Loop area: %v. Cell area %v. Ratio %.3f\n", EarthArea(a2), EarthArea(a1), a1/a2) 174 } 175 176 func cellUnionArea(cu s2.CellUnion) float64 { 177 var area float64 178 for _, c := range cu { 179 cell := s2.CellFromCellID(c) 180 area += cell.ExactArea() 181 } 182 return area 183 } 184 185 func BenchmarkToLoopZip(b *testing.B) { 186 benchToLoop(b, "testdata/zip.json") 187 } 188 189 func BenchmarkToLoopAruba(b *testing.B) { 190 benchToLoop(b, "testdata/aruba.json") 191 } 192 193 func BenchmarkCoverZip_10(b *testing.B) { 194 benchCover(b, "testdata/zip.json", 10) 195 } 196 197 func BenchmarkCoverZip_15(b *testing.B) { 198 benchCover(b, "testdata/zip.json", 15) 199 } 200 201 func BenchmarkCoverZip_18(b *testing.B) { 202 benchCover(b, "testdata/zip.json", 18) 203 } 204 205 func BenchmarkCoverZip_30(b *testing.B) { 206 benchCover(b, "testdata/zip.json", 30) 207 } 208 209 func BenchmarkCoverAruba_10(b *testing.B) { 210 benchCover(b, "testdata/aruba.json", 10) 211 } 212 213 func BenchmarkCoverAruba_15(b *testing.B) { 214 benchCover(b, "testdata/aruba.json", 15) 215 } 216 217 func BenchmarkCoverAruba_18(b *testing.B) { 218 benchCover(b, "testdata/aruba.json", 18) 219 } 220 221 func BenchmarkCoverAruba_30(b *testing.B) { 222 benchCover(b, "testdata/aruba.json", 30) 223 } 224 225 func BenchmarkKeyGeneratorPoint(b *testing.B) { 226 p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518}) 227 data, err := wkb.Marshal(p, binary.LittleEndian) 228 if err != nil { 229 b.Error(err) 230 } 231 232 src := ValueForType(BinaryID) 233 src.Value = data 234 gc, err := Convert(src, GeoID) 235 require.NoError(b, err) 236 g := gc.Value.(geom.T) 237 238 b.ResetTimer() 239 for n := 0; n < b.N; n++ { 240 IndexGeoTokens(g) 241 } 242 } 243 244 func BenchmarkKeyGeneratorPolygon(b *testing.B) { 245 p, err := loadPolygon("testdata/zip.json") 246 if err != nil { 247 b.Error(err) 248 } 249 data, err := wkb.Marshal(p, binary.LittleEndian) 250 if err != nil { 251 b.Error(err) 252 } 253 254 src := ValueForType(GeoID) 255 src.Value = data 256 gc, err := Convert(src, GeoID) 257 require.NoError(b, err) 258 g := gc.Value.(geom.T) 259 260 b.ResetTimer() 261 for n := 0; n < b.N; n++ { 262 IndexGeoTokens(g) 263 } 264 } 265 266 func benchCover(b *testing.B, file string, max int) { 267 p, err := loadPolygon(file) 268 if err != nil { 269 b.Error(err) 270 } 271 l, _ := loopFromPolygon(p.(*geom.Polygon)) 272 var cu s2.CellUnion 273 b.ResetTimer() 274 for n := 0; n < b.N; n++ { 275 cu = coverLoop(l, MinCellLevel, MaxCellLevel, max) 276 } 277 printCoverAccuracy(l, cu) 278 } 279 280 func benchToLoop(b *testing.B, file string) { 281 p, err := loadPolygon(file) 282 if err != nil { 283 b.Error(err) 284 } 285 b.ResetTimer() 286 for n := 0; n < b.N; n++ { 287 _, _ = loopFromPolygon(p.(*geom.Polygon)) 288 } 289 }