1
1
use itertools:: Itertools ;
2
- use mimir:: rubber:: Rubber ;
3
2
use mimir:: Poi ;
4
3
use mimirsbrunn:: admin_geofinder:: AdminGeoFinder ;
5
4
use mimirsbrunn:: labels:: format_addr_name_and_label;
6
5
use mimirsbrunn:: labels:: format_street_label;
7
6
use mimirsbrunn:: utils:: find_country_codes;
8
- use reqwest:: StatusCode ;
9
7
use serde:: Deserialize ;
8
+ use serde_json:: json;
10
9
use std:: ops:: Deref ;
11
10
use std:: sync:: Arc ;
12
11
12
+ use crate :: lazy_es:: { parse_es_response, LazyEs } ;
13
+
13
14
// Prefixes used in ids for Address objects derived from OSM tags
14
15
const FAFNIR_ADDR_NAMESPACE : & str = "addr_poi:" ;
15
16
const FAFNIR_STREET_NAMESPACE : & str = "street_poi:" ;
17
+ const MAX_REVERSE_DISTANCE : & str = "500m" ;
16
18
17
19
/// Check if a mimir address originates from OSM data.
18
20
pub fn is_addr_derived_from_tags ( addr : & mimir:: Address ) -> bool {
@@ -37,36 +39,33 @@ pub enum CurPoiAddress {
37
39
/// Get current value of address associated with a POI in the ES database if
38
40
/// any, together with current coordinates of the POI that have been used to
39
41
/// perform a reverse
40
- pub fn get_current_addr ( rubber : & mut Rubber , poi_index : & str , osm_id : & str ) -> CurPoiAddress {
41
- let query = format ! (
42
- "{}/poi/{}/_source?_source_include=address,coord" ,
43
- poi_index, osm_id
44
- ) ;
45
-
42
+ pub fn get_current_addr < ' a > ( poi_index : & str , osm_id : & ' a str ) -> LazyEs < ' a , CurPoiAddress > {
46
43
#[ derive( Deserialize ) ]
47
- struct FetchPOI {
44
+ struct FetchPoi {
48
45
coord : mimir:: Coord ,
49
46
address : Option < mimir:: Address > ,
50
47
}
51
48
52
- rubber
53
- . get ( & query)
54
- . map_err ( |err| warn ! ( "query to elasticsearch failed: {:?}" , err) )
55
- . ok ( )
56
- . and_then ( |res| {
57
- if res. status ( ) != StatusCode :: NOT_FOUND {
58
- res. json ( )
59
- . map_err ( |err| {
60
- warn ! (
61
- "failed to parse ES response while reading old address for {}: {:?}" ,
62
- osm_id, err
63
- )
64
- } )
65
- . ok ( )
66
- . map ( |poi_json : FetchPOI | {
67
- let coord = poi_json. coord ;
49
+ LazyEs :: NeedEsQuery {
50
+ header : json ! ( { "index" : poi_index } ) ,
51
+ query : json ! ( {
52
+ "_source" : [ "address" , "coord" ] ,
53
+ "query" : { "terms" : { "_id" : [ osm_id] } }
54
+ } ) ,
55
+ progress : Box :: new ( move |es_response| {
56
+ LazyEs :: Value ( {
57
+ let hits = parse_es_response ( es_response)
58
+ . expect ( "got error from ES while reading old address" ) ;
59
+
60
+ assert ! ( hits. len( ) <= 1 ) ;
68
61
69
- if let Some ( address) = poi_json. address {
62
+ hits. into_iter ( )
63
+ . next ( )
64
+ . map ( |hit| {
65
+ let poi: FetchPoi = hit. source ;
66
+ let coord = poi. coord ;
67
+
68
+ if let Some ( address) = poi. address {
70
69
CurPoiAddress :: Some {
71
70
coord,
72
71
address : Box :: new ( address) ,
@@ -75,11 +74,49 @@ pub fn get_current_addr(rubber: &mut Rubber, poi_index: &str, osm_id: &str) -> C
75
74
CurPoiAddress :: None { coord }
76
75
}
77
76
} )
78
- } else {
79
- None
77
+ . unwrap_or ( CurPoiAddress :: NotFound )
78
+ } )
79
+ } ) ,
80
+ }
81
+ }
82
+
83
+ /// Get addresses close to input coordinates.
84
+ pub fn get_addr_from_coords < ' a > ( coord : & mimir:: Coord ) -> LazyEs < ' a , Vec < mimir:: Place > > {
85
+ let indexes = mimir:: rubber:: get_indexes ( false , & [ ] , & [ ] , & [ "house" , "street" ] ) ;
86
+
87
+ LazyEs :: NeedEsQuery {
88
+ header : json ! ( {
89
+ "index" : indexes,
90
+ "ignore_unavailable" : true
91
+ } ) ,
92
+ query : json ! ( {
93
+ "query" : {
94
+ "bool" : {
95
+ "should" : mimir:: rubber:: build_proximity_with_boost( coord, 1. ) ,
96
+ "must" : {
97
+ "geo_distance" : {
98
+ "distance" : MAX_REVERSE_DISTANCE ,
99
+ "coord" : {
100
+ "lat" : coord. lat( ) ,
101
+ "lon" : coord. lon( )
102
+ }
103
+ }
104
+ }
105
+ }
80
106
}
81
- } )
82
- . unwrap_or ( CurPoiAddress :: NotFound )
107
+ } ) ,
108
+ progress : Box :: new ( |es_response| {
109
+ LazyEs :: Value (
110
+ parse_es_response ( es_response)
111
+ . expect ( "got error from ES while performing reverse" )
112
+ . into_iter ( )
113
+ . filter_map ( |hit| {
114
+ mimir:: rubber:: make_place ( hit. doc_type , Some ( Box :: new ( hit. source ) ) , None )
115
+ } )
116
+ . collect ( ) ,
117
+ )
118
+ } ) ,
119
+ }
83
120
}
84
121
85
122
fn build_new_addr (
@@ -159,102 +196,101 @@ fn build_new_addr(
159
196
/// We also search for the admins that contains the coordinates of the poi
160
197
/// and add them as the address's admins.
161
198
///
162
- /// If try_skip_reverse is set to try , it will reuse the address already
199
+ /// If try_skip_reverse is set to true , it will reuse the address already
163
200
/// attached to a POI in the ES database.
164
- pub fn find_address (
165
- poi : & Poi ,
166
- geofinder : & AdminGeoFinder ,
167
- rubber : & mut Rubber ,
201
+ pub fn find_address < ' p > (
202
+ poi : & ' p Poi ,
203
+ geofinder : & ' p AdminGeoFinder ,
168
204
poi_index : & str ,
169
205
try_skip_reverse : bool ,
170
- ) -> Option < mimir:: Address > {
206
+ ) -> LazyEs < ' p , Option < mimir:: Address > > {
171
207
if poi
172
208
. properties
173
209
. iter ( )
174
210
. any ( |p| p. key == "poi_class" && p. value == "locality" )
175
211
{
176
212
// We don't want to add address on hamlets.
177
- return None ;
213
+ return LazyEs :: Value ( None ) ;
178
214
}
215
+
179
216
let osm_addr_tag = [ "addr:housenumber" , "contact:housenumber" ]
180
217
. iter ( )
181
- . filter_map ( |k| {
218
+ . find_map ( |k| {
182
219
poi. properties
183
220
. iter ( )
184
221
. find ( |p| & p. key == k)
185
222
. map ( |p| & p. value )
186
- } )
187
- . next ( ) ;
223
+ } ) ;
188
224
189
- let osm_street_tag = [ "addr:street" , "contact:street" ]
190
- . iter ( )
191
- . filter_map ( |k| {
192
- poi. properties
193
- . iter ( )
194
- . find ( |p| & p. key == k)
195
- . map ( |p| & p. value )
196
- } )
197
- . next ( ) ;
225
+ let osm_street_tag = [ "addr:street" , "contact:street" ] . iter ( ) . find_map ( |k| {
226
+ poi. properties
227
+ . iter ( )
228
+ . find ( |p| & p. key == k)
229
+ . map ( |p| & p. value )
230
+ } ) ;
198
231
199
232
match ( osm_addr_tag, osm_street_tag) {
200
- ( Some ( house_number_tag) , Some ( street_tag) ) => Some ( build_new_addr (
233
+ ( Some ( house_number_tag) , Some ( street_tag) ) => LazyEs :: Value ( Some ( build_new_addr (
201
234
house_number_tag,
202
235
street_tag,
203
236
poi,
204
237
geofinder. get ( & poi. coord ) ,
205
- ) ) ,
206
- ( None , Some ( street_tag) ) => {
207
- if let Ok ( addrs) = rubber. get_address ( & poi. coord ) {
208
- for addr in addrs. into_iter ( ) {
209
- if let Some ( address) = addr. address ( ) {
210
- match address {
211
- mimir:: Address :: Street ( _) => continue ,
212
- mimir:: Address :: Addr ( ref a) => {
213
- if a. street . name != * street_tag {
214
- continue ;
215
- }
216
- }
217
- }
218
- return Some ( address) ;
238
+ ) ) ) ,
239
+ ( None , Some ( street_tag) ) => get_addr_from_coords ( & poi. coord ) . map ( move |addrs| {
240
+ addrs
241
+ . into_iter ( )
242
+ . find_map ( |p| {
243
+ let as_address = p. address ( ) ;
244
+
245
+ match & as_address {
246
+ Some ( mimir:: Address :: Addr ( a) ) if a. street . name == * street_tag => as_address,
247
+ _ => None ,
219
248
}
220
- }
221
- }
222
- Some ( build_new_addr (
223
- "" ,
224
- street_tag,
225
- poi,
226
- geofinder. get ( & poi. coord ) ,
227
- ) )
228
- }
249
+ } )
250
+ . or_else ( || {
251
+ Some ( build_new_addr (
252
+ "" ,
253
+ street_tag,
254
+ poi,
255
+ geofinder. get ( & poi. coord ) ,
256
+ ) )
257
+ } )
258
+ } ) ,
229
259
_ => {
260
+ let lazy_es_address = get_addr_from_coords ( & poi. coord ) . map ( |places| {
261
+ Some (
262
+ places
263
+ . into_iter ( )
264
+ . next ( ) ?
265
+ . address ( )
266
+ . expect ( "`get_address_from_coords` returned a non-address object" ) ,
267
+ )
268
+ } ) ;
269
+
230
270
if try_skip_reverse {
231
- // Fetch the address already attached to the POI to avoid computing an unnecessary
232
- // reverse.
233
- let changed_coords = |old_coord : mimir:: Coord | {
234
- ( old_coord. lon ( ) - poi. coord . lon ( ) ) . abs ( ) > 1e-6
235
- || ( old_coord. lat ( ) - poi. coord . lat ( ) ) . abs ( ) > 1e-6
236
- } ;
271
+ // Fetch the address already attached to the POI to avoid computing an
272
+ // unnecessary reverse.
273
+ get_current_addr ( poi_index, & poi. id ) . then ( move |current_address| {
274
+ let changed_coords = |old_coord : mimir:: Coord | {
275
+ ( old_coord. lon ( ) - poi. coord . lon ( ) ) . abs ( ) > 1e-6
276
+ || ( old_coord. lat ( ) - poi. coord . lat ( ) ) . abs ( ) > 1e-6
277
+ } ;
237
278
238
- match get_current_addr ( rubber, poi_index, & poi. id ) {
239
- CurPoiAddress :: None { coord } if !changed_coords ( coord) => return None ,
240
- CurPoiAddress :: Some { coord, address }
241
- if !is_addr_derived_from_tags ( & address) && !changed_coords ( coord) =>
242
- {
243
- return Some ( * address) ;
279
+ match current_address {
280
+ CurPoiAddress :: None { coord } if !changed_coords ( coord) => {
281
+ LazyEs :: Value ( None )
282
+ }
283
+ CurPoiAddress :: Some { coord, address }
284
+ if !is_addr_derived_from_tags ( & address) && !changed_coords ( coord) =>
285
+ {
286
+ LazyEs :: Value ( Some ( * address) )
287
+ }
288
+ _ => lazy_es_address,
244
289
}
245
- _ => { }
246
- }
247
- }
248
-
249
- rubber
250
- . get_address ( & poi. coord )
251
- . map_err ( |e| warn ! ( "`get_address` returned ES error for {}: {}" , poi. id, e) )
252
- . ok ( )
253
- . and_then ( |addrs| addrs. into_iter ( ) . next ( ) )
254
- . map ( |addr| {
255
- addr. address ( )
256
- . expect ( "`get_address` returned a non-address object" )
257
290
} )
291
+ } else {
292
+ lazy_es_address
293
+ }
258
294
}
259
295
}
260
296
}
0 commit comments