/[projects]/dao/DaoAdresseService/src/dk/daoas/daoadresseservice/AdressSearch.java
ViewVC logotype

Contents of /dao/DaoAdresseService/src/dk/daoas/daoadresseservice/AdressSearch.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2388 - (show annotations) (download)
Thu Feb 26 15:02:19 2015 UTC (9 years, 2 months ago) by torben
File size: 15889 byte(s)
Integrer Levenstein
1 package dk.daoas.daoadresseservice;
2
3 import java.sql.SQLException;
4 import java.text.SimpleDateFormat;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Date;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.concurrent.ConcurrentHashMap;
14
15 import org.apache.commons.lang3.StringUtils;
16
17 import dk.daoas.daoadresseservice.admin.ServiceConfig;
18 import dk.daoas.daoadresseservice.beans.Address;
19 import dk.daoas.daoadresseservice.beans.DataStatisticsBean;
20 import dk.daoas.daoadresseservice.beans.ExtendedBean;
21 import dk.daoas.daoadresseservice.beans.HundredePctBean;
22 import dk.daoas.daoadresseservice.beans.SearchResult;
23 import dk.daoas.daoadresseservice.beans.SearchResult.Status;
24 import dk.daoas.daoadresseservice.db.DatabaseLayer;
25
26 public class AdressSearch {
27
28 private Map<Integer, Map<String,Long>> searchPostnrVejnavnGadeid;
29 private Map<Long, Map<String,Address>> searchGadeidentAdresser;
30
31 private List<Address> alleAdresser;
32
33 private Map<String,Long> helperCache;
34
35 private DataStatisticsBean stats = new DataStatisticsBean();
36
37 ServiceConfig config;
38
39 public AdressSearch(ServiceConfig config) {
40 this.config = config;
41 }
42
43
44 public SearchResult search(String postnrStr, String adresse) {
45
46 SearchResult result = new SearchResult();
47
48 int postnr=0;
49
50 String helperSearchKey = "";
51
52 try {
53 postnr = Integer.parseInt(postnrStr);
54 } catch (Exception E) {
55 result.status = Status.ERROR_UNKNOWN_POSTAL;
56 return result;
57 }
58
59 Map<String,Long> postnrVeje = searchPostnrVejnavnGadeid.get(postnr);
60
61 if (postnrVeje == null) {
62 result.status = Status.ERROR_UNKNOWN_POSTAL;
63 return result;
64 }
65
66
67 result.splitResult = AddressUtils.splitAdresse(adresse);
68
69
70 if (result.splitResult.husnr.length() == 0) {
71 result.status = Status.ERROR_MISSING_HOUSENUMBER;
72 return result;
73 }
74
75 String vasketVejnavn = AddressUtils.vaskVejnavn( result.splitResult.vej );
76
77 Long gadeident = postnrVeje.get(vasketVejnavn);
78
79
80 if ( gadeident == null) {
81 helperSearchKey = "" + postnr + "/" + vasketVejnavn;
82 gadeident = helperCache.get(helperSearchKey);
83 }
84
85 if (gadeident == null) {
86 String best = getbestLevenshteinDistance(vasketVejnavn, postnrVeje);
87 if (best != null) {
88 gadeident = postnrVeje.get(best);
89 }
90 }
91
92
93 // Brug OpenStreetMap før vi prøver google
94 // For google har en request limit, det har OSM ikke!
95 if ( gadeident == null) {
96 if (config.useOpenStreetMaps) {
97 result.osmVej = GeocodeHelper.openstreetmapHelper(config, postnr, result.splitResult.vej );
98 result.osm = true;
99
100 if (result.osmVej != null) {
101 String osmVasket = AddressUtils.vaskVejnavn( result.osmVej );
102 gadeident = postnrVeje.get(osmVasket);
103
104 if (gadeident != null) {
105 helperCache.put(helperSearchKey, gadeident);
106 }
107 }
108 }
109 }
110
111 if ( gadeident == null) {
112 if (config.useGoogle) {
113 result.googleVej = GeocodeHelper.googleHelper(config, postnr, result.splitResult.vej );
114 result.google = true;
115
116 if (result.googleVej != null) {
117 String googleVasket = AddressUtils.vaskVejnavn( result.googleVej );
118 gadeident = postnrVeje.get(googleVasket);
119
120 if (gadeident != null) {
121 helperCache.put(helperSearchKey, gadeident);
122 }
123 }
124 }
125 }
126
127
128
129 if (gadeident == null) {
130 result.status = Status.ERROR_UNKNOWN_STREETNAME;
131 return result;
132 }
133
134 Map<String, Address> gade = searchGadeidentAdresser.get(gadeident);
135 if (gade == null) { //Denne søgning må ikke fejle
136 result.status = Status.ERROR_INTERNAL;
137 return result;
138 }
139
140
141 String husnrSearch = "" + result.splitResult.husnr + result.splitResult.litra;
142 Address addr = gade.get(husnrSearch);
143
144 if (addr == null) {
145 result.status = Status.ERROR_UNKNOWN_ADDRESSPOINT;
146 return result;
147 }
148
149 result.address = addr;
150
151
152 if ( StringUtils.equals(addr.distributor, "LUKKET") ) {
153 result.status = Status.STATUS_NOT_COVERED; //Skal vi have en special status til Lukkede adresser ?
154 return result;
155 }
156
157 if (addr.daekningsType == DaekningsType.DAEKNING_IKKEDAEKKET) {
158 result.status = Status.STATUS_NOT_COVERED;
159 return result;
160 }
161
162
163 result.status = Status.STATUS_OK;
164
165 return result;
166 }
167
168
169 public void buildSearchStructures() throws SQLException{
170 searchPostnrVejnavnGadeid = new HashMap<Integer, Map<String,Long>>();
171 searchGadeidentAdresser = new HashMap<Long, Map<String,Address>>();
172 helperCache = new ConcurrentHashMap<String,Long>();
173
174 long start1 = System.currentTimeMillis();
175 System.out.println("Build -- stage 1");
176
177 alleAdresser = DatabaseLayer.getAllAdresses();
178
179
180 /* Mapper mellem db Row ID og adresse noden */
181 Map<Integer,Address> idAddressMap = new HashMap<Integer,Address>( alleAdresser.size() );
182
183 for (Address a : alleAdresser) {
184 idAddressMap.put(a.id, a);
185
186 Map<String,Long> postnrVeje = searchPostnrVejnavnGadeid.get(a.postnr);
187
188 if (postnrVeje == null) {
189 postnrVeje = new ConcurrentHashMap<String,Long>();
190 searchPostnrVejnavnGadeid.put(a.postnr, postnrVeje);
191 }
192
193 String vasketVejnavn = AddressUtils.vaskVejnavn(a.vejnavn);
194 Long gadeident = postnrVeje.get(vasketVejnavn);
195 if (gadeident == null) {
196 //postnrVeje.put(vasketVejnavn, a.gadeid);
197
198 Set<String> aliaser = findVejAliaser(a.vejnavn);
199 for(String alias : aliaser) {
200 String vasketAlias = AddressUtils.vaskVejnavn(alias);
201 postnrVeje.put(vasketAlias, a.gadeid);
202 }
203
204 }
205
206 Map<String, Address> gade = searchGadeidentAdresser.get(a.gadeid);
207 if (gade == null) {
208 gade = new HashMap<String, Address>();
209 searchGadeidentAdresser.put(a.gadeid, gade);
210 }
211 String husnrSearch = "" + a.husnr + a.husnrbogstav;
212 gade.put(husnrSearch, a);
213 }
214
215
216 ////////////////////////////////////////////////////////////////////////////////////////
217 long start2 = System.currentTimeMillis();
218 System.out.println("Build, stage1 elapsed: " + (start2-start1) );
219 System.out.println("Build -- stage 2 udvidet dækning");
220
221 List<ExtendedBean> extDao = DatabaseLayer.getExtendedAdresslist();
222 for (ExtendedBean eb : extDao) {
223
224 Address orgAddress = idAddressMap.get(eb.orgId);
225 if (orgAddress == null)
226 continue;
227
228 Address targetAddress = idAddressMap.get(eb.targetId);
229 if (targetAddress == null)
230 continue;
231
232 if (orgAddress.distributor != null && orgAddress.distributor.equals("LUKKET")) {
233 continue;
234 }
235
236 if (targetAddress.distributor.equals("LUKKET")) {
237 continue;
238 }
239
240 orgAddress.extTarget = targetAddress;
241 orgAddress.extAfstand = eb.afstand;
242
243 boolean covered = false;
244 if (targetAddress.distributor.equals("DAO")) {
245 orgAddress.rute = calculateExtendedDaoRoute(eb,orgAddress,targetAddress);
246 if (orgAddress.rute != null) {
247 orgAddress.koreliste = targetAddress.koreliste;
248 covered = true;
249 }
250 }
251
252 if (targetAddress.distributor.equals("BK")) {
253 orgAddress.koreliste = calculateExtendedBkKoreliste(eb,orgAddress,targetAddress);
254 if (orgAddress.koreliste != null) {
255 orgAddress.rute = targetAddress.rute;
256 covered = true;
257 }
258 }
259
260 if (covered) { //Kopier resten af felterne
261 orgAddress.daekningsType = DaekningsType.DAEKNING_UDVIDET;
262 orgAddress.dbkBane = targetAddress.dbkBane;
263
264 /* Sådan gør den gamle service */
265 orgAddress.kommunekode = targetAddress.kommunekode;
266 orgAddress.vejkode = targetAddress.vejkode;
267
268 orgAddress.distributor = targetAddress.distributor;
269 }
270 }
271
272 // nu skal vi ikke bruge idAddressMap længere
273 idAddressMap = null;
274
275 //////////////////////////////////////////////////////////////////////////////////////
276 long start3 = System.currentTimeMillis();
277 System.out.println("Build, stage2 elapsed: " + (start3-start2) );
278 System.out.println("Build -- stage 3 - 100pct");
279
280 Map<Integer,HundredePctBean> hundredePct = DatabaseLayer.get100PctList();
281 for (Address addr : alleAdresser) {
282 if (addr.daekningsType != DaekningsType.DAEKNING_IKKEDAEKKET) {
283 continue;
284 }
285
286 if (addr.distributor != null && addr.distributor.equals("LUKKET")) {
287 continue;
288 }
289
290
291 HundredePctBean bean = hundredePct.get(addr.postnr);
292 if (bean == null) {
293 continue;
294 }
295
296 addr.daekningsType = DaekningsType.DAEKNING_100PCT;
297 addr.rute = bean.rute;
298 addr.koreliste = bean.koreliste;
299 addr.dbkBane = bean.dbkBane;
300 addr.distributor = bean.distributor;
301 }
302
303 ////////////////////////////////////////////////////////////////////////////////////
304 long stop = System.currentTimeMillis();
305 System.out.println("Build, stage3 elapsed: " + (stop-start3) );
306 System.out.println("Build -- Gathering statistics");
307
308 for (Address addr : alleAdresser) {
309 switch (addr.daekningsType) {
310 case DAEKNING_DIREKTE:
311 stats.direkteCount++;
312 break;
313 case DAEKNING_UDVIDET:
314 stats.extendedCount++;
315 break;
316 case DAEKNING_100PCT:
317 stats.hundredePctCount++;
318 break;
319 default:
320 stats.ikkeDaekketCount++;
321 }
322 }
323
324
325 stats.elapsed = stop-start1;
326 stats.buildTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( new Date() );
327
328 System.out.println("Build: direkteCount: " + stats.direkteCount);
329 System.out.println("Build: extendedCount: " + stats.extendedCount);
330 System.out.println("Build: hundredePctCount: " + stats.hundredePctCount);
331 System.out.println("Build: ikkeDaekketCount: " + stats.ikkeDaekketCount);
332
333 System.out.println("Build: Total Elapsed: " + (stop-start1) );
334 System.out.println("Build Completed");
335
336 }
337
338 public DataStatisticsBean getStatistics() {
339 return stats;
340 }
341
342 public void clear() {
343 searchPostnrVejnavnGadeid.clear();
344 searchGadeidentAdresser.clear();
345 alleAdresser.clear();
346 helperCache.clear();
347 }
348
349
350 private String getbestLevenshteinDistance(String vasketVejnavn, Map<String,Long> postnrVeje) {
351 for(String vej : postnrVeje.keySet()) {
352 if ( StringUtils.getLevenshteinDistance(vasketVejnavn, vej) == 1) {
353 System.out.println("Levenstein: " + vasketVejnavn + "->" + vej);
354 return vej;
355 }
356 }
357
358 return null;
359 }
360
361 private String calculateExtendedDaoRoute(ExtendedBean eb, Address orgAddress, Address targetAddress) {
362
363 // ///////////////////////////////////////////////////////////////////
364 switch( eb.transport) {
365 case "cykel":
366 if (eb.afstand < 0.151) {
367 return "." + targetAddress.rute;
368 } else if (eb.afstand < 0.501) {
369 return ".." + targetAddress.rute;
370 } else if (eb.afstand < 0.701) {
371 return "..." + targetAddress.rute;
372 } else if (eb.afstand < 0.501) {
373 return "...." + targetAddress.rute;
374 }
375 break;
376 case "scooter":
377 if (eb.afstand < 0.151) {
378 return "." + targetAddress.rute;
379 } else if (eb.afstand < 0.801) {
380 return ".." + targetAddress.rute;
381 } else if (eb.afstand < 1.201) {
382 return "..." + targetAddress.rute;
383 } else if (eb.afstand < 2.101) {
384 return "...." + targetAddress.rute;
385 }
386 break;
387 case "bil":
388 if (eb.afstand < 0.151) {
389 return "." + targetAddress.rute;
390 } else if (eb.afstand < 1.001) {
391 return ".." + targetAddress.rute;
392 } else if (eb.afstand < 1.601) {
393 return "..." + targetAddress.rute;
394 } else if (eb.afstand < 2.601) {
395 return "...." + targetAddress.rute;
396 }
397 break;
398 }
399 return null;
400 }
401
402 public List<Address> getNonCoveredAddresses() {
403 List<Address> result = new ArrayList<Address>(60000);
404 for (Address a : alleAdresser) {
405 if ( a.daekningsType == DaekningsType.DAEKNING_IKKEDAEKKET) {
406 result.add(a);
407 }
408 }
409 Collections.sort(result );
410 return result;
411 }
412
413 ///////////////////////////////////////////////////////////
414 private String calculateExtendedBkKoreliste(ExtendedBean eb, Address orgAddress, Address targetAddress) {
415 String inject;
416 if (eb.afstand <= 0.500) {
417 inject = ".";
418 } else {
419 inject = "..";
420 }
421 return AddressUtils.injectIntoBk(targetAddress.koreliste, inject);
422 }
423
424 private Set<String> findVejAliaser(String vejnavn) {
425 vejnavn = vejnavn.toLowerCase();
426 HashSet<String> aliasSet = new HashSet<String>();
427 aliasSet.add(vejnavn);
428
429 aliasSet.add(vejnavn.replace("u", "ü") );
430 aliasSet.add(vejnavn.replace("ü", "u") );
431
432 aliasSet.add(vejnavn.replace("alle", "allé") );
433 aliasSet.add(vejnavn.replace("allé", "alle") );
434
435 aliasSet.add(vejnavn.replace("dronningens", "dr") );
436 aliasSet.add(vejnavn.replace("dr.", "dronningens") );
437 aliasSet.add(vejnavn.replace("dr ", "dronningens") );
438
439 aliasSet.add(vejnavn.replace("kvt", "kvarter") );
440 aliasSet.add(vejnavn.replace("kvarter", "kvt") );
441
442 aliasSet.add(vejnavn.replace("gl", "gammel") );
443 aliasSet.add(vejnavn.replace("gammel", "gl") );
444
445 aliasSet.add(vejnavn.replace("lille", "ll") );
446 aliasSet.add(vejnavn.replace("ll ", "lille") );
447 aliasSet.add(vejnavn.replace("ll.", "lille") );
448
449 aliasSet.add(vejnavn.replace("store", "st") );
450 aliasSet.add(vejnavn.replace("st ", "store") );
451 aliasSet.add(vejnavn.replace("st.", "store") );
452
453 aliasSet.add(vejnavn.replace("søndre", "sdr") );
454 aliasSet.add(vejnavn.replace("sdr", "søndre") );
455
456
457 aliasSet.add(vejnavn.replace("nørre", "nr") );
458 aliasSet.add(vejnavn.replace("nr", "nørre") );
459
460 aliasSet.add(vejnavn.replace("nordre", "ndr") );
461 aliasSet.add(vejnavn.replace("ndr", "nordre") );
462
463 aliasSet.add(vejnavn.replace("sankt", "skt") );
464 aliasSet.add(vejnavn.replace("sankt", "sct") );
465 aliasSet.add(vejnavn.replace("skt", "sankt") );
466
467 aliasSet.add(vejnavn.replace("skt", "sct") );
468 aliasSet.add(vejnavn.replace("sct", "skt") );
469
470
471 //alternative måder at stave vej/gade/alle
472 aliasSet.add(vejnavn.replace("vej", "ve") );
473 aliasSet.add(vejnavn.replace("vej", "vj") );
474 aliasSet.add(vejnavn.replace("vej", "v") );
475
476 aliasSet.add(vejnavn.replace("alle", "all") );
477 aliasSet.add(vejnavn.replace("allé", "all") );
478 aliasSet.add(vejnavn.replace("alle", "allú") ); //Fundet i logs.hentruteinfo
479 aliasSet.add(vejnavn.replace("allé", "allú") );
480
481 aliasSet.add(vejnavn.replace("gade", "gaed") ); //Fundet i logs.hentruteinfo
482
483
484 // Opbyg æøå varianter over alle fundne aliaser
485
486 @SuppressWarnings("unchecked")
487 HashSet<String> variants = (HashSet<String>) aliasSet.clone();
488
489 for (String vVejnavn : variants) {
490 // danske tegn 1
491 aliasSet.add( vVejnavn.replace("æ", "ae") );
492 aliasSet.add( vVejnavn.replace("ø", "oe") );
493 aliasSet.add( vVejnavn.replace("å", "aa") );
494 aliasSet.add( vVejnavn.replace("ae", "æ") );
495 aliasSet.add( vVejnavn.replace("oe", "ø") );
496 aliasSet.add( vVejnavn.replace("aa", "å") );
497
498 //danske tegn 2
499 aliasSet.add( vVejnavn.replace("æ", "ae").replace("ø", "oe") );
500 aliasSet.add( vVejnavn.replace("æ", "ae").replace("å", "aa") );
501 aliasSet.add( vVejnavn.replace("ø", "ae").replace("å", "aa") );
502 aliasSet.add( vVejnavn.replace("ae", "æ").replace("oe","ø") );
503 aliasSet.add( vVejnavn.replace("ae", "æ").replace("aa","å") );
504 aliasSet.add( vVejnavn.replace("oe", "ø").replace("aa", "å") );
505
506 //danske tegn 3
507 aliasSet.add( vejnavn.replace("æ", "ae").replace("ø", "oe").replace("å", "aa") );
508 aliasSet.add( vejnavn.replace("ae", "æ").replace("oe", "ø").replace("aa", "å") );
509 }
510
511 return aliasSet;
512 }
513
514
515 }

  ViewVC Help
Powered by ViewVC 1.1.20