From b540b5b2e75a833c214cb5c697cf5e52c6c2014f Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Thu, 18 Jun 2020 14:18:24 +0200 Subject: [PATCH] Add aditional types to search --- .../osmand/search/core/SearchCoreFactory.java | 172 ++++++++++++------ 1 file changed, 121 insertions(+), 51 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java index e174967d97..26d16e2c54 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java @@ -35,6 +35,7 @@ import net.osmand.util.MapUtils; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -669,6 +670,11 @@ public class SearchCoreFactory { return phrase.getNextRadiusSearch(BBOX_RADIUS); } } + + protected static class PoiTypeResult { + public AbstractPoiType pt; + public Set foundWords = new LinkedHashSet(); + } public static class SearchAmenityTypesAPI extends SearchBaseAPI { @@ -704,68 +710,102 @@ public class SearchCoreFactory { } } - public Map> getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) { - Map> results = new LinkedHashMap<>(); + public Map getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) { + Map results = new LinkedHashMap<>(); for (AbstractPoiType pf : topVisibleFilters) { - checkPoiType(nm, pf, results); + PoiTypeResult res = checkPoiType(nm, pf); + if(res != null) { + results.put(res.pt.getKeyName(), res); + } + } + if (includeAdditionals) { + addAditonals(nm, results, types.getOtherMapCategory()); } for (PoiCategory c : categories) { - checkPoiType(nm, c, results); + PoiTypeResult res = checkPoiType(nm, c); + if(res != null) { + results.put(res.pt.getKeyName(), res); + } + if (includeAdditionals) { + addAditonals(nm, results, c); + } } Iterator> it = translatedNames.entrySet().iterator(); while (it.hasNext()) { Entry e = it.next(); PoiType pt = e.getValue(); - if (pt.getCategory() != types.getOtherMapCategory()) { - checkPoiType(nm, pt, results); - List additionals = pt.getPoiAdditionals(); - if (additionals != null && includeAdditionals) { - for (PoiType a : additionals) { - if (!results.containsKey(a)) { - String enTranslation = a.getEnTranslation().toLowerCase(); - if (!"yes".equals(enTranslation) && !"no".equals(enTranslation)) { - checkPoiType(nm, a, results); - } - } - } + if (pt.getCategory() != types.getOtherMapCategory() && !pt.isReference()) { + PoiTypeResult res = checkPoiType(nm, pt); + if(res != null) { + results.put(res.pt.getKeyName(), res); + } + if (includeAdditionals) { + addAditonals(nm, results, pt); } } } return results; } - private void checkPoiType(NameStringMatcher nm, AbstractPoiType pf, Map> results) { - List lst = results.get(pf); - boolean nl = lst == null; + private void addAditonals(NameStringMatcher nm, Map results, AbstractPoiType pt) { + List additionals = pt.getPoiAdditionals(); + if (additionals != null) { + for (PoiType a : additionals) { + PoiTypeResult existingResult = results.get(a.getKeyName()); + if (existingResult != null) { + PoiAdditionalCustomFilter f ; + if (existingResult.pt instanceof PoiAdditionalCustomFilter) { + f = (PoiAdditionalCustomFilter) existingResult.pt; + } else { + f = new PoiAdditionalCustomFilter(types, (PoiType) existingResult.pt); + } + f.additionalPoiTypes.add(a); + existingResult.pt = f; + } else { + String enTranslation = a.getEnTranslation().toLowerCase(); + if (!"no".equals(enTranslation) // && !"yes".equals(enTranslation) + ) { + PoiTypeResult ptr = checkPoiType(nm, a); + if (ptr != null) { + results.put(a.getKeyName(), ptr); + } + } + } + } + } + } + + private PoiTypeResult checkPoiType(NameStringMatcher nm, AbstractPoiType pf) { + PoiTypeResult res = null; if (nm.matches(pf.getTranslation())) { - lst = addToList(pf.getTranslation(), lst); + res = addIfMatch(nm, pf.getTranslation(), pf, res); } if (nm.matches(pf.getEnTranslation())) { - lst = addToList(pf.getEnTranslation(), lst); + res = addIfMatch(nm, pf.getEnTranslation(), pf, res); } if (nm.matches(pf.getKeyName())) { - lst = addToList(pf.getKeyName().replace('_', ' '), lst); + res = addIfMatch(nm, pf.getKeyName().replace('_', ' '), pf, res); } if (nm.matches(pf.getSynonyms())) { String[] synonyms = pf.getSynonyms().split(";"); for (String synonym : synonyms) { - if (nm.matches(synonym)) { - lst = addToList(synonym, lst); - } + res = addIfMatch(nm, synonym, pf, res); } } - if(lst != null && nl) { - results.put(pf, lst); - } + return res; } - private List addToList(String s, List lst) { - if(lst == null) { - lst = new ArrayList<>(); + private PoiTypeResult addIfMatch(NameStringMatcher nm, String s, AbstractPoiType pf, PoiTypeResult res) { + if (nm.matches(s)) { + if (res == null) { + res = new PoiTypeResult(); + res.pt = pf; + } + res.foundWords.add(s); + } - lst.add(s); - return lst; + return res; } private void initPoiTypes() { @@ -792,11 +832,11 @@ public class SearchCoreFactory { } else { boolean includeAdditional = !phrase.hasMoreThanOneUnknownSearchWord(); - Map> poiTypes = getPoiTypeResults(nm, includeAdditional); - for (Entry> pt : poiTypes.entrySet()) { + Map poiTypes = getPoiTypeResults(nm, includeAdditional); + for (PoiTypeResult ptr : poiTypes.values()) { boolean match = !phrase.isFirstUnknownSearchWordComplete(); if (!match) { - for (String foundName : pt.getValue()) { + for (String foundName : ptr.foundWords) { CollatorStringMatcher csm = new CollatorStringMatcher(foundName, StringMatcherMode.CHECK_ONLY_STARTS_WITH); match = csm.matches(phrase.getUnknownSearchPhrase()); if (match) { @@ -806,9 +846,9 @@ public class SearchCoreFactory { } if (match) { SearchResult res = new SearchResult(phrase); - res.localeName = pt.getKey().getTranslation(); - res.object = pt.getKey(); - addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(pt.getKey()), + res.localeName = ptr.pt.getTranslation(); + res.object = ptr.pt; + addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(ptr.pt), res); } } @@ -826,7 +866,7 @@ public class SearchCoreFactory { } private void addPoiTypeResult(SearchPhrase phrase, SearchResultMatcher resultMatcher, boolean showTopFiltersOnly, - String stdFilterId , SearchResult res) { + String stdFilterId, SearchResult res) { res.priorityDistance = 0; res.objectType = ObjectType.POI_TYPE; res.firstUnknownWordMatches = true; @@ -919,7 +959,7 @@ public class SearchCoreFactory { SearchPoiTypeFilter poiTypeFilter = null; String nameFilter = null; int countExtraWords = 0; - Map poiAdditionals = new LinkedHashMap(); + Set poiAdditionals = new LinkedHashSet<>(); if (phrase.isLastWord(ObjectType.POI_TYPE)) { Object obj = phrase.getLastSelectedWord().getResult().object; if (obj instanceof AbstractPoiType) { @@ -933,10 +973,10 @@ public class SearchCoreFactory { } else if (searchAmenityTypesAPI != null && phrase.isFirstUnknownSearchWordComplete()) { NameStringMatcher nm = phrase.getFirstUnknownNameStringMatcher(); searchAmenityTypesAPI.initPoiTypes(); - Map> poiTypeResults = searchAmenityTypesAPI.getPoiTypeResults(nm, true); + Map poiTypeResults = searchAmenityTypesAPI.getPoiTypeResults(nm, true); // find first full match only - for (Entry> poiType : poiTypeResults.entrySet()) { - for (String foundName : poiType.getValue()) { + for (PoiTypeResult poiTypeResult : poiTypeResults.values()) { + for (String foundName : poiTypeResult.foundWords) { CollatorStringMatcher csm = new CollatorStringMatcher(foundName, StringMatcherMode.CHECK_ONLY_STARTS_WITH); // matches only completely int mwords = phrase.countWords(foundName) ; @@ -953,8 +993,8 @@ public class SearchCoreFactory { nameFilter += otherSearchWords.get(k); } } - poiTypeFilter = getPoiTypeFilter(poiType.getKey(), poiAdditionals); - unselectedPoiType = poiType.getKey(); + poiTypeFilter = getPoiTypeFilter(poiTypeResult.pt, poiAdditionals); + unselectedPoiType = poiTypeResult.pt; } } } @@ -983,7 +1023,7 @@ public class SearchCoreFactory { private ResultMatcher getResultMatcher(final SearchPhrase phrase, final SearchPoiTypeFilter poiTypeFilter, final SearchResultMatcher resultMatcher, final String nameFilter, final BinaryMapIndexReader selected, final Set searchedPois, - final Map poiAdditionals, final int countExtraWords) { + final Collection poiAdditionals, final int countExtraWords) { final NameStringMatcher ns = nameFilter == null ? null : new NameStringMatcher(nameFilter, StringMatcherMode.CHECK_STARTS_FROM_SPACE); @@ -1004,7 +1044,7 @@ public class SearchCoreFactory { } if (!poiAdditionals.isEmpty()) { boolean found = false; - for (String add : poiAdditionals.keySet()) { + for (String add : poiAdditionals) { if(object.getAdditionalInfo().containsKey(add)) { found = true; break; @@ -1058,13 +1098,13 @@ public class SearchCoreFactory { }; } - private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt, Map poiAdditionals ) { + private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt, Set poiAdditionals ) { final Map> acceptedTypes = new LinkedHashMap>(); pt.putTypes(acceptedTypes); poiAdditionals.clear(); - if (pt instanceof PoiType && ((PoiType) pt).isAdditional() && ((PoiType) pt).getParentType() != null) { - poiAdditionals.put(pt.getKeyName(), (PoiType) pt); + if (pt.isAdditional()) { + poiAdditionals.add(pt.getKeyName()); } return new SearchPoiTypeFilter() { @@ -1324,6 +1364,36 @@ public class SearchCoreFactory { return SEARCH_BUILDING_BY_STREET_PRIORITY; } } + + protected static class PoiAdditionalCustomFilter extends AbstractPoiType { + + protected List additionalPoiTypes = new ArrayList(); + + public PoiAdditionalCustomFilter(MapPoiTypes registry, PoiType pt) { + super(pt.getKeyName(), registry); + additionalPoiTypes.add(pt); + } + + @Override + public boolean isAdditional() { + return true; + } + + public Map> putTypes(Map> acceptedTypes) { + for (PoiType p : additionalPoiTypes) { + if (p.getParentType() == registry.getOtherMapCategory()) { + for (PoiCategory c : registry.getCategories(false)) { + c.putTypes(acceptedTypes); + } + } else { + p.getParentType().putTypes(acceptedTypes); + } + + } + return acceptedTypes; + } + + } public static class SearchLocationAndUrlAPI extends SearchBaseAPI {