Initial commit address search refactoring

This commit is contained in:
Victor Shcherb 2020-06-01 13:54:03 +02:00
parent fd9f87ba1d
commit f40657ebec
12 changed files with 514 additions and 503 deletions

View file

@ -17,12 +17,20 @@ public class CollatorStringMatcher implements StringMatcher {
private final String part; private final String part;
public static enum StringMatcherMode { public static enum StringMatcherMode {
// tests only first word as base starts with part
CHECK_ONLY_STARTS_WITH, CHECK_ONLY_STARTS_WITH,
// tests all words (split by space) and one of word should start with a given part
CHECK_STARTS_FROM_SPACE, CHECK_STARTS_FROM_SPACE,
// tests all words except first (split by space) and one of word should start with a given part
CHECK_STARTS_FROM_SPACE_NOT_BEGINNING, CHECK_STARTS_FROM_SPACE_NOT_BEGINNING,
// tests all words (split by space) and one of word should be equal to part
CHECK_EQUALS_FROM_SPACE, CHECK_EQUALS_FROM_SPACE,
// TO DO: make a separate method
// trims part to make shorter then full text and tests only first word as base starts with part
TRIM_AND_CHECK_ONLY_STARTS_WITH,
// simple collator contains in any part of the base
CHECK_CONTAINS, CHECK_CONTAINS,
CHECK_ONLY_STARTS_WITH_TRIM, // simple collator equals
CHECK_EQUALS, CHECK_EQUALS,
} }
@ -42,22 +50,25 @@ public class CollatorStringMatcher implements StringMatcher {
} }
public static boolean cmatches(Collator collator, String base, String part, StringMatcherMode mode){ public static boolean cmatches(Collator collator, String fullName, String part, StringMatcherMode mode){
switch (mode) { switch (mode) {
case CHECK_CONTAINS: case CHECK_CONTAINS:
return ccontains(collator, base, part); return ccontains(collator, fullName, part);
case CHECK_EQUALS_FROM_SPACE: case CHECK_EQUALS_FROM_SPACE:
return cstartsWith(collator, base, part, true, true, true, false); return cstartsWith(collator, fullName, part, true, true, true);
case CHECK_STARTS_FROM_SPACE: case CHECK_STARTS_FROM_SPACE:
return cstartsWith(collator, base, part, true, true, false, false); return cstartsWith(collator, fullName, part, true, true, false);
case CHECK_STARTS_FROM_SPACE_NOT_BEGINNING: case CHECK_STARTS_FROM_SPACE_NOT_BEGINNING:
return cstartsWith(collator, base, part, false, true, false, false); return cstartsWith(collator, fullName, part, false, true, false);
case CHECK_ONLY_STARTS_WITH: case CHECK_ONLY_STARTS_WITH:
return cstartsWith(collator, base, part, true, false, false, false); return cstartsWith(collator, fullName, part, true, false, false);
case CHECK_ONLY_STARTS_WITH_TRIM: case TRIM_AND_CHECK_ONLY_STARTS_WITH:
return cstartsWith(collator, base, part, true, false, false, true); if (part.length() > fullName.length()) {
part = part.substring(0, fullName.length());
}
return cstartsWith(collator, fullName, part, true, false, false);
case CHECK_EQUALS: case CHECK_EQUALS:
return cstartsWith(collator, base, part, false, false, true, false); return cstartsWith(collator, fullName, part, false, false, true);
} }
return false; return false;
} }
@ -116,21 +127,14 @@ public class CollatorStringMatcher implements StringMatcher {
* Special check try to find as well in the middle of name * Special check try to find as well in the middle of name
* *
* @param collator * @param collator
* @param searchInParam * @param fullText
* @param theStart * @param theStart
* @param trim - trim theStart to searchInParam length if searchInParam non empty
* @return true if searchIn starts with token * @return true if searchIn starts with token
*/ */
public static boolean cstartsWith(Collator collator, String searchInParam, String theStart, public static boolean cstartsWith(Collator collator, String fullText, String theStart,
boolean checkBeginning, boolean checkSpaces, boolean equals, boolean trim) { boolean checkBeginning, boolean checkSpaces, boolean equals) {
String searchIn = searchInParam.toLowerCase(Locale.getDefault()); String searchIn = fullText.toLowerCase(Locale.getDefault());
if (trim && searchIn.length() > 0) {
searchIn += " ";
}
int searchInLength = searchIn.length(); int searchInLength = searchIn.length();
if (trim && searchInLength > 0 && theStart.length() > searchInLength) {
theStart = theStart.substring(0, searchInLength);
}
int startLength = theStart.length(); int startLength = theStart.length();
if (startLength == 0) { if (startLength == 0) {
return true; return true;

View file

@ -13,10 +13,6 @@ public class CommonWords {
frequentlyUsedWordsDictionary.put(string, frequentlyUsedWordsDictionary.size()); frequentlyUsedWordsDictionary.put(string, frequentlyUsedWordsDictionary.size());
} }
public static int getCommon(String name) { public static int getCommon(String name) {
// if(true) {
// // not ready for old versions yet
// return -1;
// }
Integer i = commonWordsDictionary.get(name); Integer i = commonWordsDictionary.get(name);
return i == null ? -1 : i.intValue(); return i == null ? -1 : i.intValue();
} }
@ -28,7 +24,15 @@ public class CommonWords {
public static int getCommonSearch(String name) { public static int getCommonSearch(String name) {
Integer i = commonWordsDictionary.get(name); Integer i = commonWordsDictionary.get(name);
return i == null ? getFrequentlyUsed(name) : i.intValue() + frequentlyUsedWordsDictionary.size(); // higher means better for search
if (i == null) {
int fq = getFrequentlyUsed(name);
if (fq != -1) {
return commonWordsDictionary.size() + fq;
}
return -1;
}
return i.intValue();
} }
public static int getCommonGeocoding(String name) { public static int getCommonGeocoding(String name) {

View file

@ -1,7 +1,6 @@
package net.osmand.search; package net.osmand.search;
import net.osmand.Collator; import net.osmand.Collator;
import net.osmand.OsmAndCollator;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher; import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader;
@ -72,7 +71,7 @@ public class SearchUICore {
taskQueue = new LinkedBlockingQueue<Runnable>(); taskQueue = new LinkedBlockingQueue<Runnable>();
searchSettings = new SearchSettings(new ArrayList<BinaryMapIndexReader>()); searchSettings = new SearchSettings(new ArrayList<BinaryMapIndexReader>());
searchSettings = searchSettings.setLang(locale, transliterate); searchSettings = searchSettings.setLang(locale, transliterate);
phrase = new SearchPhrase(searchSettings, OsmAndCollator.primaryCollator()); phrase = SearchPhrase.emptyPhrase();
currentSearchResult = new SearchResultCollection(phrase); currentSearchResult = new SearchResultCollection(phrase);
singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, taskQueue); singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, taskQueue);
} }
@ -351,10 +350,10 @@ public class SearchUICore {
} }
} }
public void setFilterOrders(List<String> filterOrders) { public void setActivePoiFiltersByOrder(List<String> filterOrders) {
for (SearchCoreAPI capi : apis) { for (SearchCoreAPI capi : apis) {
if (capi instanceof SearchAmenityTypesAPI) { if (capi instanceof SearchAmenityTypesAPI) {
((SearchAmenityTypesAPI) capi).setFilterOrders(filterOrders); ((SearchAmenityTypesAPI) capi).setActivePoiFiltersByOrder(filterOrders);
} }
} }
} }
@ -404,7 +403,7 @@ public class SearchUICore {
} }
private boolean filterOneResult(SearchResult object, SearchPhrase phrase) { private boolean filterOneResult(SearchResult object, SearchPhrase phrase) {
NameStringMatcher nameStringMatcher = phrase.getNameStringMatcher(); NameStringMatcher nameStringMatcher = phrase.getFirstUnknownNameStringMatcher();
return nameStringMatcher.matches(object.localeName) || nameStringMatcher.matches(object.otherNames); return nameStringMatcher.matches(object.localeName) || nameStringMatcher.matches(object.otherNames);
} }
@ -714,16 +713,17 @@ public class SearchUICore {
@Override @Override
public boolean publish(SearchResult object) { public boolean publish(SearchResult object) {
if (phrase != null && object.otherNames != null && !phrase.getNameStringMatcher().matches(object.localeName)) { // TODO first , other?
if (phrase != null && object.otherNames != null && !phrase.getFirstUnknownNameStringMatcher().matches(object.localeName)) {
for (String s : object.otherNames) { for (String s : object.otherNames) {
if (phrase.getNameStringMatcher().matches(s)) { if (phrase.getFirstUnknownNameStringMatcher().matches(s)) {
object.alternateName = s; object.alternateName = s;
break; break;
} }
} }
if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) { if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) {
for (String value : ((Amenity) object.object).getAdditionalInfo().values()) { for (String value : ((Amenity) object.object).getAdditionalInfo().values()) {
if (phrase.getNameStringMatcher().matches(value)) { if (phrase.getFirstUnknownNameStringMatcher().matches(value)) {
object.alternateName = value; object.alternateName = value;
break; break;
} }
@ -815,7 +815,7 @@ public class SearchUICore {
SearchExportSettings exportSettings = phrase.getSettings().getExportSettings(); SearchExportSettings exportSettings = phrase.getSettings().getExportSettings();
json.put("settings", phrase.getSettings().toJSON()); json.put("settings", phrase.getSettings().toJSON());
json.put("phrase", phrase.getRawUnknownSearchPhrase()); json.put("phrase", phrase.getFullSearchPhrase());
if (searchResult.searchResults != null && searchResult.searchResults.size() > 0) { if (searchResult.searchResults != null && searchResult.searchResults.size() > 0) {
JSONArray resultsArr = new JSONArray(); JSONArray resultsArr = new JSONArray();
for (SearchResult r : searchResult.searchResults) { for (SearchResult r : searchResult.searchResults) {
@ -963,14 +963,12 @@ public class SearchUICore {
} }
public static class SearchResultComparator implements Comparator<SearchResult> { public static class SearchResultComparator implements Comparator<SearchResult> {
private SearchPhrase sp;
private Collator collator; private Collator collator;
private LatLon loc; private LatLon loc;
private boolean sortByName; private boolean sortByName;
public SearchResultComparator(SearchPhrase sp) { public SearchResultComparator(SearchPhrase sp) {
this.sp = sp;
this.collator = sp.getCollator(); this.collator = sp.getCollator();
loc = sp.getLastTokenLocation(); loc = sp.getLastTokenLocation();
sortByName = sp.isSortByName(); sortByName = sp.isSortByName();

View file

@ -140,20 +140,18 @@ public class SearchCoreFactory {
return 0; return 0;
} }
protected void subSearchApiOrPublish(SearchPhrase phrase, protected void subSearchApiOrPublish(SearchPhrase phrase, SearchResultMatcher resultMatcher, SearchResult res, SearchBaseAPI api)
SearchResultMatcher resultMatcher, SearchResult res, SearchBaseAPI api)
throws IOException { throws IOException {
phrase.countUnknownWordsMatch(res); phrase.countUnknownWordsMatchMainResult(res);
// int cnt = resultMatcher.getCount(); // TODO select word & delete found words
List<String> ws = phrase.getUnknownSearchWords(res.otherWordsMatch); List<String> ws = phrase.getUnknownSearchWords(res.otherWordsMatch);
if (!res.firstUnknownWordMatches) { if (!res.firstUnknownWordMatches) {
ws.add(phrase.getUnknownSearchWord()); ws.add(phrase.getFirstUnknownSearchWord());
} }
// publish result to set parentSearchResult before search // publish result to set parentSearchResult before search
resultMatcher.publish(res); resultMatcher.publish(res);
if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) { if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) {
SearchPhrase nphrase = phrase.selectWord(res, ws, SearchPhrase nphrase = phrase.selectWord(res, ws, phrase.isLastUnknownSearchWordComplete());
phrase.isLastUnknownSearchWordComplete());
resultMatcher.setParentSearchResult(res); resultMatcher.setParentSearchResult(res);
api.search(nphrase, resultMatcher); api.search(nphrase, resultMatcher);
resultMatcher.setParentSearchResult(res.parentSearchResult); resultMatcher.setParentSearchResult(res.parentSearchResult);
@ -166,8 +164,6 @@ public class SearchCoreFactory {
} }
} }
public static class SearchRegionByNameAPI extends SearchBaseAPI { public static class SearchRegionByNameAPI extends SearchBaseAPI {
public SearchRegionByNameAPI() { public SearchRegionByNameAPI() {
@ -186,9 +182,9 @@ public class SearchCoreFactory {
sr.objectType = ObjectType.REGION; sr.objectType = ObjectType.REGION;
sr.location = bmir.getRegionCenter(); sr.location = bmir.getRegionCenter();
sr.preferredZoom = 6; sr.preferredZoom = 6;
if (phrase.getUnknownSearchWordLength() <= 1 && phrase.isNoSelectedType()) { if (phrase.getFirstUnknownSearchWord().length() <= 1 && phrase.isNoSelectedType()) {
resultMatcher.publish(sr); resultMatcher.publish(sr);
} else if (phrase.getNameStringMatcher().matches(sr.localeName)) { } else if (phrase.getFirstUnknownNameStringMatcher().matches(sr.localeName)) {
resultMatcher.publish(sr); resultMatcher.publish(sr);
} }
} }
@ -210,19 +206,6 @@ public class SearchCoreFactory {
} }
} }
private static String stripBraces(String localeName) {
int i = localeName.indexOf('(');
String retName = localeName;
if (i > -1) {
retName = localeName.substring(0, i);
int j = localeName.indexOf(')', i);
if (j > -1) {
retName = retName.trim() + ' ' + localeName.substring(j);
}
}
return retName;
}
public static class SearchAddressByNameAPI extends SearchBaseAPI { public static class SearchAddressByNameAPI extends SearchBaseAPI {
private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000; private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000;
@ -310,10 +293,7 @@ public class SearchCoreFactory {
if (phrase.isNoSelectedType() && bbox != null if (phrase.isNoSelectedType() && bbox != null
&& (phrase.isUnknownSearchWordPresent() || phrase.isEmptyQueryAllowed()) && (phrase.isUnknownSearchWordPresent() || phrase.isEmptyQueryAllowed())
&& phrase.isSearchTypeAllowed(ObjectType.CITY)) { && phrase.isSearchTypeAllowed(ObjectType.CITY)) {
String word = phrase.getUnknownWordToSearch(); NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
NameStringMatcher nm = phrase.getNameStringMatcher(word, phrase.isUnknownSearchWordComplete());
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(word, true);
boolean firstUnknownWordMatches = word.equals(phrase.getUnknownSearchWord());
resArray.clear(); resArray.clear();
resArray = townCitiesQR.queryInBox(bbox, resArray); resArray = townCitiesQR.queryInBox(bbox, resArray);
int limit = 0; int limit = 0;
@ -335,8 +315,6 @@ public class SearchCoreFactory {
if (phrase.isEmptyQueryAllowed() && phrase.isEmpty()) { if (phrase.isEmptyQueryAllowed() && phrase.isEmpty()) {
resultMatcher.publish(res); resultMatcher.publish(res);
} else if (nm.matches(res.localeName) || nm.matches(res.otherNames)) { } else if (nm.matches(res.localeName) || nm.matches(res.otherNames)) {
res.firstUnknownWordMatches = firstUnknownWordMatches;
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
subSearchApiOrPublish(phrase, resultMatcher, res, cityApi); subSearchApiOrPublish(phrase, resultMatcher, res, cityApi);
} }
if (limit++ > LIMIT * phrase.getRadiusLevel()) { if (limit++ > LIMIT * phrase.getRadiusLevel()) {
@ -348,7 +326,8 @@ public class SearchCoreFactory {
private void searchByName(final SearchPhrase phrase, final SearchResultMatcher resultMatcher) private void searchByName(final SearchPhrase phrase, final SearchResultMatcher resultMatcher)
throws IOException { throws IOException {
if (phrase.getRadiusLevel() > 1 || phrase.getUnknownSearchWordLength() > 3 || phrase.getUnknownSearchWords().size() > 0 || phrase.isSearchTypeAllowed(ObjectType.POSTCODE, true)) { if (phrase.getRadiusLevel() > 1 || phrase.getUnknownWordToSearch().length() > 3 ||
phrase.hasMoreThanOneUnknownSearchWord()|| phrase.isSearchTypeAllowed(ObjectType.POSTCODE, true)) {
final boolean locSpecified = phrase.getLastTokenLocation() != null; final boolean locSpecified = phrase.getLastTokenLocation() != null;
LatLon loc = phrase.getLastTokenLocation(); LatLon loc = phrase.getLastTokenLocation();
final List<SearchResult> immediateResults = new ArrayList<>(); final List<SearchResult> immediateResults = new ArrayList<>();
@ -391,7 +370,7 @@ public class SearchCoreFactory {
if (object.getName().startsWith("<")) { if (object.getName().startsWith("<")) {
return false; return false;
} }
if (!phrase.getNameStringMatcher().matches(stripBraces(sr.localeName))) { if (!phrase.getFirstUnknownNameStringMatcher().matches(stripBraces(sr.localeName))) {
sr.priorityDistance = 5; sr.priorityDistance = 5;
} }
sr.objectType = ObjectType.STREET; sr.objectType = ObjectType.STREET;
@ -460,16 +439,13 @@ public class SearchCoreFactory {
}; };
Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(DEFAULT_ADDRESS_BBOX_RADIUS * 5, Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(DEFAULT_ADDRESS_BBOX_RADIUS * 5,
SearchPhraseDataType.ADDRESS); SearchPhraseDataType.ADDRESS);
String wordToSearch = phrase.getUnknownWordToSearch(); String wordToSearch = phrase.getUnknownWordToSearch();
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(wordToSearch, true);
boolean firstUnknownWordMatches = wordToSearch.equals(phrase.getUnknownSearchWord());
while (offlineIterator.hasNext() && wordToSearch.length() > 0) { while (offlineIterator.hasNext() && wordToSearch.length() > 0) {
BinaryMapIndexReader r = offlineIterator.next(); BinaryMapIndexReader r = offlineIterator.next();
currentFile[0] = r; currentFile[0] = r;
immediateResults.clear(); immediateResults.clear();
SearchRequest<MapObject> req = BinaryMapIndexReader.buildAddressByNameRequest(rm, wordToSearch.toLowerCase(), SearchRequest<MapObject> req = BinaryMapIndexReader.buildAddressByNameRequest(rm, wordToSearch.toLowerCase(),
phrase.isUnknownSearchWordComplete() ? StringMatcherMode.CHECK_EQUALS_FROM_SPACE phrase.isMainUnknownSearchWordComplete() ? StringMatcherMode.CHECK_EQUALS_FROM_SPACE
: StringMatcherMode.CHECK_STARTS_FROM_SPACE); : StringMatcherMode.CHECK_STARTS_FROM_SPACE);
if (locSpecified) { if (locSpecified) {
req.setBBoxRadius(loc.getLatitude(), loc.getLongitude(), req.setBBoxRadius(loc.getLatitude(), loc.getLongitude(),
@ -477,8 +453,6 @@ public class SearchCoreFactory {
} }
r.searchAddressDataByName(req); r.searchAddressDataByName(req);
for (SearchResult res : immediateResults) { for (SearchResult res : immediateResults) {
res.firstUnknownWordMatches = firstUnknownWordMatches;
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
if (res.objectType == ObjectType.STREET) { if (res.objectType == ObjectType.STREET) {
City ct = ((Street) res.object).getCity(); City ct = ((Street) res.object).getCity();
phrase.countUnknownWordsMatch(res, phrase.countUnknownWordsMatch(res,
@ -510,29 +484,28 @@ public class SearchCoreFactory {
if (!phrase.isUnknownSearchWordPresent()) { if (!phrase.isUnknownSearchWordPresent()) {
return false; return false;
} }
boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent() // TODO
&& phrase.isUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes(); // consider 'bar' - 'Hospital 512'
if (!phrase.isNoSelectedType()) {
// don't search by name when type is selected or poi type is part of name
return false;
}
// boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent()
// && phrase.isMainUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes();
// Check feedback before it was searching exact match of whole phrase.getUnknownSearchPhrase()
final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1]; final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1];
Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(BBOX_RADIUS, Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(BBOX_RADIUS,
SearchPhraseDataType.POI); SearchPhraseDataType.POI);
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim(); String searchWord = phrase.getUnknownWordToSearch();
String searchWord = hasUnselectedType ? unknownSearchPhrase : phrase.getUnknownWordToSearch(); final NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
final NameStringMatcher nm = phrase.getNameStringMatcher(searchWord, phrase.isUnknownSearchWordComplete());
final NameStringMatcher phraseMatcher;
if (!Algorithms.isEmpty(unknownSearchPhrase)) {
phraseMatcher = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_EQUALS);
} else {
phraseMatcher = null;
}
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS_INSIDE); QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS_INSIDE);
final Set<String> ids = new HashSet<String>(); final Set<String> ids = new HashSet<String>();
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest( SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest((int) bbox.centerX(),
(int)bbox.centerX(), (int)bbox.centerY(), (int) bbox.centerY(), searchWord, (int) bbox.left, (int) bbox.right, (int) bbox.top,
searchWord, (int) bbox.bottom, new ResultMatcher<Amenity>() {
(int)bbox.left, (int)bbox.right,
(int)bbox.top, (int)bbox.bottom,
new ResultMatcher<Amenity>() {
int limit = 0; int limit = 0;
@Override @Override
public boolean publish(Amenity object) { public boolean publish(Amenity object) {
if (phrase.getSettings().isExportObjects()) { if (phrase.getSettings().isExportObjects()) {
@ -547,19 +520,17 @@ public class SearchCoreFactory {
} }
SearchResult sr = new SearchResult(phrase); SearchResult sr = new SearchResult(phrase);
sr.otherNames = object.getAllNames(true); sr.otherNames = object.getAllNames(true);
sr.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); sr.localeName = object.getName(phrase.getSettings().getLang(),
if (phrase.isUnknownSearchWordComplete()) { phrase.getSettings().isTransliterate());
if(!nm.matches(sr.localeName) && !nm.matches(sr.otherNames) && if (!nm.matches(sr.localeName) && !nm.matches(sr.otherNames)
!nm.matches(object.getAdditionalInfo().values())) { && !nm.matches(object.getAdditionalInfo().values())) {
return false; return false;
} }
}
sr.object = object; sr.object = object;
sr.preferredZoom = 17; sr.preferredZoom = 17;
sr.file = currentFile[0]; sr.file = currentFile[0];
sr.location = object.getLocation(); sr.location = object.getLocation();
if (object.getSubType().equals("city") || if (object.getSubType().equals("city") || object.getSubType().equals("country")) {
object.getSubType().equals("country")) {
sr.priorityDistance = SEARCH_AMENITY_BY_NAME_CITY_PRIORITY_DISTANCE; sr.priorityDistance = SEARCH_AMENITY_BY_NAME_CITY_PRIORITY_DISTANCE;
sr.preferredZoom = object.getSubType().equals("country") ? 7 : 13; sr.preferredZoom = object.getSubType().equals("country") ? 7 : 13;
} else if (object.getSubType().equals("town")) { } else if (object.getSubType().equals("town")) {
@ -568,10 +539,7 @@ public class SearchCoreFactory {
sr.priorityDistance = 1; sr.priorityDistance = 1;
} }
sr.priority = SEARCH_AMENITY_BY_NAME_PRIORITY; sr.priority = SEARCH_AMENITY_BY_NAME_PRIORITY;
if (phraseMatcher != null) { phrase.countUnknownWordsMatchMainResult(sr);
sr.unknownPhraseMatches = phraseMatcher.matches(sr.localeName);
}
phrase.countUnknownWordsMatch(sr);
sr.objectType = ObjectType.POI; sr.objectType = ObjectType.POI;
resultMatcher.publish(sr); resultMatcher.publish(sr);
ids.add(poiID); ids.add(poiID);
@ -633,9 +601,8 @@ public class SearchCoreFactory {
private List<AbstractPoiType> topVisibleFilters; private List<AbstractPoiType> topVisibleFilters;
private List<PoiCategory> categories; private List<PoiCategory> categories;
private List<CustomSearchPoiFilter> customPoiFilters = new ArrayList<>(); private List<CustomSearchPoiFilter> customPoiFilters = new ArrayList<>();
private TIntArrayList customPoiFiltersPriorites = new TIntArrayList(); private Map<String, Integer> activePoiFilters = new HashMap<>();
private MapPoiTypes types; private MapPoiTypes types;
private List<String> filterOrders = new ArrayList<>();
public SearchAmenityTypesAPI(MapPoiTypes types) { public SearchAmenityTypesAPI(MapPoiTypes types) {
super(ObjectType.POI_TYPE); super(ObjectType.POI_TYPE);
@ -644,52 +611,33 @@ public class SearchCoreFactory {
public void clearCustomFilters() { public void clearCustomFilters() {
this.customPoiFilters.clear(); this.customPoiFilters.clear();
this.customPoiFiltersPriorites.clear();
} }
public void addCustomFilter(CustomSearchPoiFilter poiFilter, int priority) { public void addCustomFilter(CustomSearchPoiFilter poiFilter, int priority) {
this.customPoiFilters.add(poiFilter); this.customPoiFilters.add(poiFilter);
this.customPoiFiltersPriorites.add(priority); if (priority > 0) {
this.activePoiFilters.put(poiFilter.getFilterId(), priority);
}
} }
public void setFilterOrders(List<String> filterOrders) { public void setActivePoiFiltersByOrder(List<String> filterOrder) {
this.filterOrders = filterOrders; for (int i = 0; i < filterOrder.size(); i++) {
this.activePoiFilters.put(filterOrder.get(i), i);
}
} }
@Override public List<AbstractPoiType> getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) {
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
if (translatedNames.isEmpty()) {
translatedNames = types.getAllTranslatedNames(false);
topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
}
List<AbstractPoiType> results = new ArrayList<AbstractPoiType>(); List<AbstractPoiType> results = new ArrayList<AbstractPoiType>();
List<AbstractPoiType> searchWordTypes = new ArrayList<AbstractPoiType>();
NameStringMatcher nm;
String unknownSearchPhrase = phrase.getUnknownSearchPhrase();
boolean showTopFiltersOnly = !phrase.isUnknownSearchWordPresent();
if (phrase.getUnknownSearchWord().length() < unknownSearchPhrase.length()) {
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_ONLY_STARTS_WITH_TRIM);
} else {
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
}
for (AbstractPoiType pf : topVisibleFilters) { for (AbstractPoiType pf : topVisibleFilters) {
if (showTopFiltersOnly if (nm.matches(pf.getTranslation()) || nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getTranslation())
|| nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getSynonyms())) { || nm.matches(pf.getSynonyms())) {
results.add(pf); results.add(pf);
searchWordTypes.add(pf);
} }
} }
if (!showTopFiltersOnly) {
for (PoiCategory c : categories) { for (PoiCategory c : categories) {
if (!results.contains(c) if (!results.contains(c) && (nm.matches(c.getTranslation()) || nm.matches(c.getEnTranslation())
&& (nm.matches(c.getTranslation())
|| nm.matches(c.getEnTranslation())
|| nm.matches(c.getSynonyms()))) { || nm.matches(c.getSynonyms()))) {
results.add(c); results.add(c);
searchWordTypes.add(c);
} }
} }
Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator(); Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator();
@ -697,20 +645,18 @@ public class SearchCoreFactory {
Entry<String, PoiType> e = it.next(); Entry<String, PoiType> e = it.next();
PoiType pt = e.getValue(); PoiType pt = e.getValue();
if (pt.getCategory() != types.getOtherMapCategory()) { if (pt.getCategory() != types.getOtherMapCategory()) {
if (!results.contains(pt) if (!results.contains(pt) && (nm.matches(pt.getEnTranslation()) || nm.matches(pt.getTranslation())
&& (nm.matches(pt.getEnTranslation())
|| nm.matches(pt.getTranslation())
|| nm.matches(pt.getSynonyms()))) { || nm.matches(pt.getSynonyms()))) {
results.add(pt); results.add(pt);
searchWordTypes.add(pt);
} }
List<PoiType> additionals = pt.getPoiAdditionals(); List<PoiType> additionals = pt.getPoiAdditionals();
if (additionals != null) { if (additionals != null && includeAdditionals) {
for (PoiType a : additionals) { for (PoiType a : additionals) {
if (!results.contains(a)) { if (!results.contains(a)) {
String enTranslation = a.getEnTranslation().toLowerCase(); String enTranslation = a.getEnTranslation().toLowerCase();
if (!"yes".equals(enTranslation) && !"no".equals(enTranslation) if (!"yes".equals(enTranslation) && !"no".equals(enTranslation)
&& (nm.matches(enTranslation) || nm.matches(a.getTranslation()) || nm.matches(a.getSynonyms()))) { && (nm.matches(enTranslation) || nm.matches(a.getTranslation())
|| nm.matches(a.getSynonyms()))) {
results.add(a); results.add(a);
} }
} }
@ -718,52 +664,70 @@ public class SearchCoreFactory {
} }
} }
} }
return results;
} }
phrase.setUnknownSearchWordPoiTypes(searchWordTypes);
if (resultMatcher != null) { private void initPoiTypes() {
String word = phrase.getUnknownSearchWord(); if (translatedNames.isEmpty()) {
NameStringMatcher startMatch = new NameStringMatcher(word, StringMatcherMode.CHECK_ONLY_STARTS_WITH); translatedNames = types.getAllTranslatedNames(false);
for (AbstractPoiType pt : results) { topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
}
}
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
boolean showTopFiltersOnly = !phrase.isUnknownSearchWordPresent();
NameStringMatcher nm = phrase.getFullUnknownNameMatcher();
initPoiTypes();
List<AbstractPoiType> poiTypes = topVisibleFilters;
if (!showTopFiltersOnly) {
poiTypes = getPoiTypeResults(nm, true);
}
for (AbstractPoiType pt : poiTypes) {
SearchResult res = new SearchResult(phrase); SearchResult res = new SearchResult(phrase);
res.localeName = pt.getTranslation(); res.localeName = pt.getTranslation();
res.object = pt; res.object = pt;
res.priorityDistance = 0; addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(pt), res);
res.objectType = ObjectType.POI_TYPE;
res.firstUnknownWordMatches = startMatch.matches(res.localeName);
if (showTopFiltersOnly) {
String stdFilterId = getStandardFilterId(pt);
if (filterOrders.contains(stdFilterId)) {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY + filterOrders.indexOf(stdFilterId);
resultMatcher.publish(res);
}
} else {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY;
resultMatcher.publish(res);
}
} }
for (int i = 0; i < customPoiFilters.size(); i++) { for (int i = 0; i < customPoiFilters.size(); i++) {
CustomSearchPoiFilter csf = customPoiFilters.get(i); CustomSearchPoiFilter csf = customPoiFilters.get(i);
if (!phrase.isUnknownSearchWordPresent() || nm.matches(csf.getName())) { if (showTopFiltersOnly || nm.matches(csf.getName())) {
SearchResult res = new SearchResult(phrase); SearchResult res = new SearchResult(phrase);
res.localeName = csf.getName(); res.localeName = csf.getName();
res.object = csf; res.object = csf;
res.objectType = ObjectType.POI_TYPE; addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, csf.getFilterId(), res);
if (showTopFiltersOnly) {
if (filterOrders.contains(csf.getFilterId())) {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY + filterOrders.indexOf(csf.getFilterId());
resultMatcher.publish(res);
}
} else {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY + customPoiFiltersPriorites.get(i);
resultMatcher.publish(res);
}
}
} }
} }
return true; return true;
} }
private void addPoiTypeResult(SearchPhrase phrase, SearchResultMatcher resultMatcher, boolean showTopFiltersOnly,
String stdFilterId , SearchResult res) {
res.priorityDistance = 0;
res.objectType = ObjectType.POI_TYPE;
if (showTopFiltersOnly) {
if (activePoiFilters.containsKey(stdFilterId)) {
res.priority = getPoiTypePriority(stdFilterId);
resultMatcher.publish(res);
}
} else {
phrase.countUnknownWordsMatchMainResult(res);
res.priority = SEARCH_AMENITY_TYPE_PRIORITY;
resultMatcher.publish(res);
}
}
private int getPoiTypePriority(String stdFilterId) {
Integer i = activePoiFilters.get(stdFilterId);
if ( i == null) {
return SEARCH_AMENITY_TYPE_PRIORITY;
}
return SEARCH_AMENITY_TYPE_PRIORITY + i.intValue();
}
public String getStandardFilterId(AbstractPoiType poi) { public String getStandardFilterId(AbstractPoiType poi) {
return STD_POI_FILTER_PREFIX + poi.getKeyName(); return STD_POI_FILTER_PREFIX + poi.getKeyName();
} }
@ -842,68 +806,67 @@ public class SearchCoreFactory {
@Override @Override
public boolean search(final SearchPhrase phrase, final SearchResultMatcher resultMatcher) throws IOException { public boolean search(final SearchPhrase phrase, final SearchResultMatcher resultMatcher) throws IOException {
SearchPoiTypeFilter poiTypeFilter = null;
String nameFilter = null;
if (phrase.isLastWord(ObjectType.POI_TYPE)) { if (phrase.isLastWord(ObjectType.POI_TYPE)) {
Object obj = phrase.getLastSelectedWord().getResult().object; Object obj = phrase.getLastSelectedWord().getResult().object;
SearchPoiTypeFilter ptf;
if (obj instanceof AbstractPoiType) { if (obj instanceof AbstractPoiType) {
ptf = getPoiTypeFilter((AbstractPoiType) obj); poiTypeFilter = getPoiTypeFilter((AbstractPoiType) obj);
} else if (obj instanceof SearchPoiTypeFilter) { } else if (obj instanceof SearchPoiTypeFilter) {
ptf = (SearchPoiTypeFilter) obj; poiTypeFilter = (SearchPoiTypeFilter) obj;
} else { } else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
searchPoi(phrase, resultMatcher, obj, null, ptf);
} else if (searchAmenityTypesAPI != null) { } else if (searchAmenityTypesAPI != null) {
if (phrase.getUnknownSearchWordPoiTypes() == null) { NameStringMatcher nm = phrase.getFullUnknownNameMatcher();
searchAmenityTypesAPI.search(phrase, null); searchAmenityTypesAPI.initPoiTypes();
} List<AbstractPoiType> presentPoiTypes = searchAmenityTypesAPI.getPoiTypeResults(nm, false);
// TODO get first ?
AbstractPoiType poiType = phrase.getUnknownSearchWordPoiType(); AbstractPoiType poiType = phrase.getUnknownSearchWordPoiType();
if (poiType != null) { if (poiType != null) {
SearchPoiTypeFilter ptf = getPoiTypeFilter(poiType); poiTypeFilter = getPoiTypeFilter(poiType);
String customName = phrase.getPoiNameFilter(poiType); nameFilter = phrase.getPoiNameFilter(poiType);
if (customName != null) { if (nameFilter != null) {
phrase.setUnknownSearchWordPoiType(poiType); phrase.setUnknownSearchWordPoiType(poiType);
searchPoi(phrase, resultMatcher, null, customName.length() == 0 ? null : customName, ptf);
} }
} }
} }
if (poiTypeFilter != null) {
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS);
List<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes();
Set<String> searchedPois = new TreeSet<>();
for (BinaryMapIndexReader r : offlineIndexes) {
ResultMatcher<Amenity> rm = getResultMatcher(phrase, resultMatcher, nameFilter, r, searchedPois);
if (poiTypeFilter instanceof CustomSearchPoiFilter) {
rm = ((CustomSearchPoiFilter) poiTypeFilter).wrapResultMatcher(rm);
}
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest((int) bbox.left,
(int) bbox.right, (int) bbox.top, (int) bbox.bottom, -1, poiTypeFilter, rm);
r.searchPoi(req);
resultMatcher.apiSearchRegionFinished(this, r, phrase);
}
}
return true; return true;
} }
private void searchPoi(SearchPhrase phrase, SearchResultMatcher resultMatcher, Object obj, String customName, SearchPoiTypeFilter ptf) throws IOException {
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS);
List<BinaryMapIndexReader> oo = phrase.getOfflineIndexes();
Set<String> searchedPois = new TreeSet<>();
for (BinaryMapIndexReader o : oo) {
ResultMatcher<Amenity> rm = getResultMatcher(phrase, resultMatcher, customName, o, searchedPois);
if (obj instanceof CustomSearchPoiFilter) {
rm = ((CustomSearchPoiFilter) obj).wrapResultMatcher(rm);
}
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
(int) bbox.left, (int) bbox.right,
(int) bbox.top, (int) bbox.bottom, -1, ptf,
rm);
o.searchPoi(req);
resultMatcher.apiSearchRegionFinished(this, o, phrase);
}
}
private ResultMatcher<Amenity> getResultMatcher(final SearchPhrase phrase, final SearchResultMatcher resultMatcher, private ResultMatcher<Amenity> getResultMatcher(final SearchPhrase phrase, final SearchResultMatcher resultMatcher,
final String customName, final BinaryMapIndexReader selected, final String nameFilter, final BinaryMapIndexReader selected,
final Set<String> searchedPois) { final Set<String> searchedPois) {
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim(); // TODO
final NameStringMatcher phraseMatcher; // String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim();
if (!Algorithms.isEmpty(unknownSearchPhrase)) { // final NameStringMatcher phraseMatcher;
phraseMatcher = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_EQUALS); // if (!Algorithms.isEmpty(unknownSearchPhrase)) {
} else { // phraseMatcher = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_EQUALS);
phraseMatcher = null; // } else {
} // phraseMatcher = null;
// }
final NameStringMatcher ns; final NameStringMatcher ns;
final boolean hasCustomName = !Algorithms.isEmpty(customName); final boolean hasCustomName = !Algorithms.isEmpty(nameFilter);
if (hasCustomName) { if (hasCustomName) {
ns = phrase.getNameStringMatcher(customName, phrase.isLastUnknownSearchWordComplete()); ns = phrase.getNameStringMatcher(nameFilter, phrase.isLastUnknownSearchWordComplete());
} else { } else {
ns = phrase.getNameStringMatcher(); ns = phrase.getFirstUnknownNameStringMatcher();
} }
return new ResultMatcher<Amenity>() { return new ResultMatcher<Amenity>() {
@ -930,15 +893,19 @@ public class SearchCoreFactory {
res.localeName = object.getSubType(); res.localeName = object.getSubType();
} }
} }
if (phrase.isUnknownSearchWordPresent() if (phrase.isUnknownSearchWordPresent()) {
&& !(ns.matches(res.localeName) || ns.matches(res.otherNames))) { if (ns.matches(res.localeName) || ns.matches(res.otherNames)) {
phrase.countUnknownWordsMatchMainResult(res);
} else {
String ref = object.getTagContent(Amenity.REF, null); String ref = object.getTagContent(Amenity.REF, null);
if (ref == null || !ns.matches(ref)) { if (ref == null || !ns.matches(ref)) {
return false; return false;
} else { } else {
phrase.countUnknownWordsMatch(res, ref, null);
res.localeName += " " + ref; res.localeName += " " + ref;
} }
} }
}
res.object = object; res.object = object;
res.preferredZoom = 17; res.preferredZoom = 17;
@ -946,6 +913,7 @@ public class SearchCoreFactory {
res.location = object.getLocation(); res.location = object.getLocation();
res.priority = SEARCH_AMENITY_BY_TYPE_PRIORITY; res.priority = SEARCH_AMENITY_BY_TYPE_PRIORITY;
res.priorityDistance = 1; res.priorityDistance = 1;
if (phraseMatcher != null) { if (phraseMatcher != null) {
boolean unknownPhraseMatches = phraseMatcher.matches(res.localeName); boolean unknownPhraseMatches = phraseMatcher.matches(res.localeName);
AbstractPoiType unknownSearchWordPoiType = phrase.getUnknownSearchWordPoiType(); AbstractPoiType unknownSearchWordPoiType = phrase.getUnknownSearchWordPoiType();
@ -969,7 +937,6 @@ public class SearchCoreFactory {
} }
private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt) { private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt) {
acceptedTypes.clear(); acceptedTypes.clear();
poiAdditionals.clear(); poiAdditionals.clear();
updateTypesToAccept(pt); updateTypesToAccept(pt);
@ -1045,16 +1012,8 @@ public class SearchCoreFactory {
sw.getResult().file.preloadStreets(c, null); sw.getResult().file.preloadStreets(c, null);
} }
int limit = 0; int limit = 0;
String wordToSearch = phrase.getUnknownWordToSearch(); NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
boolean firstUnknownWordMatches = wordToSearch.equals(phrase.getUnknownSearchWord());
NameStringMatcher nm = phrase.getNameStringMatcher(wordToSearch, phrase.isUnknownSearchWordComplete());
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim();
NameStringMatcher phraseMatcher = null;
if (!Algorithms.isEmpty(unknownSearchPhrase)) {
phraseMatcher = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_EQUALS);
}
for (Street object : c.getStreets()) { for (Street object : c.getStreets()) {
SearchResult res = new SearchResult(phrase); SearchResult res = new SearchResult(phrase);
res.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
@ -1067,12 +1026,6 @@ public class SearchCoreFactory {
&& !(nm.matches(res.localeName) || nm.matches(res.otherNames))) { && !(nm.matches(res.localeName) || nm.matches(res.otherNames))) {
continue; continue;
} }
res.firstUnknownWordMatches = firstUnknownWordMatches ||
phrase.getNameStringMatcher().matches(res.localeName) ||
phrase.getNameStringMatcher().matches(res.otherNames);
if (phraseMatcher != null) {
res.unknownPhraseMatches = phraseMatcher.matches(res.localeName);
}
res.localeRelatedObjectName = c.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.localeRelatedObjectName = c.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
res.object = object; res.object = object;
res.preferredZoom = 17; res.preferredZoom = 17;
@ -1102,11 +1055,6 @@ public class SearchCoreFactory {
} }
public static boolean isLastWordCityGroup(SearchPhrase p ) {
return p.isLastWord(ObjectType.CITY) || p.isLastWord(ObjectType.POSTCODE) ||
p.isLastWord(ObjectType.VILLAGE);
}
public static class SearchBuildingAndIntersectionsByStreetAPI extends SearchBaseAPI { public static class SearchBuildingAndIntersectionsByStreetAPI extends SearchBaseAPI {
Street cacheBuilding; Street cacheBuilding;
@ -1179,7 +1127,7 @@ public class SearchCoreFactory {
}); });
} }
String lw = phrase.getUnknownWordToSearchBuilding(); String lw = phrase.getUnknownWordToSearchBuilding();
NameStringMatcher buildingMatch = phrase.getNameStringMatcher(lw, phrase.isLastUnknownSearchWordComplete()); NameStringMatcher buildingMatch = phrase.getUnknownWordToSearchBuildingNameMatcher();
NameStringMatcher startMatch = new NameStringMatcher(lw, StringMatcherMode.CHECK_ONLY_STARTS_WITH); NameStringMatcher startMatch = new NameStringMatcher(lw, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
for (Building b : s.getBuildings()) { for (Building b : s.getBuildings()) {
SearchResult res = new SearchResult(phrase); SearchResult res = new SearchResult(phrase);
@ -1194,6 +1142,7 @@ public class SearchCoreFactory {
res.file = file; res.file = file;
res.priority = priority; res.priority = priority;
res.priorityDistance = 0; res.priorityDistance = 0;
// TOOO phrase.countUnknownWordsMatchMainResult(res);
res.firstUnknownWordMatches = startMatch.matches(res.localeName); res.firstUnknownWordMatches = startMatch.matches(res.localeName);
res.relatedObject = s; res.relatedObject = s;
res.localeRelatedObjectName = s.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.localeRelatedObjectName = s.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
@ -1208,7 +1157,7 @@ public class SearchCoreFactory {
resultMatcher.publish(res); resultMatcher.publish(res);
} }
String streetIntersection = phrase.getUnknownWordToSearch(); String streetIntersection = phrase.getUnknownWordToSearch();
NameStringMatcher streetMatch = phrase.getNameStringMatcher(streetIntersection, phrase.isLastUnknownSearchWordComplete()); NameStringMatcher streetMatch = phrase.getMainUnknownNameStringMatcher();
if (Algorithms.isEmpty(streetIntersection) || if (Algorithms.isEmpty(streetIntersection) ||
(!Character.isDigit(streetIntersection.charAt(0)) && (!Character.isDigit(streetIntersection.charAt(0)) &&
CommonWords.getCommonSearch(streetIntersection) == -1) ) { CommonWords.getCommonSearch(streetIntersection) == -1) ) {
@ -1218,6 +1167,7 @@ public class SearchCoreFactory {
|| !phrase.isSearchTypeAllowed(ObjectType.STREET_INTERSECTION)) { || !phrase.isSearchTypeAllowed(ObjectType.STREET_INTERSECTION)) {
continue; continue;
} }
// TOOO phrase.countUnknownWordsMatchMainResult(res);
res.otherNames = street.getAllNames(true); res.otherNames = street.getAllNames(true);
res.localeName = street.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.localeName = street.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
res.object = street; res.object = street;
@ -1404,4 +1354,22 @@ public class SearchCoreFactory {
return cachedParsedCode == null ? SEARCH_LOCATION_PRIORITY : SEARCH_MAX_PRIORITY; return cachedParsedCode == null ? SEARCH_LOCATION_PRIORITY : SEARCH_MAX_PRIORITY;
} }
} }
private static String stripBraces(String localeName) {
int i = localeName.indexOf('(');
String retName = localeName;
if (i > -1) {
retName = localeName.substring(0, i);
int j = localeName.indexOf(')', i);
if (j > -1) {
retName = retName.trim() + ' ' + localeName.substring(j);
}
}
return retName;
}
public static boolean isLastWordCityGroup(SearchPhrase p ) {
return p.isLastWord(ObjectType.CITY) || p.isLastWord(ObjectType.POSTCODE) ||
p.isLastWord(ObjectType.VILLAGE);
}
} }

View file

@ -1,7 +1,7 @@
package net.osmand.search.core; package net.osmand.search.core;
import net.osmand.Collator; import net.osmand.Collator;
import net.osmand.CollatorStringMatcher; import net.osmand.CollatorStringMatcher;import net.osmand.OsmAndCollator;
import net.osmand.CollatorStringMatcher.StringMatcherMode; import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.StringMatcher; import net.osmand.StringMatcher;
import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader;
@ -10,6 +10,7 @@ import net.osmand.binary.CommonWords;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.data.QuadRect; import net.osmand.data.QuadRect;
import net.osmand.osm.AbstractPoiType; import net.osmand.osm.AbstractPoiType;
import net.osmand.search.core.SearchPhrase.NameStringMatcher;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import net.osmand.util.LocationParser; import net.osmand.util.LocationParser;
import net.osmand.util.MapUtils; import net.osmand.util.MapUtils;
@ -27,31 +28,39 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.regex.Pattern; import java.util.regex.Pattern;
//immutable object // Immutable object !
public class SearchPhrase { public class SearchPhrase {
private List<SearchWord> words = new ArrayList<>();
private List<String> unknownWords = new ArrayList<>();
private List<NameStringMatcher> unknownWordsMatcher = new ArrayList<>();
private String unknownSearchWordTrim;
private String rawUnknownSearchPhrase = "";
private String unknownSearchPhrase = "";
private AbstractPoiType unknownSearchWordPoiType;
private List<AbstractPoiType> unknownSearchWordPoiTypes = null;
private NameStringMatcher sm;
private SearchSettings settings;
private List<BinaryMapIndexReader> indexes;
private QuadRect cache1kmRect;
private boolean lastUnknownSearchWordComplete;
private static final String DELIMITER = " "; private static final String DELIMITER = " ";
private static final String ALLDELIMITERS = "\\s|,"; private static final String ALLDELIMITERS = "\\s|,";
private static final Pattern reg = Pattern.compile(ALLDELIMITERS); private static final Pattern reg = Pattern.compile(ALLDELIMITERS);
private Collator clt;
private static Comparator<String> commonWordsComparator; private static Comparator<String> commonWordsComparator;
private static Set<String> conjunctions = new TreeSet<>(); private static Set<String> conjunctions = new TreeSet<>();
private final Collator clt;
private final SearchSettings settings;
private List<BinaryMapIndexReader> indexes;
// Object consists of 2 part [known + unknown]
private String fullTextSearchPhrase = "";
private String unknownSearchPhrase = "";
// Words of 2 parts
private List<SearchWord> words = new ArrayList<>();
private String firstUnknownSearchWord = "";
private List<String> otherUnknownWords = new ArrayList<>();
private boolean lastUnknownSearchWordComplete;
// Main unknown word used for search
private String mainUnknownWordToSearch = null;
private boolean mainUnknownSearchWordComplete;
// Name Searchers
private NameStringMatcher firstUnknownNameStringMatcher;
private NameStringMatcher mainUnknownNameStringMatcher;
private List<NameStringMatcher> unknownWordsMatcher = new ArrayList<>();
private QuadRect cache1kmRect;
static { static {
// the // the
conjunctions.add("the"); conjunctions.add("the");
@ -140,7 +149,7 @@ public class SearchPhrase {
} }
public SearchPhrase(SearchSettings settings, Collator clt) { private SearchPhrase(SearchSettings settings, Collator clt) {
this.settings = settings; this.settings = settings;
this.clt = clt; this.clt = clt;
} }
@ -149,83 +158,160 @@ public class SearchPhrase {
return clt; return clt;
} }
public SearchPhrase generateNewPhrase(String text, SearchSettings settings) { public SearchPhrase generateNewPhrase(String text, SearchSettings settings) {
SearchPhrase sp = new SearchPhrase(settings, this.clt); String textToSearch = text;
String restText = text;
List<SearchWord> leftWords = this.words; List<SearchWord> leftWords = this.words;
String thisTxt = getText(true); String thisTxt = getText(true);
List<SearchWord> foundWords = new ArrayList<>();
if (text.startsWith(thisTxt)) { if (text.startsWith(thisTxt)) {
// string is longer // string is longer
restText = text.substring(getText(false).length()); textToSearch = text.substring(getText(false).length());
sp.words = new ArrayList<>(this.words); foundWords.addAll(this.words);
leftWords = leftWords.subList(leftWords.size(), leftWords.size()); leftWords = leftWords.subList(leftWords.size(), leftWords.size());
} }
for (SearchWord w : leftWords) { for (SearchWord w : leftWords) {
if(restText.startsWith(w.getWord() + DELIMITER)) { if (textToSearch.startsWith(w.getWord() + DELIMITER)) {
sp.words.add(w); foundWords.add(w);
restText = restText.substring(w.getWord().length() + DELIMITER.length()); textToSearch = textToSearch.substring(w.getWord().length() + DELIMITER.length());
} else { } else {
break; break;
} }
} }
sp.rawUnknownSearchPhrase = text; SearchPhrase sp = createNewSearchPhrase(settings, text, foundWords, textToSearch);
sp.unknownSearchPhrase = restText; return sp;
sp.unknownWords.clear(); }
sp.unknownWordsMatcher.clear();
if (!reg.matcher(restText).find()) {
sp.unknownSearchWordTrim = sp.unknownSearchPhrase.trim(); public static SearchPhrase emptyPhrase() {
return emptyPhrase(null);
}
public static SearchPhrase emptyPhrase(SearchSettings settings) {
return emptyPhrase(settings, OsmAndCollator.primaryCollator());
}
public static SearchPhrase emptyPhrase(SearchSettings settings, Collator clt) {
return new SearchPhrase(settings, clt);
}
// init search phrase
private SearchPhrase createNewSearchPhrase(SearchSettings settings, String fullText, List<SearchWord> foundWords,
String textToSearch) {
SearchPhrase sp = new SearchPhrase(settings, this.clt);
sp.words = foundWords;
sp.fullTextSearchPhrase = fullText;
sp.unknownSearchPhrase = textToSearch;
if (!reg.matcher(textToSearch).find()) {
sp.firstUnknownSearchWord = sp.unknownSearchPhrase.trim();
} else { } else {
sp.unknownSearchWordTrim = ""; sp.firstUnknownSearchWord = "";
String[] ws = restText.split(ALLDELIMITERS); String[] ws = textToSearch.split(ALLDELIMITERS);
boolean first = true; boolean first = true;
for (int i = 0; i < ws.length ; i++) { for (int i = 0; i < ws.length ; i++) {
String wd = ws[i].trim(); String wd = ws[i].trim();
if (wd.length() > 0 && !conjunctions.contains(wd.toLowerCase())) { if (wd.length() > 0 && !conjunctions.contains(wd.toLowerCase())) {
if (first) { if (first) {
sp.unknownSearchWordTrim = wd; sp.firstUnknownSearchWord = wd;
first = false; first = false;
} else { } else {
sp.unknownWords.add(wd); sp.otherUnknownWords.add(wd);
} }
} }
} }
} }
sp.lastUnknownSearchWordComplete = false; sp.lastUnknownSearchWordComplete = isTextComplete(fullText) ;
if (text.length() > 0 ) {
char ch = text.charAt(text.length() - 1);
sp.lastUnknownSearchWordComplete = ch == ' ' || ch == ',' || ch == '\r' || ch == '\n'
|| ch == ';';
}
return sp; return sp;
} }
public SearchPhrase selectWord(SearchResult res, List<String> unknownWords, boolean lastComplete) {
SearchPhrase sp = new SearchPhrase(this.settings, this.clt);
addResult(res, sp);
SearchResult prnt = res.parentSearchResult;
while (prnt != null) {
addResult(prnt, sp);
prnt = prnt.parentSearchResult;
}
sp.words.addAll(0, this.words);
if (unknownWords != null) {
sp.lastUnknownSearchWordComplete = lastComplete;
StringBuilder genUnknownSearchPhrase = new StringBuilder();
for (int i = 0; i < unknownWords.size(); i++) {
if (i == 0) {
sp.firstUnknownSearchWord = unknownWords.get(0);
} else {
sp.otherUnknownWords.add(unknownWords.get(i));
}
genUnknownSearchPhrase.append(unknownWords.get(i)).append(" ");
}
sp.fullTextSearchPhrase = fullTextSearchPhrase;
sp.unknownSearchPhrase = genUnknownSearchPhrase.toString().trim();
}
return sp;
}
private void calcMainUnknownWordToSearch() {
if (mainUnknownWordToSearch != null) {
return;
}
List<String> unknownSearchWords = otherUnknownWords;
mainUnknownWordToSearch = firstUnknownSearchWord;
mainUnknownSearchWordComplete = lastUnknownSearchWordComplete;
if (unknownSearchWords.size() > 0) {
mainUnknownSearchWordComplete = true;
List<String> searchWords = new ArrayList<>(unknownSearchWords);
searchWords.add(0, getFirstUnknownSearchWord());
Collections.sort(searchWords, commonWordsComparator);
for (String s : searchWords) {
if (s.length() > 0 && !Character.isDigit(s.charAt(0)) && !LocationParser.isValidOLC(s)) {
mainUnknownWordToSearch = s.trim();
int unknownInd = unknownSearchWords.indexOf(s);
if (!lastUnknownSearchWordComplete && unknownSearchWords.size() - 1 == unknownInd) {
mainUnknownSearchWordComplete = false;
}
break;
}
}
}
}
public List<SearchWord> getWords() { public List<SearchWord> getWords() {
return words; return words;
} }
public boolean isUnknownSearchWordComplete() { public boolean isMainUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete || unknownWords.size() > 0 || unknownSearchWordPoiType != null; // return lastUnknownSearchWordComplete || otherUnknownWords.size() > 0 || unknownSearchWordPoiType != null;
// TODO unknownSearchWordPoiType != null;!!!
return mainUnknownSearchWordComplete;
} }
public boolean isLastUnknownSearchWordComplete() { public boolean isLastUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete; return lastUnknownSearchWordComplete;
} }
public NameStringMatcher getFullUnknownNameMatcher() {
// TODO investigate diesel 95
if (isLastUnknownSearchWordComplete() || hasMoreThanOneUnknownSearchWord()) {
return new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.TRIM_AND_CHECK_ONLY_STARTS_WITH);
} else {
return new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
}
}
public List<String> getUnknownSearchWords() { public boolean hasMoreThanOneUnknownSearchWord() {
return unknownWords; return otherUnknownWords.size() > 0;
} }
public List<String> getUnknownSearchWords(Collection<String> exclude) { public List<String> getUnknownSearchWords(Collection<String> exclude) {
if(exclude == null || unknownWords.size() == 0 || exclude.size() == 0) { if(exclude == null || otherUnknownWords.size() == 0 || exclude.size() == 0) {
return unknownWords; return otherUnknownWords;
} }
List<String> l = new ArrayList<>(); List<String> l = new ArrayList<>();
for(String uw : unknownWords) { for(String uw : otherUnknownWords) {
if(exclude == null || !exclude.contains(uw)) { if(exclude == null || !exclude.contains(uw)) {
l.add(uw); l.add(uw);
} }
@ -234,12 +320,12 @@ public class SearchPhrase {
} }
public String getUnknownSearchWord() { public String getFirstUnknownSearchWord() {
return unknownSearchWordTrim; return firstUnknownSearchWord;
} }
public String getRawUnknownSearchPhrase() { public String getFullSearchPhrase() {
return rawUnknownSearchPhrase; return fullTextSearchPhrase;
} }
public String getUnknownSearchPhrase() { public String getUnknownSearchPhrase() {
@ -247,64 +333,7 @@ public class SearchPhrase {
} }
public boolean isUnknownSearchWordPresent() { public boolean isUnknownSearchWordPresent() {
return unknownSearchWordTrim.length() > 0; return firstUnknownSearchWord.length() > 0;
}
public int getUnknownSearchWordLength() {
return unknownSearchWordTrim.length() ;
}
public AbstractPoiType getUnknownSearchWordPoiType() {
return unknownSearchWordPoiType;
}
public void setUnknownSearchWordPoiType(AbstractPoiType unknownSearchWordPoiType) {
this.unknownSearchWordPoiType = unknownSearchWordPoiType;
}
public boolean hasUnknownSearchWordPoiType() {
return unknownSearchWordPoiType != null;
}
public String getPoiNameFilter() {
return getPoiNameFilter(unknownSearchWordPoiType);
}
public boolean hasUnknownSearchWordPoiTypes() {
return unknownSearchWordPoiTypes != null && unknownSearchWordPoiTypes.size() > 0;
}
public List<AbstractPoiType> getUnknownSearchWordPoiTypes() {
return unknownSearchWordPoiTypes;
}
public void setUnknownSearchWordPoiTypes(List<AbstractPoiType> unknownSearchWordPoiTypes) {
this.unknownSearchWordPoiTypes = unknownSearchWordPoiTypes;
for (AbstractPoiType pt : unknownSearchWordPoiTypes) {
if (getPoiNameFilter(pt) != null) {
setUnknownSearchWordPoiType(pt);
break;
}
}
}
public String getPoiNameFilter(AbstractPoiType pt) {
String nameFilter = null;
if (pt != null) {
NameStringMatcher nm = getNameStringMatcher(getUnknownSearchWord(), true);
String unknownSearchPhrase = getUnknownSearchPhrase();
String enTranslation = pt.getEnTranslation();
String translation = pt.getTranslation();
String synonyms = pt.getSynonyms();
if (unknownSearchPhrase.length() >= enTranslation.length() && nm.matches(enTranslation)) {
nameFilter = unknownSearchPhrase.substring(enTranslation.length()).trim();
} else if (unknownSearchPhrase.length() >= translation.length() && nm.matches(translation)) {
nameFilter = unknownSearchPhrase.substring(translation.length()).trim();
} else if (unknownSearchPhrase.length() >= synonyms.length() && nm.matches(synonyms)) {
nameFilter = unknownSearchPhrase.substring(synonyms.length()).trim();
}
}
return nameFilter;
} }
public QuadRect getRadiusBBoxToSearch(int radius) { public QuadRect getRadiusBBoxToSearch(int radius) {
@ -459,31 +488,6 @@ public class SearchPhrase {
return selectWord(res, null, false); return selectWord(res, null, false);
} }
public SearchPhrase selectWord(SearchResult res, List<String> unknownWords, boolean lastComplete) {
SearchPhrase sp = new SearchPhrase(this.settings, this.clt);
addResult(res, sp);
SearchResult prnt = res.parentSearchResult;
while (prnt != null) {
addResult(prnt, sp);
prnt = prnt.parentSearchResult;
}
sp.words.addAll(0, this.words);
if (unknownWords != null) {
sp.lastUnknownSearchWordComplete = lastComplete;
StringBuilder genUnknownSearchPhrase = new StringBuilder();
for (int i = 0; i < unknownWords.size(); i++) {
if (i == 0) {
sp.unknownSearchWordTrim = unknownWords.get(0);
} else {
sp.unknownWords.add(unknownWords.get(i));
}
genUnknownSearchPhrase.append(unknownWords.get(i)).append(" ");
}
sp.rawUnknownSearchPhrase = sp.unknownSearchPhrase = genUnknownSearchPhrase.toString().trim();
}
return sp;
}
private void addResult(SearchResult res, SearchPhrase sp) { private void addResult(SearchResult res, SearchPhrase sp) {
SearchWord sw = new SearchWord(res.wordsSpan != null ? res.wordsSpan : res.localeName.trim(), res); SearchWord sw = new SearchWord(res.wordsSpan != null ? res.wordsSpan : res.localeName.trim(), res);
@ -513,16 +517,32 @@ public class SearchPhrase {
return null; return null;
} }
public NameStringMatcher getNameStringMatcher() { public NameStringMatcher getMainUnknownNameStringMatcher() {
if(sm != null) { calcMainUnknownWordToSearch();
return sm; if (mainUnknownNameStringMatcher == null) {
mainUnknownNameStringMatcher = getNameStringMatcher(mainUnknownWordToSearch, mainUnknownSearchWordComplete);
} }
sm = getNameStringMatcher(unknownSearchWordTrim, lastUnknownSearchWordComplete); return mainUnknownNameStringMatcher;
return sm; }
public NameStringMatcher getFirstUnknownNameStringMatcher() {
if (firstUnknownNameStringMatcher == null) {
firstUnknownNameStringMatcher = getNameStringMatcher(firstUnknownSearchWord, lastUnknownSearchWordComplete);
}
return firstUnknownNameStringMatcher;
}
public NameStringMatcher getUnknownNameStringMatcher(int i) {
while (unknownWordsMatcher.size() <= i) {
int ind = unknownWordsMatcher.size() - 1;
boolean completeMatch = ind < otherUnknownWords.size() - 1 || isLastUnknownSearchWordComplete();
unknownWordsMatcher.add(getNameStringMatcher(otherUnknownWords.get(ind), completeMatch));
}
return unknownWordsMatcher.get(i);
} }
public NameStringMatcher getNameStringMatcher(String word, boolean complete) { private NameStringMatcher getNameStringMatcher(String word, boolean complete) {
return new NameStringMatcher(word, return new NameStringMatcher(word,
(complete ? (complete ?
StringMatcherMode.CHECK_EQUALS_FROM_SPACE : StringMatcherMode.CHECK_EQUALS_FROM_SPACE :
@ -544,12 +564,12 @@ public class SearchPhrase {
} }
} }
public String getText(boolean includeLastWord) { public String getText(boolean includeUnknownPart) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for(SearchWord s : words) { for(SearchWord s : words) {
sb.append(s.getWord()).append(DELIMITER.trim() + " "); sb.append(s.getWord()).append(DELIMITER);
} }
if(includeLastWord) { if(includeUnknownPart) {
sb.append(unknownSearchPhrase); sb.append(unknownSearchPhrase);
} }
return sb.toString(); return sb.toString();
@ -558,11 +578,11 @@ public class SearchPhrase {
public String getTextWithoutLastWord() { public String getTextWithoutLastWord() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
List<SearchWord> words = new ArrayList<>(this.words); List<SearchWord> words = new ArrayList<>(this.words);
if(Algorithms.isEmpty(unknownSearchWordTrim) && words.size() > 0) { if (Algorithms.isEmpty(unknownSearchPhrase.trim()) && words.size() > 0) {
words.remove(words.size() - 1); words.remove(words.size() - 1);
} }
for(SearchWord s : words) { for(SearchWord s : words) {
sb.append(s.getWord()).append(DELIMITER.trim() + " "); sb.append(s.getWord()).append(DELIMITER);
} }
return sb.toString(); return sb.toString();
} }
@ -705,8 +725,8 @@ public class SearchPhrase {
private CollatorStringMatcher sm; private CollatorStringMatcher sm;
public NameStringMatcher(String lastWordTrim, StringMatcherMode mode) { public NameStringMatcher(String namePart, StringMatcherMode mode) {
sm = new CollatorStringMatcher(lastWordTrim, mode); sm = new CollatorStringMatcher(namePart, mode);
} }
public boolean matches(Collection<String> map) { public boolean matches(Collection<String> map) {
@ -728,35 +748,32 @@ public class SearchPhrase {
} }
public void countUnknownWordsMatch(SearchResult sr) { public void countUnknownWordsMatchMainResult(SearchResult sr) {
countUnknownWordsMatch(sr, sr.localeName, sr.otherNames); countUnknownWordsMatch(sr, sr.localeName, sr.otherNames);
} }
public void countUnknownWordsMatch(SearchResult sr, String localeName, Collection<String> otherNames) { public void countUnknownWordsMatch(SearchResult sr, String localeName, Collection<String> otherNames) {
if (unknownWords.size() > 0) { if (otherUnknownWords.size() > 0) {
for (int i = 0; i < unknownWords.size(); i++) { for (int i = 0; i < otherUnknownWords.size(); i++) {
if (unknownWordsMatcher.size() == i) { NameStringMatcher ms = getUnknownNameStringMatcher(i);
unknownWordsMatcher.add(new NameStringMatcher(unknownWords.get(i),
i < unknownWords.size() - 1 || isLastUnknownSearchWordComplete()
? StringMatcherMode.CHECK_EQUALS_FROM_SPACE
: StringMatcherMode.CHECK_STARTS_FROM_SPACE));
}
NameStringMatcher ms = unknownWordsMatcher.get(i);
if (ms.matches(localeName) || ms.matches(otherNames)) { if (ms.matches(localeName) || ms.matches(otherNames)) {
if (sr.otherWordsMatch == null) { if (sr.otherWordsMatch == null) {
sr.otherWordsMatch = new TreeSet<>(); sr.otherWordsMatch = new TreeSet<>();
} }
sr.otherWordsMatch.add(unknownWords.get(i)); sr.otherWordsMatch.add(otherUnknownWords.get(i));
} }
} }
} }
if(!sr.firstUnknownWordMatches) { if(!sr.firstUnknownWordMatches) {
sr.firstUnknownWordMatches = localeName.equals(getUnknownSearchWord()) || sr.firstUnknownWordMatches = localeName.equals(getFirstUnknownSearchWord()) ||
getNameStringMatcher().matches(localeName) || getFirstUnknownNameStringMatcher().matches(localeName) ||
getNameStringMatcher().matches(otherNames); getFirstUnknownNameStringMatcher().matches(otherNames);
} }
} }
public int getRadiusSearch(int meters, int radiusLevel) { public int getRadiusSearch(int meters, int radiusLevel) {
int res = meters; int res = meters;
for(int k = 0; k < radiusLevel; k++) { for(int k = 0; k < radiusLevel; k++) {
@ -777,18 +794,39 @@ public class SearchPhrase {
return (x < y) ? -1 : ((x == y) ? 0 : 1); return (x < y) ? -1 : ((x == y) ? 0 : 1);
} }
public String getUnknownWordToSearchBuilding() { private int getUnknownWordToSearchBuildingInd() {
List<String> unknownSearchWords = getUnknownSearchWords(); if (otherUnknownWords.size() > 0 && Algorithms.extractFirstIntegerNumber(getFirstUnknownSearchWord()) == 0) {
if(unknownSearchWords.size() > 0 && Algorithms.extractFirstIntegerNumber(getUnknownSearchWord()) == 0) { int ind = 0;
for(String wrd : unknownSearchWords) { for (String wrd : otherUnknownWords) {
ind++;
if (Algorithms.extractFirstIntegerNumber(wrd) != 0) { if (Algorithms.extractFirstIntegerNumber(wrd) != 0) {
return wrd; return ind;
} }
} }
} }
return getUnknownSearchWord(); return 0;
} }
public NameStringMatcher getUnknownWordToSearchBuildingNameMatcher() {
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return getUnknownNameStringMatcher(ind - 1);
} else {
return getFirstUnknownNameStringMatcher();
}
}
public String getUnknownWordToSearchBuilding() {
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return otherUnknownWords.get(ind - 1);
} else {
return firstUnknownSearchWord;
}
}
private static int lengthWithoutNumbers(String s) { private static int lengthWithoutNumbers(String s) {
int len = 0; int len = 0;
for(int k = 0; k < s.length(); k++) { for(int k = 0; k < s.length(); k++) {
@ -802,19 +840,18 @@ public class SearchPhrase {
} }
public String getUnknownWordToSearch() { public String getUnknownWordToSearch() {
List<String> unknownSearchWords = getUnknownSearchWords(); calcMainUnknownWordToSearch();
String wordToSearch = getUnknownSearchWord(); return mainUnknownWordToSearch;
if (unknownSearchWords.size() > 0) {
List<String> searchWords = new ArrayList<>(unknownSearchWords);
searchWords.add(0, getUnknownSearchWord());
Collections.sort(searchWords, commonWordsComparator);
for (String s : searchWords) {
if (s.length() > 0 && !Character.isDigit(s.charAt(0)) && !LocationParser.isValidOLC(s)) {
return s;
} }
private boolean isTextComplete(String fullText) {
boolean lastUnknownSearchWordComplete = false;
if (fullText.length() > 0 ) {
char ch = fullText.charAt(fullText.length() - 1);
lastUnknownSearchWordComplete = ch == ' ' || ch == ',' || ch == '\r' || ch == '\n'
|| ch == ';';
} }
} return lastUnknownSearchWordComplete;
return wordToSearch;
} }

View file

@ -17,17 +17,32 @@ public class SearchResult {
// search phrase that makes search result valid // search phrase that makes search result valid
public SearchPhrase requiredSearchPhrase; public SearchPhrase requiredSearchPhrase;
// internal package fields (used for sorting)
public SearchResult parentSearchResult;
String wordsSpan ;
// TODO
boolean firstUnknownWordMatches = true;
Collection<String> otherWordsMatch = null;
boolean unknownPhraseMatches = false;
public Object object; public Object object;
public ObjectType objectType; public ObjectType objectType;
public BinaryMapIndexReader file; public BinaryMapIndexReader file;
public double priority; public double priority;
public double priorityDistance; public double priorityDistance;
public String wordsSpan ;
public SearchResult parentSearchResult; public LatLon location;
public Collection<String> otherWordsMatch = null; public int preferredZoom = 15;
public boolean firstUnknownWordMatches = true;
public boolean unknownPhraseMatches = false; public String localeName;
public String alternateName;
public Collection<String> otherNames;
public String localeRelatedObjectName;
public Object relatedObject;
public double distRelatedObjectName;
public SearchResult(SearchPhrase sp) { public SearchResult(SearchPhrase sp) {
this.requiredSearchPhrase = sp; this.requiredSearchPhrase = sp;
@ -40,7 +55,12 @@ public class SearchResult {
res = ObjectType.getTypeWeight(objectType); res = ObjectType.getTypeWeight(objectType);
} }
if (parentSearchResult != null) { if (parentSearchResult != null) {
// TODO
// 10 > maximum type // 10 > maximum type
// double x = parentSearchResult.getUnknownPhraseMatchWeight();
// if (x == 0) {
// return 0;
// }
// res = Math.max(res, parentSearchResult.getUnknownPhraseMatchWeight()); // res = Math.max(res, parentSearchResult.getUnknownPhraseMatchWeight());
res += parentSearchResult.getUnknownPhraseMatchWeight() / 10; res += parentSearchResult.getUnknownPhraseMatchWeight() / 10;
} }
@ -77,16 +97,6 @@ public class SearchResult {
return priority - 1 / (1 + pd * distance); return priority - 1 / (1 + pd * distance);
} }
public LatLon location;
public int preferredZoom = 15;
public String localeName;
public String alternateName;
public Collection<String> otherNames;
public String localeRelatedObjectName;
public Object relatedObject;
public double distRelatedObjectName;
@Override @Override
public String toString() { public String toString() {

View file

@ -17,7 +17,7 @@ public class LocationSearchTest {
private void search(String string, LatLon latLon) throws IOException { private void search(String string, LatLon latLon) throws IOException {
SearchResultMatcher srm = new SearchUICore.SearchResultMatcher(null, null, 0, null, 100); SearchResultMatcher srm = new SearchUICore.SearchResultMatcher(null, null, 0, null, 100);
new SearchCoreFactory.SearchLocationAndUrlAPI(). new SearchCoreFactory.SearchLocationAndUrlAPI().
search(new SearchPhrase(null, OsmAndCollator.primaryCollator()).generateNewPhrase(string, null), srm); search(SearchPhrase.emptyPhrase().generateNewPhrase(string, null), srm);
Assert.assertEquals(1, srm.getRequestResults().size()); Assert.assertEquals(1, srm.getRequestResults().size());
Assert.assertEquals(latLon, srm.getRequestResults().get(0).location); Assert.assertEquals(latLon, srm.getRequestResults().get(0).location);
} }

View file

@ -8,7 +8,6 @@ import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import net.osmand.OsmAndCollator;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.search.SearchUICore.SearchResultCollection; import net.osmand.search.SearchUICore.SearchResultCollection;
import net.osmand.search.core.SearchPhrase; import net.osmand.search.core.SearchPhrase;
@ -29,7 +28,7 @@ public class SearchUICoreGenericTest {
public void testDuplicates() throws IOException { public void testDuplicates() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null); SearchSettings ss = new SearchSettings((SearchSettings)null);
ss = ss.setOriginalLocation(new LatLon(0, 0)); ss = ss.setOriginalLocation(new LatLon(0, 0));
SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); SearchPhrase phrase = SearchPhrase.emptyPhrase(ss);
SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase);
List<SearchResult> rs = new ArrayList<>(); List<SearchResult> rs = new ArrayList<>();
SearchResult a1 = searchResult(rs, phrase, "a", 100); SearchResult a1 = searchResult(rs, phrase, "a", 100);
@ -47,7 +46,7 @@ public class SearchUICoreGenericTest {
public void testNoResort() throws IOException { public void testNoResort() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null); SearchSettings ss = new SearchSettings((SearchSettings)null);
ss = ss.setOriginalLocation(new LatLon(0, 0)); ss = ss.setOriginalLocation(new LatLon(0, 0));
SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); SearchPhrase phrase = SearchPhrase.emptyPhrase(ss);
SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase);
List<SearchResult> rs = new ArrayList<>(); List<SearchResult> rs = new ArrayList<>();
SearchResult a1 = searchResult(rs, phrase, "a", 100); SearchResult a1 = searchResult(rs, phrase, "a", 100);
@ -80,7 +79,7 @@ public class SearchUICoreGenericTest {
public void testNoResortDuplicate() throws IOException { public void testNoResortDuplicate() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null); SearchSettings ss = new SearchSettings((SearchSettings)null);
ss = ss.setOriginalLocation(new LatLon(0, 0)); ss = ss.setOriginalLocation(new LatLon(0, 0));
SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); SearchPhrase phrase = SearchPhrase.emptyPhrase(ss);
SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase);
List<SearchResult> rs = new ArrayList<>(); List<SearchResult> rs = new ArrayList<>();
SearchResult a1 = searchResult(rs, phrase, "a", 100); SearchResult a1 = searchResult(rs, phrase, "a", 100);

View file

@ -152,7 +152,7 @@ public class SearchUICoreTest {
SearchSettings s = SearchSettings.parseJSON(settingsJson); SearchSettings s = SearchSettings.parseJSON(settingsJson);
s.setOfflineIndexes(Collections.singletonList(reader)); s.setOfflineIndexes(Collections.singletonList(reader));
SearchPhrase phrase = new SearchPhrase(s, OsmAndCollator.primaryCollator()); SearchPhrase phrase = SearchPhrase.emptyPhrase(s);
phrase = phrase.generateNewPhrase(phraseText, s); phrase = phrase.generateNewPhrase(phraseText, s);
final SearchUICore core = new SearchUICore(MapPoiTypes.getDefault(), "en", false); final SearchUICore core = new SearchUICore(MapPoiTypes.getDefault(), "en", false);

View file

@ -351,11 +351,11 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
cancelSearch(); cancelSearch();
SearchPhrase searchPhrase = searchUICore.getPhrase(); SearchPhrase searchPhrase = searchUICore.getPhrase();
if (foundPartialLocation) { if (foundPartialLocation) {
QuickSearchCoordinatesFragment.showDialog(QuickSearchDialogFragment.this, searchPhrase.getUnknownSearchWord()); QuickSearchCoordinatesFragment.showDialog(QuickSearchDialogFragment.this, searchPhrase.getFirstUnknownSearchWord());
} else if (searchPhrase.isNoSelectedType() || searchPhrase.isLastWord(POI_TYPE)) { } else if (searchPhrase.isNoSelectedType() || searchPhrase.isLastWord(POI_TYPE)) {
PoiUIFilter filter; PoiUIFilter filter;
if (searchPhrase.isNoSelectedType()) { if (searchPhrase.isNoSelectedType()) {
if (isOnlineSearch() && !Algorithms.isEmpty(searchPhrase.getUnknownSearchWord())) { if (isOnlineSearch() && !Algorithms.isEmpty(searchPhrase.getFirstUnknownSearchWord())) {
app.getPoiFilters().resetNominatimFilters(); app.getPoiFilters().resetNominatimFilters();
filter = app.getPoiFilters().getNominatimPOIFilter(); filter = app.getPoiFilters().getNominatimPOIFilter();
filter.setFilterByName(searchPhrase.getUnknownSearchPhrase()); filter.setFilterByName(searchPhrase.getUnknownSearchPhrase());
@ -369,8 +369,8 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
} }
} else { } else {
filter = app.getPoiFilters().getSearchByNamePOIFilter(); filter = app.getPoiFilters().getSearchByNamePOIFilter();
if (!Algorithms.isEmpty(searchPhrase.getUnknownSearchWord())) { if (!Algorithms.isEmpty(searchPhrase.getFirstUnknownSearchWord())) {
filter.setFilterByName(searchPhrase.getUnknownSearchWord()); filter.setFilterByName(searchPhrase.getFirstUnknownSearchWord());
filter.clearCurrentResults(); filter.clearCurrentResults();
} }
} }
@ -382,8 +382,8 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
.getResult().object; .getResult().object;
filter = new PoiUIFilter(abstractPoiType, app, ""); filter = new PoiUIFilter(abstractPoiType, app, "");
} }
if (!Algorithms.isEmpty(searchPhrase.getUnknownSearchWord())) { if (!Algorithms.isEmpty(searchPhrase.getFirstUnknownSearchWord())) {
filter.setFilterByName(searchPhrase.getUnknownSearchWord()); filter.setFilterByName(searchPhrase.getFirstUnknownSearchWord());
} }
} else { } else {
filter = (PoiUIFilter) searchPhrase.getLastSelectedWord().getResult().object; filter = (PoiUIFilter) searchPhrase.getLastSelectedWord().getResult().object;
@ -628,9 +628,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (searchEditText.getText().length() > 0) { if (searchEditText.getText().length() > 0) {
String newText = searchUICore.getPhrase().getTextWithoutLastWord(); clearLastWord();
searchEditText.setText(newText);
searchEditText.setSelection(newText.length());
} else if (useMapCenter && location != null) { } else if (useMapCenter && location != null) {
useMapCenter = false; useMapCenter = false;
centerLatLon = null; centerLatLon = null;

View file

@ -123,7 +123,7 @@ public class QuickSearchHelper implements ResourceListener {
public void refreshFilterOrders() { public void refreshFilterOrders() {
PoiFiltersHelper filtersHelper = app.getPoiFilters(); PoiFiltersHelper filtersHelper = app.getPoiFilters();
core.setFilterOrders(filtersHelper.getPoiFilterOrders(true)); core.setActivePoiFiltersByOrder(filtersHelper.getPoiFilterOrders(true));
} }
public void setRepositoriesForSearchUICore(final OsmandApplication app) { public void setRepositoriesForSearchUICore(final OsmandApplication app) {
@ -353,7 +353,7 @@ public class QuickSearchHelper implements ResourceListener {
public boolean search(SearchPhrase phrase, SearchResultMatcher matcher) throws IOException { public boolean search(SearchPhrase phrase, SearchResultMatcher matcher) throws IOException {
double lat = phrase.getSettings().getOriginalLocation().getLatitude(); double lat = phrase.getSettings().getOriginalLocation().getLatitude();
double lon = phrase.getSettings().getOriginalLocation().getLongitude(); double lon = phrase.getSettings().getOriginalLocation().getLongitude();
String text = phrase.getRawUnknownSearchPhrase(); String text = phrase.getFullSearchPhrase();
filter.setFilterByName(text); filter.setFilterByName(text);
publishAmenities(phrase, matcher, filter.initializeNewSearch(lat, lon, publishAmenities(phrase, matcher, filter.initializeNewSearch(lat, lon,
-1, null, phrase.getRadiusLevel() + 3)); -1, null, phrase.getRadiusLevel() + 3));

View file

@ -785,13 +785,6 @@ public class QuickSearchDialogFragment extends DialogFragment implements SampleC
runCoreSearch(txt, false, false); runCoreSearch(txt, false, false);
} }
public void clearLastWord() {
if (searchEditText.getText().length() > 0) {
String newText = searchUICore.getPhrase().getTextWithoutLastWord();
searchEditText.setText(newText);
searchEditText.setSelection(newText.length());
}
}
private void addMoreButton() { private void addMoreButton() {
QuickSearchMoreListItem moreListItem = QuickSearchMoreListItem moreListItem =