package dk.daoas.daoadresseservice; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import dk.daoas.daoadresseservice.AddressUtils.SplitResult; import dk.daoas.daoadresseservice.admin.ServiceConfig; import dk.daoas.daoadresseservice.beans.Address; import dk.daoas.daoadresseservice.beans.DataStatisticsBean; import dk.daoas.daoadresseservice.beans.ExtendedBean; import dk.daoas.daoadresseservice.beans.HundredePctBean; import dk.daoas.daoadresseservice.beans.SearchResult; import dk.daoas.daoadresseservice.beans.SearchResult.Status; import dk.daoas.daoadresseservice.db.DatabaseLayer; public class AdressSearch { private Map> searchPostnrVejnavnGadeid; private Map> searchGadeidentAdresser; private List
alleAdresser; private Map helperCache; private DataStatisticsBean stats = new DataStatisticsBean(); public SearchResult search(ServiceConfig config, String postnrStr, String adresse) { int postnr=0; boolean google = false; boolean osm = false; String helperSearchKey = ""; try { postnr = Integer.parseInt(postnrStr); } catch (Exception E) { return new SearchResult(Status.ERROR_UNKNOWN_POSTAL); } Map postnrVeje = searchPostnrVejnavnGadeid.get(postnr); if (postnrVeje == null) { return new SearchResult(Status.ERROR_UNKNOWN_POSTAL); } SplitResult split = AddressUtils.splitAdresse(adresse); String vasketVejnavn = AddressUtils.vaskVejnavn( split.vej ); if (split.husnr.length() == 0) { return new SearchResult(Status.ERROR_MISSING_HOUSENUMBER); } Long gadeident = postnrVeje.get(vasketVejnavn); if ( gadeident == null) { helperSearchKey = "" + postnr + "/" + vasketVejnavn; gadeident = helperCache.get(helperSearchKey); } if ( gadeident == null) { if (config.useGoogle) { String googleVej = GeocodeHelper.googleHelper(config, postnr, split.vej ); google = true; if (googleVej != null) { String googleVasket = AddressUtils.vaskVejnavn( googleVej ); gadeident = postnrVeje.get(googleVasket); if (gadeident != null) { helperCache.put(helperSearchKey, gadeident); } } } } if ( gadeident == null) { if (config.useOpenStreetMaps) { String osmVej = GeocodeHelper.openstreetmapHelper(postnr, split.vej ); osm = true; if (osmVej != null) { String osmVasket = AddressUtils.vaskVejnavn( osmVej ); gadeident = postnrVeje.get(osmVasket); if (gadeident != null) { helperCache.put(helperSearchKey, gadeident); } } } } if (gadeident == null) { return new SearchResult(Status.ERROR_UNKNOWN_STREETNAME); } Map gade = searchGadeidentAdresser.get(gadeident); //Denne søgning må ikke fejle String husnrSearch = "" + split.husnr + split.litra; Address addr = gade.get(husnrSearch); if (addr == null) { return new SearchResult(Status.ERROR_UNKNOWN_ADDRESSPOINT); } if (addr.daekningsType == DaekningsType.DAEKNING_IKKEDAEKKET) { return new SearchResult(Status.STATUS_NOT_COVERED); } if (addr.distributor.equals("LUKKET")) { return new SearchResult(Status.STATUS_NOT_COVERED); //Skal vi have en special status til Lukkede adresser ? } SearchResult res = new SearchResult(addr); res.google = google; res.osm = osm; return res; } public void buildSearchStructures() throws SQLException{ searchPostnrVejnavnGadeid = new HashMap>(); searchGadeidentAdresser = new HashMap>(); helperCache = new ConcurrentHashMap(); long start1 = System.currentTimeMillis(); System.out.println("Build -- stage 1"); alleAdresser = DatabaseLayer.getAllAdresses(); /* Mapper mellem db Row ID og adresse noden */ Map idAddressMap = new HashMap( alleAdresser.size() ); for (Address a : alleAdresser) { idAddressMap.put(a.id, a); Map postnrVeje = searchPostnrVejnavnGadeid.get(a.postnr); if (postnrVeje == null) { postnrVeje = new ConcurrentHashMap(); searchPostnrVejnavnGadeid.put(a.postnr, postnrVeje); } String vasketVejnavn = AddressUtils.vaskVejnavn(a.vejnavn); Long gadeident = postnrVeje.get(vasketVejnavn); if (gadeident == null) { //postnrVeje.put(vasketVejnavn, a.gadeid); Set aliaser = findVejAliaser(a.vejnavn); for(String alias : aliaser) { String vasketAlias = AddressUtils.vaskVejnavn(alias); postnrVeje.put(vasketAlias, a.gadeid); } } Map gade = searchGadeidentAdresser.get(a.gadeid); if (gade == null) { gade = new HashMap(); searchGadeidentAdresser.put(a.gadeid, gade); } String husnrSearch = "" + a.husnr + a.husnrbogstav; gade.put(husnrSearch, a); } //////////////////////////////////////////////////////////////////////////////////////// long start2 = System.currentTimeMillis(); System.out.println("Build, stage1 elapsed: " + (start2-start1) ); System.out.println("Build -- stage 2 udvidet dækning"); List extDao = DatabaseLayer.getExtendedAdresslist(); for (ExtendedBean eb : extDao) { Address orgAddress = idAddressMap.get(eb.orgId); if (orgAddress == null) continue; Address targetAddress = idAddressMap.get(eb.targetId); if (targetAddress == null) continue; if (orgAddress.distributor != null && orgAddress.distributor.equals("LUKKET")) { continue; } if (targetAddress.distributor.equals("LUKKET")) { continue; } orgAddress.extTarget = targetAddress; orgAddress.extAfstand = eb.afstand; boolean covered = false; if (targetAddress.distributor.equals("DAO")) { orgAddress.rute = calculateExtendedDaoRoute(eb,orgAddress,targetAddress); if (orgAddress.rute != null) { orgAddress.koreliste = targetAddress.koreliste; covered = true; } } if (targetAddress.distributor.equals("BK")) { orgAddress.koreliste = calculateExtendedBkKoreliste(eb,orgAddress,targetAddress); if (orgAddress.koreliste != null) { orgAddress.rute = targetAddress.rute; covered = true; } } if (covered) { //Kopier resten af felterne orgAddress.daekningsType = DaekningsType.DAEKNING_UDVIDET; orgAddress.dbkBane = targetAddress.dbkBane; /* Sådan gør den gamle service */ orgAddress.kommunekode = targetAddress.kommunekode; orgAddress.vejkode = targetAddress.vejkode; orgAddress.distributor = targetAddress.distributor; } } // nu skal vi ikke bruge idAddressMap længere idAddressMap = null; ////////////////////////////////////////////////////////////////////////////////////// long start3 = System.currentTimeMillis(); System.out.println("Build, stage2 elapsed: " + (start3-start2) ); System.out.println("Build -- stage 3 - 100pct"); Map hundredePct = DatabaseLayer.get100PctList(); for (Address addr : alleAdresser) { if (addr.daekningsType != DaekningsType.DAEKNING_IKKEDAEKKET) { continue; } if (addr.distributor != null && addr.distributor.equals("LUKKET")) { continue; } HundredePctBean bean = hundredePct.get(addr.postnr); if (bean == null) { continue; } addr.daekningsType = DaekningsType.DAEKNING_100PCT; addr.rute = bean.rute; addr.koreliste = bean.koreliste; addr.dbkBane = bean.dbkBane; addr.distributor = bean.distributor; } //////////////////////////////////////////////////////////////////////////////////// long stop = System.currentTimeMillis(); System.out.println("Build, stage3 elapsed: " + (stop-start3) ); System.out.println("Build -- Gathering statistics"); for (Address addr : alleAdresser) { switch (addr.daekningsType) { case DAEKNING_DIREKTE: stats.direkteCount++; break; case DAEKNING_UDVIDET: stats.extendedCount++; break; case DAEKNING_100PCT: stats.hundredePctCount++; break; default: stats.ikkeDaekketCount++; } } stats.elapsed = stop-start1; stats.buildTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( new Date() ); System.out.println("Build: direkteCount: " + stats.direkteCount); System.out.println("Build: extendedCount: " + stats.extendedCount); System.out.println("Build: hundredePctCount: " + stats.hundredePctCount); System.out.println("Build: ikkeDaekketCount: " + stats.ikkeDaekketCount); System.out.println("Build: Total Elapsed: " + (stop-start1) ); System.out.println("Build Completed"); } public DataStatisticsBean getStatistics() { return stats; } public void clear() { searchPostnrVejnavnGadeid.clear(); searchGadeidentAdresser.clear(); alleAdresser.clear(); helperCache.clear(); } private String calculateExtendedDaoRoute(ExtendedBean eb, Address orgAddress, Address targetAddress) { // /////////////////////////////////////////////////////////////////// switch( eb.transport) { case "cykel": if (eb.afstand < 0.151) { return "." + targetAddress.rute; } else if (eb.afstand < 0.501) { return ".." + targetAddress.rute; } else if (eb.afstand < 0.701) { return "..." + targetAddress.rute; } else if (eb.afstand < 0.501) { return "...." + targetAddress.rute; } break; case "scooter": if (eb.afstand < 0.151) { return "." + targetAddress.rute; } else if (eb.afstand < 0.801) { return ".." + targetAddress.rute; } else if (eb.afstand < 1.201) { return "..." + targetAddress.rute; } else if (eb.afstand < 2.101) { return "...." + targetAddress.rute; } break; case "bil": if (eb.afstand < 0.151) { return "." + targetAddress.rute; } else if (eb.afstand < 1.001) { return ".." + targetAddress.rute; } else if (eb.afstand < 1.601) { return "..." + targetAddress.rute; } else if (eb.afstand < 2.601) { return "...." + targetAddress.rute; } break; } return null; } public List
getNonCoveredAddresses() { List
result = new ArrayList
(60000); for (Address a : alleAdresser) { if ( a.daekningsType == DaekningsType.DAEKNING_IKKEDAEKKET) { result.add(a); } } Collections.sort(result ); return result; } /////////////////////////////////////////////////////////// private String calculateExtendedBkKoreliste(ExtendedBean eb, Address orgAddress, Address targetAddress) { String inject; if (eb.afstand <= 0.500) { inject = "."; } else { inject = ".."; } return AddressUtils.injectIntoBk(targetAddress.koreliste, inject); } private Set findVejAliaser(String vejnavn) { vejnavn = vejnavn.toLowerCase(); HashSet aliasSet = new HashSet(); aliasSet.add(vejnavn); aliasSet.add(vejnavn.replace("u", "ü") ); aliasSet.add(vejnavn.replace("ü", "u") ); aliasSet.add(vejnavn.replace("alle", "allé") ); aliasSet.add(vejnavn.replace("allé", "alle") ); aliasSet.add(vejnavn.replace("dronningens", "dr") ); aliasSet.add(vejnavn.replace("dr.", "dronningens") ); aliasSet.add(vejnavn.replace("dr ", "dronningens") ); aliasSet.add(vejnavn.replace("kvt", "kvarter") ); aliasSet.add(vejnavn.replace("kvarter", "kvt") ); aliasSet.add(vejnavn.replace("gl", "gammel") ); aliasSet.add(vejnavn.replace("gammel", "gl") ); aliasSet.add(vejnavn.replace("lille", "ll") ); aliasSet.add(vejnavn.replace("ll ", "lille") ); aliasSet.add(vejnavn.replace("ll.", "lille") ); aliasSet.add(vejnavn.replace("store", "st") ); aliasSet.add(vejnavn.replace("st ", "store") ); aliasSet.add(vejnavn.replace("st.", "store") ); aliasSet.add(vejnavn.replace("søndre", "sdr") ); aliasSet.add(vejnavn.replace("sdr", "søndre") ); aliasSet.add(vejnavn.replace("nørre", "nr") ); aliasSet.add(vejnavn.replace("nr", "nørre") ); aliasSet.add(vejnavn.replace("nordre", "ndr") ); aliasSet.add(vejnavn.replace("ndr", "nordre") ); aliasSet.add(vejnavn.replace("sankt", "skt") ); aliasSet.add(vejnavn.replace("sankt", "sct") ); aliasSet.add(vejnavn.replace("skt", "sankt") ); aliasSet.add(vejnavn.replace("skt", "sct") ); aliasSet.add(vejnavn.replace("sct", "skt") ); // Opbyg æøå varianter over alle fundne aliaser @SuppressWarnings("unchecked") HashSet variants = (HashSet) aliasSet.clone(); for (String vVejnavn : variants) { // danske tegn 1 aliasSet.add( vVejnavn.replace("æ", "ae") ); aliasSet.add( vVejnavn.replace("ø", "oe") ); aliasSet.add( vVejnavn.replace("å", "aa") ); aliasSet.add( vVejnavn.replace("ae", "æ") ); aliasSet.add( vVejnavn.replace("oe", "ø") ); aliasSet.add( vVejnavn.replace("aa", "å") ); //danske tegn 2 aliasSet.add( vVejnavn.replace("æ", "ae").replace("ø", "oe") ); aliasSet.add( vVejnavn.replace("æ", "ae").replace("å", "aa") ); aliasSet.add( vVejnavn.replace("ø", "ae").replace("å", "aa") ); aliasSet.add( vVejnavn.replace("ae", "æ").replace("oe","ø") ); aliasSet.add( vVejnavn.replace("ae", "æ").replace("aa","å") ); aliasSet.add( vVejnavn.replace("oe", "ø").replace("aa", "å") ); //danske tegn 3 aliasSet.add( vejnavn.replace("æ", "ae").replace("ø", "oe").replace("å", "aa") ); aliasSet.add( vejnavn.replace("ae", "æ").replace("oe", "ø").replace("aa", "å") ); } return aliasSet; } }