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

  ViewVC Help
Powered by ViewVC 1.1.20