1// Copyright (c) 2017 Couchbase, Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package document 16 17import ( 18 "fmt" 19 20 "github.com/blevesearch/bleve/analysis" 21 "github.com/blevesearch/bleve/geo" 22 "github.com/blevesearch/bleve/numeric" 23) 24 25var GeoPrecisionStep uint = 9 26 27type GeoPointField struct { 28 name string 29 arrayPositions []uint64 30 options IndexingOptions 31 value numeric.PrefixCoded 32 numPlainTextBytes uint64 33} 34 35func (n *GeoPointField) Name() string { 36 return n.name 37} 38 39func (n *GeoPointField) ArrayPositions() []uint64 { 40 return n.arrayPositions 41} 42 43func (n *GeoPointField) Options() IndexingOptions { 44 return n.options 45} 46 47func (n *GeoPointField) Analyze() (int, analysis.TokenFrequencies) { 48 tokens := make(analysis.TokenStream, 0) 49 tokens = append(tokens, &analysis.Token{ 50 Start: 0, 51 End: len(n.value), 52 Term: n.value, 53 Position: 1, 54 Type: analysis.Numeric, 55 }) 56 57 original, err := n.value.Int64() 58 if err == nil { 59 60 shift := GeoPrecisionStep 61 for shift < 64 { 62 shiftEncoded, err := numeric.NewPrefixCodedInt64(original, shift) 63 if err != nil { 64 break 65 } 66 token := analysis.Token{ 67 Start: 0, 68 End: len(shiftEncoded), 69 Term: shiftEncoded, 70 Position: 1, 71 Type: analysis.Numeric, 72 } 73 tokens = append(tokens, &token) 74 shift += GeoPrecisionStep 75 } 76 } 77 78 fieldLength := len(tokens) 79 tokenFreqs := analysis.TokenFrequency(tokens, n.arrayPositions, n.options.IncludeTermVectors()) 80 return fieldLength, tokenFreqs 81} 82 83func (n *GeoPointField) Value() []byte { 84 return n.value 85} 86 87func (n *GeoPointField) Lon() (float64, error) { 88 i64, err := n.value.Int64() 89 if err != nil { 90 return 0.0, err 91 } 92 return geo.MortonUnhashLon(uint64(i64)), nil 93} 94 95func (n *GeoPointField) Lat() (float64, error) { 96 i64, err := n.value.Int64() 97 if err != nil { 98 return 0.0, err 99 } 100 return geo.MortonUnhashLat(uint64(i64)), nil 101} 102 103func (n *GeoPointField) GoString() string { 104 return fmt.Sprintf("&document.GeoPointField{Name:%s, Options: %s, Value: %s}", n.name, n.options, n.value) 105} 106 107func (n *GeoPointField) NumPlainTextBytes() uint64 { 108 return n.numPlainTextBytes 109} 110 111func NewGeoPointFieldFromBytes(name string, arrayPositions []uint64, value []byte) *GeoPointField { 112 return &GeoPointField{ 113 name: name, 114 arrayPositions: arrayPositions, 115 value: value, 116 options: DefaultNumericIndexingOptions, 117 numPlainTextBytes: uint64(len(value)), 118 } 119} 120 121func NewGeoPointField(name string, arrayPositions []uint64, lon, lat float64) *GeoPointField { 122 return NewGeoPointFieldWithIndexingOptions(name, arrayPositions, lon, lat, DefaultNumericIndexingOptions) 123} 124 125func NewGeoPointFieldWithIndexingOptions(name string, arrayPositions []uint64, lon, lat float64, options IndexingOptions) *GeoPointField { 126 mhash := geo.MortonHash(lon, lat) 127 prefixCoded := numeric.MustNewPrefixCodedInt64(int64(mhash), 0) 128 return &GeoPointField{ 129 name: name, 130 arrayPositions: arrayPositions, 131 value: prefixCoded, 132 options: options, 133 // not correct, just a place holder until we revisit how fields are 134 // represented and can fix this better 135 numPlainTextBytes: uint64(8), 136 } 137} 138