Merge remote-tracking branch 'origin/r3.7'

This commit is contained in:
Victor Shcherb 2020-06-04 15:57:32 +02:00
commit e8ad8c94a8
54 changed files with 1855 additions and 1208 deletions

View file

@ -17,12 +17,17 @@ 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,
// 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 +47,20 @@ 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:
return cstartsWith(collator, base, part, true, false, false, true);
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 +119,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(searchSettings);
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,18 @@ 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 Check names and count 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;
} }
} }
// TODO
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;
} }
@ -816,7 +817,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) {
@ -857,8 +858,8 @@ public class SearchUICore {
private enum ResultCompareStep { private enum ResultCompareStep {
TOP_VISIBLE, TOP_VISIBLE,
FOUND_WORD_COUNT, FOUND_WORD_COUNT, // more is better (top)
UNKNOWN_PHRASE_MATCH_WEIGHT, UNKNOWN_PHRASE_MATCH_WEIGHT, // more is better (top)
SEARCH_DISTANCE_IF_NOT_BY_NAME, SEARCH_DISTANCE_IF_NOT_BY_NAME,
COMPARE_FIRST_NUMBER_IN_NAME, COMPARE_FIRST_NUMBER_IN_NAME,
COMPARE_DISTANCE_TO_PARENT_SEARCH_RESULT, // makes sense only for inner subqueries COMPARE_DISTANCE_TO_PARENT_SEARCH_RESULT, // makes sense only for inner subqueries
@ -964,14 +965,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

@ -1,6 +1,7 @@
package net.osmand.search.core; package net.osmand.search.core;
import net.osmand.CollatorStringMatcher;
import net.osmand.CollatorStringMatcher.StringMatcherMode; import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.ResultMatcher; import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapAddressReaderAdapter; import net.osmand.binary.BinaryMapAddressReaderAdapter;
@ -20,7 +21,6 @@ import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType; import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes; import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory; import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType; import net.osmand.osm.PoiType;
import net.osmand.search.SearchUICore.SearchResultMatcher; import net.osmand.search.SearchUICore.SearchResultMatcher;
import net.osmand.search.core.SearchPhrase.NameStringMatcher; import net.osmand.search.core.SearchPhrase.NameStringMatcher;
@ -48,8 +48,6 @@ import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import gnu.trove.list.array.TIntArrayList;
public class SearchCoreFactory { public class SearchCoreFactory {
@ -140,23 +138,67 @@ 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(); boolean firstUnknownWordMatches = res.firstUnknownWordMatches;
List<String> ws = phrase.getUnknownSearchWords(res.otherWordsMatch); List<String> leftUnknownSearchWords = new ArrayList<String>(phrase.getUnknownSearchWords());
if (!res.firstUnknownWordMatches) { if(res.otherWordsMatch != null) {
ws.add(phrase.getUnknownSearchWord()); leftUnknownSearchWords.removeAll(res.otherWordsMatch);
}
SearchResult newParentSearchResult = null;
if (res.parentSearchResult == null && resultMatcher.getParentSearchResult() == null &&
res.objectType == ObjectType.STREET && res.object instanceof Street && ((Street) res.object).getCity() != null) {
City ct = ((Street) res.object).getCity();
SearchResult cityResult = new SearchResult(phrase);
cityResult.object = ct;
cityResult.objectType = ObjectType.CITY;
cityResult.localeName = ct.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
cityResult.otherNames = ct.getAllNames(true);
cityResult.location = ct.getLocation();
cityResult.localeRelatedObjectName = res.file.getRegionName();
cityResult.file = res.file;
phrase.countUnknownWordsMatchMainResult(cityResult);
boolean match = false;
if (firstUnknownWordMatches) {
cityResult.firstUnknownWordMatches = false; // don't count same name twice
} else if (cityResult.firstUnknownWordMatches) {
firstUnknownWordMatches = true;
match = true;
}
if (cityResult.otherWordsMatch != null) {
Iterator<String> iterator = cityResult.otherWordsMatch.iterator();
while (iterator.hasNext()) {
String n = iterator.next();
boolean wasPresent = leftUnknownSearchWords.remove(n);
if (!wasPresent) {
iterator.remove(); // don't count same name twice
} else {
match = true;
}
}
}
// include parent search result even if it is empty
if (match) {
newParentSearchResult = cityResult;
}
}
if (!firstUnknownWordMatches) {
leftUnknownSearchWords.add(0, phrase.getFirstUnknownSearchWord());
} }
// publish result to set parentSearchResult before search // publish result to set parentSearchResult before search
if(newParentSearchResult != null) {
SearchResult prev = resultMatcher.setParentSearchResult(newParentSearchResult);
resultMatcher.publish(res); resultMatcher.publish(res);
if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) { resultMatcher.setParentSearchResult(prev);
SearchPhrase nphrase = phrase.selectWord(res, ws, } else {
phrase.isLastUnknownSearchWordComplete()); resultMatcher.publish(res);
resultMatcher.setParentSearchResult(res); }
if (!leftUnknownSearchWords.isEmpty() && api != null && api.isSearchAvailable(phrase)) {
SearchPhrase nphrase = phrase.selectWord(res, leftUnknownSearchWords, phrase.isLastUnknownSearchWordComplete());
SearchResult prev = resultMatcher.setParentSearchResult(res);
api.search(nphrase, resultMatcher); api.search(nphrase, resultMatcher);
resultMatcher.setParentSearchResult(res.parentSearchResult); resultMatcher.setParentSearchResult(prev);
} }
} }
@ -166,8 +208,6 @@ public class SearchCoreFactory {
} }
} }
public static class SearchRegionByNameAPI extends SearchBaseAPI { public static class SearchRegionByNameAPI extends SearchBaseAPI {
public SearchRegionByNameAPI() { public SearchRegionByNameAPI() {
@ -186,9 +226,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 +250,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 +337,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 +359,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 +370,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 +414,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 +483,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,13 +497,7 @@ 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();
phrase.countUnknownWordsMatch(res,
ct.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()),
ct.getAllNames(true));
subSearchApiOrPublish(phrase, resultMatcher, res, streetsApi); subSearchApiOrPublish(phrase, resultMatcher, res, streetsApi);
} else { } else {
subSearchApiOrPublish(phrase, resultMatcher, res, cityApi); subSearchApiOrPublish(phrase, resultMatcher, res, cityApi);
@ -510,29 +524,25 @@ public class SearchCoreFactory {
if (!phrase.isUnknownSearchWordPresent()) { if (!phrase.isUnknownSearchWordPresent()) {
return false; return false;
} }
boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent() if (!phrase.isNoSelectedType()) {
&& phrase.isUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes(); // don't search by name when type is selected or poi type is part of name
return false;
}
// Take into account POI [bar] - 'Hospital 512'
// BEFORE: it was searching exact match of whole phrase.getUnknownSearchPhrase() [ Check feedback ]
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 +557,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 +576,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 +638,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,126 +648,164 @@ 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 Map<AbstractPoiType, List<String>> getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) {
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException { Map<AbstractPoiType, List<String>> results = new LinkedHashMap<>();
if (translatedNames.isEmpty()) {
translatedNames = types.getAllTranslatedNames(false);
topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
}
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 checkPoiType(nm, pf, results);
|| nm.matches(pf.getTranslation())
|| nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getSynonyms())) {
results.add(pf);
searchWordTypes.add(pf);
} }
}
if (!showTopFiltersOnly) {
for (PoiCategory c : categories) { for (PoiCategory c : categories) {
if (!results.contains(c) checkPoiType(nm, c, results);
&& (nm.matches(c.getTranslation())
|| nm.matches(c.getEnTranslation())
|| nm.matches(c.getSynonyms()))) {
results.add(c);
searchWordTypes.add(c);
}
} }
Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator(); Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
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) checkPoiType(nm, pt, results);
&& (nm.matches(pt.getEnTranslation())
|| nm.matches(pt.getTranslation())
|| nm.matches(pt.getSynonyms()))) {
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.containsKey(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()))) { checkPoiType(nm, a, results);
results.add(a);
} }
} }
} }
} }
} }
} }
return results;
} }
phrase.setUnknownSearchWordPoiTypes(searchWordTypes);
if (resultMatcher != null) { private void checkPoiType(NameStringMatcher nm, AbstractPoiType pf, Map<AbstractPoiType, List<String>> results) {
String word = phrase.getUnknownSearchWord(); List<String> lst = results.get(pf);
NameStringMatcher startMatch = new NameStringMatcher(word, StringMatcherMode.CHECK_ONLY_STARTS_WITH); boolean nl = lst == null;
for (AbstractPoiType pt : results) { if (nm.matches(pf.getTranslation())) {
lst = addToList(pf.getTranslation(), lst);
}
if (nm.matches(pf.getEnTranslation())) {
lst = addToList(pf.getEnTranslation(), lst);
}
if (nm.matches(pf.getSynonyms())) {
String[] synonyms = pf.getSynonyms().split(";");
for (String synonym : synonyms) {
if (nm.matches(synonym)) {
lst = addToList(synonym, lst);
}
}
}
if(lst != null && nl) {
results.put(pf, lst);
}
}
private List<String> addToList(String s, List<String> lst) {
if(lst == null) {
lst = new ArrayList<>();
}
lst.add(s);
return lst;
}
private void initPoiTypes() {
if (translatedNames.isEmpty()) {
translatedNames = types.getAllTranslatedNames(false);
topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
}
}
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
boolean showTopFiltersOnly = !phrase.isUnknownSearchWordPresent();
NameStringMatcher nm = phrase.getFirstUnknownNameStringMatcher();
initPoiTypes();
if (showTopFiltersOnly) {
for (AbstractPoiType pt : topVisibleFilters) {
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 { } else {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY; boolean includeAdditional = !phrase.hasMoreThanOneUnknownSearchWord();
resultMatcher.publish(res); Map<AbstractPoiType, List<String>> poiTypes = getPoiTypeResults(nm, includeAdditional);
for (Entry<AbstractPoiType, List<String>> pt : poiTypes.entrySet()) {
boolean match = !phrase.isFirstUnknownSearchWordComplete();
if (!match) {
for (String foundName : pt.getValue()) {
CollatorStringMatcher csm = new CollatorStringMatcher(foundName, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
match = csm.matches(phrase.getUnknownSearchPhrase());
if (match) {
break;
}
}
}
if (match) {
SearchResult res = new SearchResult(phrase);
res.localeName = pt.getKey().getTranslation();
res.object = pt.getKey();
addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(pt.getKey()),
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();
} }
@ -792,8 +834,10 @@ public class SearchCoreFactory {
public static class SearchAmenityByTypeAPI extends SearchBaseAPI { public static class SearchAmenityByTypeAPI extends SearchBaseAPI {
private static final int BBOX_RADIUS = 10000; private static final int BBOX_RADIUS = 10000;
private SearchAmenityTypesAPI searchAmenityTypesAPI; private SearchAmenityTypesAPI searchAmenityTypesAPI;
private MapPoiTypes types; private MapPoiTypes types;
private Map<PoiCategory, LinkedHashSet<String>> acceptedTypes = new LinkedHashMap<PoiCategory,
LinkedHashSet<String>>();
private Map<String, PoiType> poiAdditionals = new HashMap<String, PoiType>();
public SearchAmenityByTypeAPI(MapPoiTypes types, SearchAmenityTypesAPI searchAmenityTypesAPI) { public SearchAmenityByTypeAPI(MapPoiTypes types, SearchAmenityTypesAPI searchAmenityTypesAPI) {
super(ObjectType.POI); super(ObjectType.POI);
@ -816,95 +860,82 @@ public class SearchCoreFactory {
return phrase.getNextRadiusSearch(BBOX_RADIUS); return phrase.getNextRadiusSearch(BBOX_RADIUS);
} }
private Map<PoiCategory, LinkedHashSet<String>> acceptedTypes = new LinkedHashMap<PoiCategory,
LinkedHashSet<String>>();
private Map<String, PoiType> poiAdditionals = new HashMap<String, PoiType>();
public void updateTypesToAccept(AbstractPoiType pt) { public void updateTypesToAccept(AbstractPoiType pt) {
pt.putTypes(acceptedTypes); pt.putTypes(acceptedTypes);
if (pt instanceof PoiType && ((PoiType) pt).isAdditional() && ((PoiType) pt).getParentType() != null) { if (pt instanceof PoiType && ((PoiType) pt).isAdditional() && ((PoiType) pt).getParentType() != null) {
fillPoiAdditionals(((PoiType) pt).getParentType()); poiAdditionals.put(pt.getKeyName(), (PoiType) pt);
} else {
fillPoiAdditionals(pt);
}
}
private void fillPoiAdditionals(AbstractPoiType pt) {
for (PoiType add : pt.getPoiAdditionals()) {
poiAdditionals.put(add.getKeyName().replace('_', ':').replace(' ', ':'), add);
poiAdditionals.put(add.getTranslation().replace(' ', ':').toLowerCase(), add);
}
if (pt instanceof PoiFilter && !(pt instanceof PoiCategory)) {
for (PoiType ps : ((PoiFilter) pt).getPoiTypes()) {
fillPoiAdditionals(ps);
}
} }
} }
@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;
int countExtraWords = 0;
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); nameFilter = phrase.getUnknownSearchPhrase();
} else if (searchAmenityTypesAPI != null) { } else if (searchAmenityTypesAPI != null && phrase.isFirstUnknownSearchWordComplete()) {
if (phrase.getUnknownSearchWordPoiTypes() == null) { NameStringMatcher nm = phrase.getFirstUnknownNameStringMatcher();
searchAmenityTypesAPI.search(phrase, null); searchAmenityTypesAPI.initPoiTypes();
Map<AbstractPoiType, List<String>> poiTypeResults = searchAmenityTypesAPI.getPoiTypeResults(nm, true);
// find first full match only
for (Entry<AbstractPoiType, List<String>> poiType : poiTypeResults.entrySet()) {
for (String foundName : poiType.getValue()) {
CollatorStringMatcher csm = new CollatorStringMatcher(foundName, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
// matches only completely
int mwords = phrase.countWords(foundName) ;
if (csm.matches(phrase.getUnknownSearchPhrase()) && countExtraWords < mwords) {
countExtraWords = phrase.countWords(foundName);
List<String> otherSearchWords = phrase.getUnknownSearchWords();
nameFilter = null;
if (countExtraWords - 1 < otherSearchWords.size()) {
nameFilter = "";
for(int k = countExtraWords - 1; k < otherSearchWords.size(); k++) {
if(nameFilter.length() > 0) {
nameFilter += SearchPhrase.DELIMITER;
} }
AbstractPoiType poiType = phrase.getUnknownSearchWordPoiType(); nameFilter += otherSearchWords.get(k);
if (poiType != null) {
SearchPoiTypeFilter ptf = getPoiTypeFilter(poiType);
String customName = phrase.getPoiNameFilter(poiType);
if (customName != null) {
phrase.setUnknownSearchWordPoiType(poiType);
searchPoi(phrase, resultMatcher, null, customName.length() == 0 ? null : customName, ptf);
} }
} }
poiTypeFilter = getPoiTypeFilter(poiType.getKey());
}
}
}
}
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, poiTypeFilter, resultMatcher, nameFilter, r, searchedPois, countExtraWords);
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 SearchPoiTypeFilter poiTypeFilter,
final String customName, final BinaryMapIndexReader selected, final SearchResultMatcher resultMatcher, final String nameFilter,
final Set<String> searchedPois) { final BinaryMapIndexReader selected, final Set<String> searchedPois,
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim(); final int countExtraWords) {
final NameStringMatcher phraseMatcher;
if (!Algorithms.isEmpty(unknownSearchPhrase)) { NameStringMatcher ns = nameFilter == null ? null : new NameStringMatcher(nameFilter, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
phraseMatcher = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_EQUALS);
} else {
phraseMatcher = null;
}
final NameStringMatcher ns;
final boolean hasCustomName = !Algorithms.isEmpty(customName);
if (hasCustomName) {
ns = phrase.getNameStringMatcher(customName, phrase.isLastUnknownSearchWordComplete());
} else {
ns = phrase.getNameStringMatcher();
}
return new ResultMatcher<Amenity>() { return new ResultMatcher<Amenity>() {
@Override @Override
@ -920,6 +951,18 @@ public class SearchCoreFactory {
if (object.isClosed()) { if (object.isClosed()) {
return false; return false;
} }
if (!poiAdditionals.isEmpty()) {
boolean found = false;
for (String add : poiAdditionals.keySet()) {
if(object.getAdditionalInfo().containsKey(add)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
res.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
res.otherNames = object.getAllNames(true); res.otherNames = object.getAllNames(true);
if (Algorithms.isEmpty(res.localeName)) { if (Algorithms.isEmpty(res.localeName)) {
@ -930,15 +973,19 @@ public class SearchCoreFactory {
res.localeName = object.getSubType(); res.localeName = object.getSubType();
} }
} }
if (phrase.isUnknownSearchWordPresent() if (ns != null) {
&& !(ns.matches(res.localeName) || ns.matches(res.otherNames))) { if (ns.matches(res.localeName) || ns.matches(res.otherNames)) {
phrase.countUnknownWordsMatchMainResult(res, countExtraWords);
} 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, countExtraWords);
res.localeName += " " + ref; res.localeName += " " + ref;
} }
} }
}
res.object = object; res.object = object;
res.preferredZoom = 17; res.preferredZoom = 17;
@ -946,16 +993,6 @@ 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) {
boolean unknownPhraseMatches = phraseMatcher.matches(res.localeName);
AbstractPoiType unknownSearchWordPoiType = phrase.getUnknownSearchWordPoiType();
if (unknownPhraseMatches && unknownSearchWordPoiType != null) {
unknownPhraseMatches = !phraseMatcher.matches(unknownSearchWordPoiType.getTranslation())
&& !phraseMatcher.matches(unknownSearchWordPoiType.getEnTranslation())
&& !phraseMatcher.matches(unknownSearchWordPoiType.getSynonyms());
}
res.unknownPhraseMatches = unknownPhraseMatches;
}
res.objectType = ObjectType.POI; res.objectType = ObjectType.POI;
resultMatcher.publish(res); resultMatcher.publish(res);
return false; return false;
@ -969,7 +1006,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 +1081,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 +1095,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 +1124,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 +1196,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 +1211,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 +1226,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 +1236,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 +1423,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;
@ -9,7 +9,6 @@ import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.CommonWords; 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.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 +26,41 @@ 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 {
public static final String DELIMITER = " ";
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 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 to be used for words span
private List<SearchWord> words = new ArrayList<>();
// Words of 2 parts
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,97 +158,173 @@ 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;
sp.lastUnknownSearchWordComplete = isTextComplete(fullText) ;
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())) { boolean conjunction = conjunctions.contains(wd.toLowerCase());
boolean lastAndIncomplete = i == ws.length - 1 && !sp.lastUnknownSearchWordComplete;
if (wd.length() > 0 && (!conjunction || lastAndIncomplete)) {
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;
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 int countWords(String w) {
String[] ws = w.split(ALLDELIMITERS);
int cnt = 0;
for (int i = 0; i < ws.length; i++) {
String wd = ws[i].trim();
if (wd.length() > 0) {
cnt++;
}
}
return cnt;
}
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;
return mainUnknownSearchWordComplete;
} }
public boolean isLastUnknownSearchWordComplete() { public boolean isLastUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete; return lastUnknownSearchWordComplete;
} }
public boolean hasMoreThanOneUnknownSearchWord() {
return otherUnknownWords.size() > 0;
}
public List<String> getUnknownSearchWords() { public List<String> getUnknownSearchWords() {
return unknownWords; return otherUnknownWords;
}
public List<String> getUnknownSearchWords(Collection<String> exclude) {
if(exclude == null || unknownWords.size() == 0 || exclude.size() == 0) {
return unknownWords;
}
List<String> l = new ArrayList<>();
for(String uw : unknownWords) {
if(exclude == null || !exclude.contains(uw)) {
l.add(uw);
}
}
return l;
} }
public String getUnknownSearchWord() { public String getFirstUnknownSearchWord() {
return unknownSearchWordTrim; return firstUnknownSearchWord;
} }
public String getRawUnknownSearchPhrase() { public boolean isFirstUnknownSearchWordComplete() {
return rawUnknownSearchPhrase; return hasMoreThanOneUnknownSearchWord() || isLastUnknownSearchWordComplete();
}
public String getFullSearchPhrase() {
return fullTextSearchPhrase;
} }
public String getUnknownSearchPhrase() { public String getUnknownSearchPhrase() {
@ -247,64 +332,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 +487,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 +516,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();
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 +563,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 +577,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 +724,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 +747,53 @@ public class SearchPhrase {
} }
public void countUnknownWordsMatch(SearchResult sr) { public int countUnknownWordsMatchMainResult(SearchResult sr) {
countUnknownWordsMatch(sr, sr.localeName, sr.otherNames); return countUnknownWordsMatch(sr, sr.localeName, sr.otherNames, 0);
} }
public void countUnknownWordsMatch(SearchResult sr, String localeName, Collection<String> otherNames) { public int countUnknownWordsMatchMainResult(SearchResult sr, int amountMatchingWords) {
if (unknownWords.size() > 0) { return countUnknownWordsMatch(sr, sr.localeName, sr.otherNames, amountMatchingWords);
for (int i = 0; i < unknownWords.size(); i++) {
if (unknownWordsMatcher.size() == 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);
public int countUnknownWordsMatch(SearchResult sr, String localeName, Collection<String> otherNames, int amountMatchingWords) {
int r = 0;
if (otherUnknownWords.size() > 0) {
for (int i = 0; i < otherUnknownWords.size(); i++) {
boolean match = false;
if (i < amountMatchingWords - 1) {
match = true;
} else {
NameStringMatcher ms = getUnknownNameStringMatcher(i);
if (ms.matches(localeName) || ms.matches(otherNames)) { if (ms.matches(localeName) || ms.matches(otherNames)) {
match = true;
}
}
if (match) {
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));
r++;
} }
} }
} }
if(!sr.firstUnknownWordMatches) { if (amountMatchingWords > 0) {
sr.firstUnknownWordMatches = localeName.equals(getUnknownSearchWord()) || sr.firstUnknownWordMatches = true;
getNameStringMatcher().matches(localeName) || r++;
getNameStringMatcher().matches(otherNames); } else {
boolean match = localeName.equals(getFirstUnknownSearchWord())
|| getFirstUnknownNameStringMatcher().matches(localeName)
|| getFirstUnknownNameStringMatcher().matches(otherNames);
if(match) {
r++;
}
sr.firstUnknownWordMatches = match || sr.firstUnknownWordMatches;
}
return r;
} }
}
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 +814,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,20 +860,21 @@ 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,36 +17,58 @@ 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 ;
boolean firstUnknownWordMatches;
Collection<String> otherWordsMatch = null;
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;
} }
private static final double MAX_TYPE_WEIGHT = 10;
// maximum corresponds to the top entry
public double getUnknownPhraseMatchWeight() { public double getUnknownPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it highers // if result is a complete match in the search we prioritize it highers
double res = 0; return getSumPhraseMatchWeight() / Math.pow(MAX_TYPE_WEIGHT, getDepth() - 1);
if (unknownPhraseMatches) {
res = ObjectType.getTypeWeight(objectType);
} }
public double getSumPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it highers
double res = ObjectType.getTypeWeight(objectType);
if (parentSearchResult != null) { if (parentSearchResult != null) {
// 10 > maximum type res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT;
// res = Math.max(res,parentSearchResult.getUnknownPhraseMatchWeight()) ;
res += parentSearchResult.getUnknownPhraseMatchWeight() / 10;
} }
return res; return res;
} }
public int getDepth() {
if (parentSearchResult != null) {
return 1 + parentSearchResult.getDepth();
}
return 1;
}
public int getFoundWordCount() { public int getFoundWordCount() {
int inc = 0; int inc = 0;
if (firstUnknownWordMatches) { if (firstUnknownWordMatches) {
@ -77,16 +99,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

@ -35,6 +35,7 @@ import net.osmand.search.core.SearchPhrase;
import net.osmand.search.core.SearchResult; import net.osmand.search.core.SearchResult;
import net.osmand.search.core.SearchSettings; import net.osmand.search.core.SearchSettings;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class SearchUICoreTest { public class SearchUICoreTest {
@ -99,7 +100,20 @@ public class SearchUICoreTest {
BinaryMapIndexReaderTest reader = new BinaryMapIndexReaderTest(); BinaryMapIndexReaderTest reader = new BinaryMapIndexReaderTest();
JSONObject sourceJson = new JSONObject(sourceJsonText); JSONObject sourceJson = new JSONObject(sourceJsonText);
String phraseText = sourceJson.getString("phrase"); JSONArray phrasesJson = sourceJson.optJSONArray("phrases");
String singlePhrase = sourceJson.optString("phrase", null);
List<String> phrases = new ArrayList<>();
if (singlePhrase != null) {
phrases.add(singlePhrase);
}
if (phrasesJson != null) {
for (int i = 0; i < phrasesJson.length(); i++) {
String phrase = phrasesJson.optString(i);
if (phrase != null) {
phrases.add(phrase);
}
}
}
JSONObject settingsJson = sourceJson.getJSONObject("settings"); JSONObject settingsJson = sourceJson.getJSONObject("settings");
if (sourceJson.has("amenities")) { if (sourceJson.has("amenities")) {
JSONArray amenitiesArr = sourceJson.getJSONArray("amenities"); JSONArray amenitiesArr = sourceJson.getJSONArray("amenities");
@ -135,26 +149,25 @@ public class SearchUICoreTest {
reader.matchedCities = matchedCities; reader.matchedCities = matchedCities;
reader.streetCities = streetCities; reader.streetCities = streetCities;
} }
List<String> results = new ArrayList<>(); List<List<String>> results = new ArrayList<>();
if (sourceJson.has("results")) { for (int i = 0; i < phrases.size(); i++) {
JSONArray resultsArr = sourceJson.getJSONArray("results"); results.add(new ArrayList<String>());
for (int i = 0; i < resultsArr.length(); i++) {
results.add(resultsArr.getString(i));
} }
if (sourceJson.has("results")) {
parseResults(sourceJson, "results", results);
} }
if (TEST_EXTRA_RESULTS && sourceJson.has("extra-results")) { if (TEST_EXTRA_RESULTS && sourceJson.has("extra-results")) {
JSONArray resultsArr = sourceJson.getJSONArray("extra-results"); parseResults(sourceJson, "extra-results", results);
for (int i = 0; i < resultsArr.length(); i++) {
results.add(resultsArr.getString(i));
} }
Assert.assertEquals(phrases.size(), results.size());
if (phrases.size() != results.size()) {
return;
} }
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());
phrase = phrase.generateNewPhrase(phraseText, s);
final SearchUICore core = new SearchUICore(MapPoiTypes.getDefault(), "en", false); final SearchUICore core = new SearchUICore(MapPoiTypes.getDefault(), "en", false);
core.init(); core.init();
@ -169,6 +182,13 @@ public class SearchUICoreTest {
return false; return false;
} }
}; };
boolean simpleTest = true;
SearchPhrase emptyPhrase = SearchPhrase.emptyPhrase(s);
for (int k = 0; k < phrases.size(); k++) {
String text = phrases.get(k);
List<String> result = results.get(k);
SearchPhrase phrase = emptyPhrase.generateNewPhrase(text, s);
SearchResultMatcher matcher = new SearchResultMatcher(rm, phrase, 1, new AtomicInteger(1), -1); SearchResultMatcher matcher = new SearchResultMatcher(rm, phrase, 1, new AtomicInteger(1), -1);
core.searchInternal(phrase, matcher); core.searchInternal(phrase, matcher);
@ -176,24 +196,61 @@ public class SearchUICoreTest {
collection.addSearchResults(matcher.getRequestResults(), true, true); collection.addSearchResults(matcher.getRequestResults(), true, true);
List<SearchResult> searchResults = collection.getCurrentSearchResults(); List<SearchResult> searchResults = collection.getCurrentSearchResults();
int i = 0; int i = 0;
for (SearchResult result : searchResults) { for (SearchResult res : searchResults) {
String expected = results.get(i++); String expected = result.get(i++);
String present = result.toString(); if (simpleTest && expected.indexOf('[') != -1) {
expected = expected.substring(0, expected.indexOf('[')).trim();
}
// String present = result.toString();
String present = formatResult(simpleTest, res, phrase);
if (!Algorithms.stringsEqual(expected, present)) { if (!Algorithms.stringsEqual(expected, present)) {
System.out.println(String.format("Mismatch for '%s' != '%s' (%d, %.3f, %s). Result: ", expected, System.out.println(String.format("Phrase: %s", phrase));
present, result.getFoundWordCount(), result.getUnknownPhraseMatchWeight(), result.objectType.toString())); System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present));
for (SearchResult r : searchResults) { for (SearchResult r : searchResults) {
// System.out.println(String.format("\t\"%s\",", r.toString())); System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase)));
System.out.println(String.format("\"%s\", (%d, %.3f, %s),", r.toString(),
r.getFoundWordCount(), r.getUnknownPhraseMatchWeight(), r.objectType.toString()));
} }
} }
Assert.assertEquals(expected, present); Assert.assertEquals(expected, present);
if (i >= results.size()) { if (i >= result.size()) {
break; break;
} }
} }
} }
}
private void parseResults(JSONObject sourceJson, String tag, List<List<String>> results) {
List<String> result = results.get(0);
JSONArray resultsArr = sourceJson.getJSONArray(tag);
boolean hasInnerArray = resultsArr.length() > 0 && resultsArr.optJSONArray(0) != null;
for (int i = 0; i < resultsArr.length(); i++) {
if (hasInnerArray) {
JSONArray innerArray = resultsArr.optJSONArray(i);
if (innerArray != null && results.size() > i) {
result = results.get(i);
for (int k = 0; k < innerArray.length(); k++) {
result.add(innerArray.getString(k));
}
}
} else {
result.add(resultsArr.getString(i));
}
}
}
private String formatResult(boolean simpleTest, SearchResult r, SearchPhrase phrase) {
if (simpleTest) {
return r.toString().trim();
}
double dist = 0;
if(r.location != null) {
dist = MapUtils.getDistance(r.location, phrase.getLastTokenLocation());
}
return String.format("%s [[%d, %s, %.3f, %.2f km]]", r.toString(),
r.getFoundWordCount(), r.objectType.toString(),
r.getUnknownPhraseMatchWeight(),
dist / 1000
);
}
static class TestSearchTranslator implements MapPoiTypes.PoiTranslator { static class TestSearchTranslator implements MapPoiTypes.PoiTranslator {

View file

@ -9,14 +9,144 @@
"emptyQueryAllowed": false, "emptyQueryAllowed": false,
"sortByName": false "sortByName": false
}, },
"phrase": "100 Bridge Street", "phrases": [ "100 bridge", "100 bridge street", "100 bridge street westbrook" ],
"results": [ "results": [
"100.0, <input> ", [
"100, Bridge Street, Westbrook", "100.0, <input> [[1, PARTIAL_LOCATION, 1.000, 5591.91 km]]",
"100, Bridge Street, Yarmouth", "100, Bridge Street, Westbrook [[2, HOUSE, 0.430, 11.29 km]]",
"Bridge Street", "100, Bridge Street, Yarmouth [[2, HOUSE, 0.430, 23.69 km]]"
"Bridge Street Dam", ],
"Bridge Street" [
"100.0, <input> [[1, PARTIAL_LOCATION, 1.000, 5591.91 km]]",
"100, Bridge Street, Westbrook [[3, HOUSE, 0.430, 11.29 km]]",
"100, Bridge Street, Yarmouth [[3, HOUSE, 0.430, 23.69 km]]"
],
[
"100.0, <input> [[1, PARTIAL_LOCATION, 1.000, 5591.91 km]]",
"100, Bridge Street, Westbrook [[4, HOUSE, 0.043, 11.29 km]]",
"100, Bridge Street, Yarmouth [[3, HOUSE, 0.430, 23.69 km]]",
"Bridge Street, Westbrook [[3, STREET, 0.310, 11.35 km]]",
"Bridge Street, Frenchtown [[2, STREET, 3.000, 11.35 km]]",
"Bridge Street, Yarmouth [[2, STREET, 3.000, 23.44 km]]",
"Bridge Street, Cornish [[2, STREET, 3.000, 27.39 km]]",
"Bridge Street (Ocean Park), Old Orchard Beach [[2, STREET, 3.000, 28.42 km]]",
"Bridge Street (Newfield), West Newfield [[2, STREET, 3.000, 32.66 km]]",
"Bridge Street, Newfield [[2, STREET, 3.000, 32.66 km]]",
"Bridge Street (Sprague City), West Newfield [[2, STREET, 3.000, 32.72 km]]",
"Bridge Street, Sprague City [[2, STREET, 3.000, 33.02 km]]",
"Bridge Street, Kezar Falls [[2, STREET, 3.000, 34.35 km]]",
"Bridge Street (Springvale), Sanford [[2, STREET, 3.000, 41.40 km]]",
"Bridge Street, Springvale [[2, STREET, 3.000, 41.40 km]]",
"Bridge Street, Brunswick [[2, STREET, 3.000, 43.74 km]]",
"Bridge Street, Lewiston [[2, STREET, 3.000, 43.86 km]]",
"Bridge Street, Topsham [[2, STREET, 3.000, 43.93 km]]",
"Bridge Street, Bath [[2, STREET, 3.000, 53.34 km]]",
"Bridge Street, Ogunquit [[2, STREET, 3.000, 56.93 km]]",
"Bridge Street, Berwick [[2, STREET, 3.000, 62.86 km]]",
"Bridge Street, Richmond [[2, STREET, 3.000, 65.70 km]]",
"Bridge Street, Boothbay Harbor [[2, STREET, 3.000, 68.39 km]]",
"Bridge Street, Gardiner [[2, STREET, 3.000, 77.20 km]]",
"Bridge Street (Oak Terrace), Kittery [[2, STREET, 3.000, 77.36 km]]",
"Bridge Street, Randolph [[2, STREET, 3.000, 77.40 km]]",
"Bridge Street, Oak Terrace [[2, STREET, 3.000, 77.41 km]]",
"Bridge Street, Gilead [[2, STREET, 3.000, 82.07 km]]",
"Bridge Street, Livermore Falls [[2, STREET, 3.000, 83.24 km]]",
"Bridge Street, Augusta [[2, STREET, 3.000, 83.82 km]]",
"Bridge Street, Jay [[2, STREET, 3.000, 85.89 km]]"
]
],
"extra-results" : [
[
"Bridge Street, Frenchtown [[1, STREET, 3.000, 11.35 km]]",
"Bridge Street, Westbrook [[1, STREET, 3.000, 11.35 km]]",
"Bridge Street, Yarmouth [[1, STREET, 3.000, 23.44 km]]",
"Bridge Street, Cornish [[1, STREET, 3.000, 27.39 km]]",
"Bridge Street (Ocean Park), Old Orchard Beach [[1, STREET, 3.000, 28.42 km]]",
"Bridge Street (Newfield), West Newfield [[1, STREET, 3.000, 32.66 km]]",
"Bridge Street, Newfield [[1, STREET, 3.000, 32.66 km]]",
"Bridge Street (Sprague City), West Newfield [[1, STREET, 3.000, 32.72 km]]",
"Bridge Street, Sprague City [[1, STREET, 3.000, 33.02 km]]",
"Bridge Street, Kezar Falls [[1, STREET, 3.000, 34.35 km]]",
"Bridge Road, Biddeford [[1, STREET, 3.000, 35.42 km]]",
"Bridge Street (Springvale), Sanford [[1, STREET, 3.000, 41.40 km]]",
"Bridge Street, Springvale [[1, STREET, 3.000, 41.40 km]]",
"Bridge Street, Brunswick [[1, STREET, 3.000, 43.74 km]]",
"Bridge Street, Lewiston [[1, STREET, 3.000, 43.86 km]]",
"Bridge Street, Topsham [[1, STREET, 3.000, 43.93 km]]",
"Bridge Road, Brunswick [[1, STREET, 3.000, 52.12 km]]",
"Bridge Street, Bath [[1, STREET, 3.000, 53.34 km]]",
"Bridge Lane, Ogunquit [[1, STREET, 3.000, 56.91 km]]",
"Bridge Street, Ogunquit [[1, STREET, 3.000, 56.93 km]]",
"Bridge Road, North Waterford [[1, STREET, 3.000, 57.76 km]]",
"Bridge Street, Berwick [[1, STREET, 3.000, 62.86 km]]",
"Bridge Street, Richmond [[1, STREET, 3.000, 65.70 km]]",
"Bridge Road, Edgecomb [[1, STREET, 3.000, 68.32 km]]",
"Bridge Road, Wiscasset [[1, STREET, 3.000, 68.34 km]]",
"Bridge Street, Boothbay Harbor [[1, STREET, 3.000, 68.39 km]]",
"Bridge Street, Gardiner [[1, STREET, 3.000, 77.20 km]]",
"Bridge Street (Oak Terrace), Kittery [[1, STREET, 3.000, 77.36 km]]",
"Bridge Street, Randolph [[1, STREET, 3.000, 77.40 km]]",
"Bridge Street, Oak Terrace [[1, STREET, 3.000, 77.41 km]]",
"Bridge Street, Gilead [[1, STREET, 3.000, 82.07 km]]",
"Bridge Street, Livermore Falls [[1, STREET, 3.000, 83.24 km]]",
"Bridge Street, Augusta [[1, STREET, 3.000, 83.82 km]]",
"Bridge Street, Jay [[1, STREET, 3.000, 85.89 km]]"
],
[
"Bridge Street, Frenchtown [[2, STREET, 3.000, 11.35 km]]",
"Bridge Street, Westbrook [[2, STREET, 3.000, 11.35 km]]",
"Bridge Street, Yarmouth [[2, STREET, 3.000, 23.44 km]]",
"Bridge Street, Cornish [[2, STREET, 3.000, 27.39 km]]",
"Bridge Street (Ocean Park), Old Orchard Beach [[2, STREET, 3.000, 28.42 km]]",
"Bridge Street (Newfield), West Newfield [[2, STREET, 3.000, 32.66 km]]",
"Bridge Street, Newfield [[2, STREET, 3.000, 32.66 km]]",
"Bridge Street (Sprague City), West Newfield [[2, STREET, 3.000, 32.72 km]]",
"Bridge Street, Sprague City [[2, STREET, 3.000, 33.02 km]]",
"Bridge Street, Kezar Falls [[2, STREET, 3.000, 34.35 km]]",
"Bridge Street (Springvale), Sanford [[2, STREET, 3.000, 41.40 km]]",
"Bridge Street, Springvale [[2, STREET, 3.000, 41.40 km]]",
"Bridge Street, Brunswick [[2, STREET, 3.000, 43.74 km]]",
"Bridge Street, Lewiston [[2, STREET, 3.000, 43.86 km]]",
"Bridge Street, Topsham [[2, STREET, 3.000, 43.93 km]]",
"Bridge Street, Bath [[2, STREET, 3.000, 53.34 km]]",
"Bridge Street, Ogunquit [[2, STREET, 3.000, 56.93 km]]",
"Bridge Street, Berwick [[2, STREET, 3.000, 62.86 km]]",
"Bridge Street, Richmond [[2, STREET, 3.000, 65.70 km]]",
"Bridge Street, Boothbay Harbor [[2, STREET, 3.000, 68.39 km]]",
"Bridge Street, Gardiner [[2, STREET, 3.000, 77.20 km]]",
"Bridge Street (Oak Terrace), Kittery [[2, STREET, 3.000, 77.36 km]]",
"Bridge Street, Randolph [[2, STREET, 3.000, 77.40 km]]",
"Bridge Street, Oak Terrace [[2, STREET, 3.000, 77.41 km]]",
"Bridge Street, Gilead [[2, STREET, 3.000, 82.07 km]]",
"Bridge Street, Livermore Falls [[2, STREET, 3.000, 83.24 km]]",
"Bridge Street, Augusta [[2, STREET, 3.000, 83.82 km]]",
"Bridge Street, Jay [[2, STREET, 3.000, 85.89 km]]",
"Bridge Street [[2, POI, 2.000, 11.59 km]]",
"Bridge Street Dam [[2, POI, 2.000, 23.62 km]]",
"Bridge Street [[2, POI, 2.000, 27.24 km]]",
"Bridge Street [[2, POI, 2.000, 34.36 km]]",
"Bridge Street [[2, POI, 2.000, 41.33 km]]",
"Bridge Street Dam [[2, POI, 2.000, 41.35 km]]",
"Bridge Street [[2, POI, 2.000, 43.84 km]]",
"Bridge Street [[2, POI, 2.000, 76.87 km]]",
"Bridge Street [[2, POI, 2.000, 77.27 km]]",
"Bridge Street [[2, POI, 2.000, 82.37 km]]",
"Bridge Street [[2, POI, 2.000, 88.20 km]]",
"The Bridge Street Green [[2, POI, 2.000, 104.21 km]]",
"Bridge Street [[2, POI, 2.000, 104.29 km]]",
"Bridge Street [[2, POI, 2.000, 110.92 km]]",
"Bridge Street [[2, POI, 2.000, 116.14 km]]",
"Bridge Street [[2, POI, 2.000, 116.20 km]]",
"Bridge Street [[2, POI, 2.000, 116.26 km]]",
"Bridge Street [[2, POI, 2.000, 119.68 km]]",
"Bridge Street [[2, POI, 2.000, 151.84 km]]",
"Bridge Street [[2, POI, 2.000, 224.29 km]]",
"Bridge Street [[2, POI, 2.000, 243.40 km]]",
"Bridge Street [[2, POI, 2.000, 394.32 km]]",
"Bridge Street [[2, POI, 2.000, 415.17 km]]",
"Bridge Street [[2, POI, 2.000, 434.56 km]]"
],
[]
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,25 +11,24 @@
}, },
"phrase": "Bank dr", "phrase": "Bank dr",
"results": [ "results": [
"Bank (Finance)", "Bank (Finance) [[1, POI_TYPE, 1.000, 0.00 km]]",
"Hohe-Bank-Weg, Königswartha - Rakecy", "Dresdner Bank [[2, POI, 2.000, 0.10 km]]",
"Dresdner Bank", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 1.46 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 2.15 km]]",
"Ostsächsische Sparkasse Dresden", "Filiale Dresden Technische Universität [[2, POI, 2.000, 2.61 km]]",
"Filiale Dresden Technische Universität", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 2.68 km]]",
"Ostsächsische Sparkasse Dresden", "Volksbank Raiffeisenbank Dresden [[2, POI, 2.000, 2.77 km]]",
"Volksbank Raiffeisenbank Dresden", "Ostsächsische Sparkasse Dresden Zwst. Strehlen [[2, POI, 2.000, 2.86 km]]",
"Ostsächsische Sparkasse Dresden Zwst. Strehlen", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 3.42 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 3.74 km]]",
"Ostsächsische Sparkasse Dresden", "Dresdner Volksbank Raiffeisenbank [[2, POI, 2.000, 4.72 km]]",
"Dresdner Volksbank Raiffeisenbank", "Ostsächsische Sparkasse Filiale Dresden Wilder Mann [[2, POI, 2.000, 5.06 km]]",
"Ostsächsische Sparkasse Filiale Dresden Wilder Mann", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 7.42 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 7.44 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 7.57 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 8.06 km]]",
"Ostsächsische Sparkasse Dresden", "Ostsächsische Sparkasse Dresden [[2, POI, 2.000, 8.83 km]]",
"Ostsächsische Sparkasse Dresden", "Dresdner Volksbank Raiffeisenbank eG [[2, POI, 2.000, 8.97 km]]"
"Dresdner Volksbank Raiffeisenbank eG"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,17 +11,26 @@
}, },
"phrase": "Burger King", "phrase": "Burger King",
"results": [ "results": [
"Burger (Cafe / Cafe and restaurant)", "Burger King Thiendorf [[2, POI, 2.000, 46.35 km]]",
"Burger (Pub / Food)", "Burger King [[2, POI, 2.000, 46.75 km]]",
"Burger (Bar / Food)", "Burger King [[2, POI, 2.000, 57.61 km]]",
"Burger (Restaurant / Cafe and restaurant)", "Burger King [[2, POI, 2.000, 58.23 km]]",
"Burger (Biergarten / Food)", "Burger King [[2, POI, 2.000, 59.20 km]]",
"Burger (Fast food / Food)", "Burger King [[2, POI, 2.000, 66.93 km]]",
"Burger King", "Burger King Riesa [[2, POI, 2.000, 78.15 km]]",
"Burger King", "Burger King [[2, POI, 2.000, 118.29 km]]",
"Burger King", "Bürger King Chemnitz [[2, POI, 2.000, 121.13 km]]",
"Burger King", "Burger King Chemnitz [[2, POI, 2.000, 123.17 km]]",
"Burger King" "Burger King [[2, POI, 2.000, 135.11 km]]",
"Burger King [[2, POI, 2.000, 139.54 km]]",
"Burger King [[2, POI, 2.000, 139.98 km]]",
"Burger King [[2, POI, 2.000, 140.17 km]]",
"Burger King Glauchau [[2, POI, 2.000, 142.15 km]]",
"Burger King [[2, POI, 2.000, 144.43 km]]",
"Burger King [[2, POI, 2.000, 146.38 km]]",
"Burger King [[2, POI, 2.000, 147.72 km]]",
"Burger King [[2, POI, 2.000, 148.27 km]]",
"Burger King [[2, POI, 2.000, 151.57 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,25 +11,70 @@
}, },
"phrase": "carrer de Vic, Sant Bartomeu del grau", "phrase": "carrer de Vic, Sant Bartomeu del grau",
"results": [ "results": [
"Carrer de Sant Bartomeu del Grau, Vic", "Carrer de Vic, Sant Bartomeu del Grau [[7, STREET, 0.310, 64.33 km]]",
"Carrer de Vic, Sant Bartomeu del Grau", "Carrer de Sant Bartomeu del Grau, Vic [[7, STREET, 0.310, 61.63 km]]"
"carrer Ponent, Sant Bartomeu del Grau",
"Carrer Pla de l'Oratori, Sant Bartomeu del Grau",
"carrer de Dalt, Sant Bartomeu del Grau",
"Carrer de la Migjorn, Sant Bartomeu del Grau",
"Carrer de la Tramuntana, Sant Bartomeu del Grau",
"Carrer de la Codina (Xalet Mas Reig), Sant Bartomeu del Grau",
"Carrer de Sant Bartomeu, Sant Cugat del Vallès",
"Carretera de Sant Bartomeu del Grau, Muntanyola",
"Carretera de Sant Bartomeu del Grau, Sant Bartomeu del Grau",
"Carretera de Sant Bartomeu, Sant Bartomeu del Grau",
"Carretera de Sant Bartomeu del Grau, Xalet Mas Reig",
"Camí de St. Bartomeu al Sorreig (Xalet Mas Reig), Sant Bartomeu del Grau",
"Carrer Tres Creus, Sant Bartomeu del Grau",
"Carrer del Mig, Sant Bartomeu del Grau",
"carrer Vell, Sant Bartomeu del Grau",
"Carrer Nou, Sant Bartomeu del Grau"
], ],
"extra-results": [
"carrer Ponent, Sant Bartomeu del Grau [[6, STREET, 0.310, 64.29 km]]",
"Carrer Pla de l'Oratori, Sant Bartomeu del Grau [[6, STREET, 0.310, 64.38 km]]",
"carrer de Dalt, Sant Bartomeu del Grau [[6, STREET, 0.310, 64.44 km]]",
"Carrer de la Migjorn, Sant Bartomeu del Grau [[6, STREET, 0.310, 64.78 km]]",
"Carrer de la Tramuntana, Sant Bartomeu del Grau [[6, STREET, 0.310, 64.83 km]]",
"Carrer de la Codina (Xalet Mas Reig), Sant Bartomeu del Grau [[6, STREET, 0.310, 64.85 km]]",
"Carretera de Sant Bartomeu del Grau, Muntanyola [[5, STREET, 3.000, 61.03 km]]",
"Carretera de Sant Bartomeu del Grau, Sant Bartomeu del Grau [[5, STREET, 3.000, 63.00 km]]",
"Carretera de Sant Bartomeu del Grau, Xalet Mas Reig [[5, STREET, 3.000, 64.71 km]]",
"Carrer de Sant Bartomeu, Sant Cugat del Vallès [[5, STREET, 0.310, 11.20 km]]",
"Carrer Tres Creus, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.34 km]]",
"Carrer del Mig, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.43 km]]",
"carrer Vell, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.47 km]]",
"Carrer Nou, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.54 km]]",
"Carrer Llevant, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.76 km]]",
"Carrer del Garbí, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.79 km]]",
"Carrer del Gregal, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.80 km]]",
"Carrer del Xaloc, Sant Bartomeu del Grau [[5, STREET, 0.310, 64.90 km]]",
"Túnel de la Fontfreda (Pere-riera), Sant Bartomeu del Grau [[5, STREET, 0.310, 56.61 km]]",
"Eix Transversal C-25 Viaducte de Pere-riera, Sant Bartomeu del Grau [[5, STREET, 0.310, 57.32 km]]",
"Camí de Ca la Burra, Sant Bartomeu del Grau [[5, STREET, 0.310, 57.58 km]]",
"Camí de Sant Genís, Sant Bartomeu del Grau [[5, STREET, 0.310, 63.08 km]]",
"Camí de Rogers, Sant Bartomeu del Grau [[5, STREET, 0.310, 63.60 km]]",
"Carretera de Sant Bartomeu, Sant Bartomeu del Grau [[5, STREET, 0.310, 63.68 km]]",
"Camí de St. Bartomeu al Sorreig (Xalet Mas Reig), Sant Bartomeu del Grau [[5, STREET, 0.310, 65.11 km]]",
"Carrer de Sant Bartomeu, Martorell [[4, STREET, 3.000, 6.20 km]]",
"Carrer de Sant Bartomeu de la Quadra (les Corts), Barcelona [[4, STREET, 3.000, 12.07 km]]",
"Carrer de Sant Bartomeu (el Raval), Barcelona [[4, STREET, 3.000, 17.67 km]]",
"Carrer de Sant Bartomeu (Sant Antoni de Llefià), Badalona [[4, STREET, 3.000, 20.95 km]]",
"Carrer de Sant Bartomeu (Sitges), Garraf [[4, STREET, 3.000, 24.54 km]]",
"Carrer de Sant Bartomeu, Vallromanes [[4, STREET, 3.000, 29.73 km]]",
"Carrer de Sant Bartomeu, Granollers [[4, STREET, 3.000, 33.57 km]]",
"Carrer de Sant Bartomeu, Igualada [[4, STREET, 3.000, 33.65 km]]",
"Carrer de Sant Bartomeu (Les Escodines), Manresa [[4, STREET, 3.000, 35.11 km]]",
"Carrer de Sant Bartomeu, Navarcles [[4, STREET, 3.000, 37.02 km]]",
"Carrer de Sant Bartomeu, Cabrera de Mar [[4, STREET, 3.000, 38.13 km]]",
"Carrer de Sant Bartomeu, Santa Oliva [[4, STREET, 3.000, 41.03 km]]",
"Carrer de Sant Bartomeu, Masarbonès [[4, STREET, 3.000, 47.72 km]]",
"Carrer de Sant Bartomeu (Masarbonès), Masllorenç [[4, STREET, 3.000, 47.72 km]]",
"Carrer de Sant Bartomeu (els Hostalets de Balenyà), Balenyà [[4, STREET, 3.000, 48.45 km]]",
"Carrer de Sant Bartomeu, Vistabella [[4, STREET, 3.000, 63.26 km]]",
"Carrer de Sant Bartomeu, Mas de Bondia [[4, STREET, 3.000, 67.50 km]]",
"Carrer de Sant Bartomeu (Mas de Bondia), Montornès de Segarra [[4, STREET, 3.000, 67.50 km]]",
"Carrer de Sant Bartomeu, l'Esquirol [[4, STREET, 3.000, 75.82 km]]",
"Carrer de Sant Bartomeu (Les Planes), l'Esquirol [[4, STREET, 3.000, 76.88 km]]",
"Carrer de Sant Bartomeu, Lloret de Mar [[4, STREET, 3.000, 79.60 km]]",
"Carrer de Sant Bartomeu, Coll de Nargó [[4, STREET, 3.000, 99.35 km]]",
"Carrer de Sant Bartomeu, Camallera [[4, STREET, 3.000, 113.48 km]]",
"Sant Bartomeu del Grau [[4, POI, 2.000, 64.32 km]]",
"Sant Bartomeu del Grau [[4, POI, 2.000, 64.60 km]]",
"Carrer Bartomeu Garcia i Subirà, Sant Boi de Llobregat [[4, STREET, 0.310, 11.59 km]]",
"Carretera de Sant Bartomeu, l'Ametlla del Vallès [[4, STREET, 0.310, 37.92 km]]",
"Camí d'Alboquers (Pere-riera), Sant Bartomeu del Grau [[4, STREET, 0.310, 58.08 km]]",
"Eix Transversal, Sant Bartomeu del Grau [[4, STREET, 0.310, 59.04 km]]",
"GR 3, Sant Bartomeu del Grau [[4, STREET, 0.310, 64.08 km]]",
"Passeig del Grau, Sant Bartomeu del Grau [[4, STREET, 0.310, 64.28 km]]",
"Plaça del Doctor Griera, Sant Bartomeu del Grau [[4, STREET, 0.310, 64.36 km]]",
"Carretera del Cementiri, Sant Bartomeu del Grau [[4, STREET, 0.310, 64.42 km]]"
],
"amenities": [ "amenities": [
{ {
"name": "Collada de Sant Bartomeu", "name": "Collada de Sant Bartomeu",

View file

@ -11,22 +11,58 @@
}, },
"phrase": "parking ", "phrase": "parking ",
"results": [ "results": [
"Parking (Personal transport)", "Parking (Personal transport) [[1, POI_TYPE, 1.000, 0.00 km]]",
"Parking entrance (Personal transport)", "для посетителей [[0, POI, 2.000, 0.03 km]]",
"Parking fee (Charging station / Transportation)", "Parking [[0, POI, 2.000, 0.05 km]]",
"Parking fee: no (Charging station / Transportation)", "Parking [[0, POI, 2.000, 0.11 km]]",
"Parking fee: yes (Charging station / Transportation)", "Parking [[0, POI, 2.000, 0.16 km]]",
"Parking lot (Fire hydrant / Emergency infrastructure)", "Parking [[0, POI, 2.000, 0.17 km]]",
"Parking space (Personal transport)", "Parking [[0, POI, 2.000, 0.23 km]]",
"Parking tickets (Vending machine / Store)", "Parking [[0, POI, 2.000, 0.35 km]]",
"Parking tickets (Vending machine / Store)", "Parking [[0, POI, 2.000, 0.40 km]]",
"Parking time limit (Parking / Personal transport)", "Parking [[0, POI, 2.000, 0.48 km]]",
"Bicycle parking (Bicycle transport)", "Parking [[0, POI, 2.000, 0.49 km]]",
"Motorcycle parking (Personal transport)", "Parking [[0, POI, 2.000, 0.55 km]]",
"Parking", "Автостоянка №1 [[0, POI, 2.000, 0.56 km]]",
"Parking", "Parking [[0, POI, 2.000, 0.58 km]]",
"Parking", "Parking [[0, POI, 2.000, 0.61 km]]",
"Parking" "Parking [[0, POI, 2.000, 0.72 km]]",
"Parking [[0, POI, 2.000, 0.81 km]]",
"Parking [[0, POI, 2.000, 0.81 km]]",
"Parking [[0, POI, 2.000, 0.85 km]]",
"для клиентов [[0, POI, 2.000, 0.89 km]]",
"Parking [[0, POI, 2.000, 0.93 km]]",
"Parking [[0, POI, 2.000, 0.94 km]]",
"Заинская ГРЭС [[0, POI, 2.000, 1.01 km]]",
"Parking [[0, POI, 2.000, 1.02 km]]",
"Южная [[0, POI, 2.000, 1.03 km]]",
"Parking [[0, POI, 2.000, 1.06 km]]",
"Parking [[0, POI, 2.000, 1.09 km]]",
"Parking [[0, POI, 2.000, 1.10 km]]",
"Служебная [[0, POI, 2.000, 1.14 km]]",
"Parking [[0, POI, 2.000, 1.20 km]]",
"Parking [[0, POI, 2.000, 1.21 km]]",
"Parking [[0, POI, 2.000, 1.36 km]]",
"Parking [[0, POI, 2.000, 1.44 km]]",
"Три тополя [[0, POI, 2.000, 1.47 km]]",
"Parking [[0, POI, 2.000, 1.53 km]]",
"Parking [[0, POI, 2.000, 1.56 km]]",
"Parking [[0, POI, 2.000, 1.62 km]]",
"Parking [[0, POI, 2.000, 1.85 km]]",
"Штрафстоянка (Эвакуатор) [[0, POI, 2.000, 2.03 km]]",
"Parking [[0, POI, 2.000, 2.05 km]]",
"для регистрации в ГИБДД [[0, POI, 2.000, 2.06 km]]",
"Parking [[0, POI, 2.000, 2.06 km]]",
"Parking [[0, POI, 2.000, 2.07 km]]",
"для техосмотра [[0, POI, 2.000, 2.09 km]]",
"Parking [[0, POI, 2.000, 2.18 km]]",
"Parking [[0, POI, 2.000, 2.55 km]]",
"Parking [[0, POI, 2.000, 3.40 km]]",
"Parking [[0, POI, 2.000, 3.41 km]]",
"Parking [[0, POI, 2.000, 3.41 km]]",
"Parking [[0, POI, 2.000, 3.45 km]]",
"Parking [[0, POI, 2.000, 4.29 km]]",
"Parking [[0, POI, 2.000, 6.71 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,17 +11,18 @@
}, },
"phrase": "48 Free Street Portland", "phrase": "48 Free Street Portland",
"results": [ "results": [
"48.0, <input> ", "48.0, <input> [[0, PARTIAL_LOCATION, 1.000, 5274.99 km]]",
"48, Free Street (Downtown), Portland" "48, Free Street (Downtown), Portland [[4, HOUSE, 0.043, 0.09 km]]",
"48, Portland Street, North Berwick [[3, HOUSE, 0.430, 54.48 km]]",
"Free Street (Downtown), Portland [[3, STREET, 0.310, 0.03 km]]",
"Free Street (Ferry Village), South Portland [[3, STREET, 0.310, 1.69 km]]",
], ],
"extra-results": [ "extra-results": [
"48, Portland Street, North Berwick", "Portland Street (Downtown), Portland [[2, STREET, 3.000, 0.62 km]]",
"Free Street (Downtown), Portland", "Portland Street Pier, South Portland [[2, STREET, 3.000, 1.43 km]]",
"Free Street (Ferry Village), South Portland", "Portland Street, Yarmouth [[2, STREET, 3.000, 16.13 km]]",
"Portland Street", "Portland Street, North Berwick [[2, STREET, 3.000, 54.37 km]]",
"Portland Street (Downtown), Portland", "Portland Street, Berwick [[2, STREET, 3.000, 59.60 km]]"
"Portland Street Pier, South Portland",
"Portland Street, Yarmouth"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,9 +11,9 @@
}, },
"phrase": "Київ Саксаганського вулиця 32", "phrase": "Київ Саксаганського вулиця 32",
"results": [ "results": [
"32, Саксаганського вулиця, Київ", "32, Саксаганського вулиця, Київ [[3, HOUSE, 0.430, 1.79 km]]",
"Саксаганського вулиця, Київ", "Саксаганського вулиця, Київ [[2, STREET, 3.000, 1.61 km]]",
"вул. Саксаганського (на вимогу)" "вул. Саксаганського (на вимогу) [[1, POI, 2.000, 1.61 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,69 +11,28 @@
}, },
"phrase": "Calle de las eras 5, Navacerrada", "phrase": "Calle de las eras 5, Navacerrada",
"results": [ "results": [
"5, Calle de las Eras (Uranización Los Corales), Navacerrada" "5, Calle de las Eras (Uranización Los Corales), Navacerrada [[6, HOUSE, 0.043, 70.17 km]]",
"Calle de las Eras (Uranización Los Corales), Navacerrada [[5, STREET, 0.310, 70.15 km]]"
], ],
"extra-results": [ "extra-results": [
"Calle de las Eras (Uranización Los Corales), Navacerrada", "5, Calle Navacerrada (Urb. Las Suertes), Las Suertes [[4, HOUSE, 0.430, 60.50 km]]",
"Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada", "50, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.37 km]]",
"Calle del Puerto de Navacerrada, Las Nieves", "52, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"5, Calle Navacerrada (Urb. Las Suertes), Las Suertes", "53, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.38 km]]",
"50, Calle de Francisco Navacerrada, Salamanca", "54, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"52, Calle de Francisco Navacerrada, Salamanca", "55, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.38 km]]",
"53, Calle de Francisco Navacerrada, Salamanca", "56, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"54, Calle de Francisco Navacerrada, Salamanca", "57, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.37 km]]",
"55, Calle de Francisco Navacerrada, Salamanca", "58, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.35 km]]",
"56, Calle de Francisco Navacerrada, Salamanca", "59, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.35 km]]",
"57, Calle de Francisco Navacerrada, Salamanca", "Pasaje de las Eras (Uranización Los Corales), Navacerrada [[4, STREET, 0.310, 70.23 km]]",
"58, Calle de Francisco Navacerrada, Salamanca", "Calle del Puerto de Navacerrada, Las Nieves [[4, STREET, 0.310, 33.80 km]]",
"59, Calle de Francisco Navacerrada, Salamanca", "Calle Barrio de las Peñas, Navacerrada [[4, STREET, 0.310, 70.10 km]]",
"Pasaje de las Eras (Uranización Los Corales), Navacerrada", "Calle de las Cruces (Residencial Sanabria), Navacerrada [[4, STREET, 0.310, 70.14 km]]",
"Calle Barrio de las Peñas, Navacerrada", "Calle de las Escuelas, Navacerrada [[4, STREET, 0.310, 70.17 km]]",
"Calle de las Cruces (Residencial Sanabria), Navacerrada", "Calle de las Huertas (Residencial Sanabria), Navacerrada [[4, STREET, 0.310, 70.18 km]]",
"Calle de las Escuelas, Navacerrada", "Calle de la Virgen de las Nieves, Puerto de Navacerrada [[4, STREET, 0.310, 74.59 km]]",
"Calle de las Huertas (Residencial Sanabria), Navacerrada", "Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada [[4, STREET_INTERSECTION, 0.043, 70.23 km]]"
"Calle de la Virgen de las Nieves, Puerto de Navacerrada",
"Calle Puerto de Navacerrada, La Poveda",
"Calle del Embalse de Navacerrada, Villa de Vallecas",
"Calle del Puerto de Navacerrada, Puente de Vallecas",
"Calle de Francisco Navacerrada, Salamanca",
"Calle de Navacerrada, Moraleja de Enmedio",
"Calle Navacerrada (Urb. Las Suertes), Las Suertes",
"Calle Puerto de Navacerrada, Roman Candelas",
"Calle Navacerrada, Becerril de la Sierra",
"Carretera de Collado Villalba a Navacerrada, El Baillo y las Hojarascas",
"Calle de Ángel Rojas, Navacerrada",
"Calle de los Robles (Uranización Los Corales), Navacerrada",
"Calle de los Enebros (Uranización Los Corales), Navacerrada",
"Calle de la Bola del Mundo (Residencial Sanabria), Navacerrada",
"Calle de la Maliciosa (Residencial Sanabria), Navacerrada",
"Calle de la Perdiz, Navacerrada",
"Calle de la Magdalena, Navacerrada",
"Calle las Jaras, Navacerrada",
"Calle de la Audiencia, Navacerrada",
"Calle de Prado Jerez, Navacerrada",
"Calle de Carmen Conde (Residencial Sanabria), Navacerrada",
"Calle de la Iglesia, Navacerrada",
"Calle de la Tejera, Navacerrada",
"Calle de la Encinilla, Navacerrada",
"Calle de la Canaleja (Residencial Sanabria), Navacerrada",
"Calle de Rafael Alvarado, Navacerrada",
"Calle de Andrés Segovia, Navacerrada",
"Calle de los Pradillos (Residencial Sanabria), Navacerrada",
"Calle de Abel, Navacerrada",
"Calle Praderas de San Sebastián, Navacerrada",
"Calle de San Sebastián (Residencial Sanabria), Navacerrada",
"Calle de Álvaro Iglesia, Navacerrada",
"Calle de los Arcos, Navacerrada",
"Calle de Peñalara, Puerto de Navacerrada",
"Calle de la Bola del Mundo, Puerto de Navacerrada",
"Calle de la Estación, Puerto de Navacerrada",
"Calle Ginos, Puerto de Navacerrada",
"Calle Vitoria, Puerto de Navacerrada",
"Calle Dos Castillas, Puerto de Navacerrada",
"Travesía de las Huertas, Navacerrada",
"Vereda de las Encinillas, Navacerrada",
"Centro Municipal de Mayores «Navacerrada»"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,7 +11,7 @@
}, },
"phrase": "QHW6+CQ", "phrase": "QHW6+CQ",
"results": [ "results": [
"55.796062, 37.56194" "55.796062, 37.56194 [[1, LOCATION, 1.000, 6.52 km]]"
], ],
"cities": [] "cities": []
} }

View file

@ -11,16 +11,64 @@
}, },
"phrase": "Biergarten ", "phrase": "Biergarten ",
"results": [ "results": [
"Biergarten (Food)", "Biergarten (Food) [[1, POI_TYPE, 1.000, 0.00 km]]",
"Biergarten Italienisches Dörfchen", "Biergarten Italienisches Dörfchen [[1, POI, 2.000, 0.55 km]]",
"Biergarten Narrenhäus'l", "Biergarten Narrenhäus'l [[1, POI, 2.000, 0.84 km]]",
"Biergarten Elbsegler", "Biergarten Elbsegler [[1, POI, 2.000, 0.89 km]]",
"Biergarten Elbsegler", "Biergarten Elbsegler [[1, POI, 2.000, 0.90 km]]",
"Biergarten", "Körnergarten [[1, POI, 2.000, 5.18 km]]",
"Biergarten", "Biergarten Goldener Anker [[1, POI, 2.000, 9.78 km]]",
"Biergarten", "Palais Bistro [[0, POI, 2.000, 0.29 km]]",
"Biergarten", "Augustus Garten am Narrenhäusl [[0, POI, 2.000, 0.88 km]]",
"Biergarten" "Zum Schießhaus [[0, POI, 2.000, 0.96 km]]",
"Biergarten [[0, POI, 2.000, 1.24 km]]",
"Wachstube [[0, POI, 2.000, 1.24 km]]",
"Torwirtschaft [[0, POI, 2.000, 1.27 km]]",
"Altes Wettbüro [[0, POI, 2.000, 1.77 km]]",
"Bottoms Up [[0, POI, 2.000, 2.16 km]]",
"Louisengarten [[0, POI, 2.000, 2.20 km]]",
"Biergarten [[0, POI, 2.000, 2.28 km]]",
"Fährgarten Johannstadt [[0, POI, 2.000, 2.42 km]]",
"Carolaschlösschen [[0, POI, 2.000, 2.53 km]]",
"Alt-Dresden [[0, POI, 2.000, 2.75 km]]",
"Biergarten [[0, POI, 2.000, 2.90 km]]",
"Café & Restaurant Saite [[0, POI, 2.000, 3.09 km]]",
"Brauhaus am Waldschlößchen [[0, POI, 2.000, 3.45 km]]",
"Brauhaus Watzke [[0, POI, 2.000, 3.51 km]]",
"el Horst [[0, POI, 2.000, 3.67 km]]",
"Biergarten [[0, POI, 2.000, 3.74 km]]",
"Spitzwegerich [[0, POI, 2.000, 3.81 km]]",
"Biergarten [[0, POI, 2.000, 3.88 km]]",
"Biergarten [[0, POI, 2.000, 4.46 km]]",
"Trobischhof [[0, POI, 2.000, 4.48 km]]",
"Biergarten [[0, POI, 2.000, 4.80 km]]",
"Biergarten [[0, POI, 2.000, 4.91 km]]",
"Schillergarten [[0, POI, 2.000, 4.97 km]]",
"Biergarten [[0, POI, 2.000, 5.11 km]]",
"Biergarten [[0, POI, 2.000, 5.13 km]]",
"Demnitz Elbegarten [[0, POI, 2.000, 5.16 km]]",
"Körnergarten [[0, POI, 2.000, 5.18 km]]",
"Biergarten [[0, POI, 2.000, 5.31 km]]",
"Trachauer Sommergarten [[0, POI, 2.000, 5.31 km]]",
"Biergarten [[0, POI, 2.000, 5.91 km]]",
"Biergarten [[0, POI, 2.000, 6.12 km]]",
"Biergarten [[0, POI, 2.000, 6.26 km]]",
"Biergarten [[0, POI, 2.000, 6.42 km]]",
"Biergarten [[0, POI, 2.000, 6.88 km]]",
"Biergarten [[0, POI, 2.000, 7.11 km]]",
"Straußenwirtschaft Weingut Pesterwitz [[0, POI, 2.000, 7.14 km]]",
"Klotzscher Sommerwirtschaft [[0, POI, 2.000, 7.16 km]]",
"Biergarten [[0, POI, 2.000, 7.17 km]]",
"Zacke [[0, POI, 2.000, 8.20 km]]",
"Weingut Seifert [[0, POI, 2.000, 8.50 km]]",
"Biergarten [[0, POI, 2.000, 8.82 km]]",
"Biergarten [[0, POI, 2.000, 9.11 km]]",
"Biergarten [[0, POI, 2.000, 9.23 km]]",
"Landgut Hofewiese [[0, POI, 2.000, 9.40 km]]",
"Biergarten Goldener Anker [[0, POI, 2.000, 9.78 km]]",
"Biergarten [[0, POI, 2.000, 10.00 km]]",
"Biergarten [[0, POI, 2.000, 10.22 km]]",
"Besenwirtschaft Steinrücken [[0, POI, 2.000, 10.85 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,161 +11,168 @@
}, },
"phrase": "spring street", "phrase": "spring street",
"results": [ "results": [
"Spring (Natural)", "Spring (Natural) [[1, POI_TYPE, 1.000, 0.00 km]]",
"Spring (Spring / Natural)", "Spring Street, South Nyack [[2, STREET, 3.000, 10.57 km]]",
"Spring (Ice rink / Sport)", "Spring Street, Tomkins Cove [[2, STREET, 3.000, 16.77 km]]",
"Spring (Bridge / Transport construction)", "Spring Street, Southfields [[2, STREET, 3.000, 18.10 km]]",
"Spring Street, South Nyack", "Spring Street, Hastings-on-Hudson [[2, STREET, 3.000, 18.94 km]]",
"Spring Street, Tomkins Cove", "Spring Street, Pleasantville [[2, STREET, 3.000, 20.89 km]]",
"Spring Street, Southfields", "Spring Street (Mount Pleasant), Hawthorne [[2, STREET, 3.000, 21.20 km]]",
"Spring Street, Hastings-on-Hudson", "Spring Street, Durland [[2, STREET, 3.000, 28.46 km]]",
"Spring Street, Pleasantville", "Spring Street, Warwick [[2, STREET, 3.000, 30.94 km]]",
"Spring Street (Mount Pleasant), Hawthorne", "Spring Street, Nelsonville [[2, STREET, 3.000, 35.60 km]]",
"Spring Street, Durland", "Spring Street, Goshen [[2, STREET, 3.000, 40.16 km]]",
"Spring Street, Warwick", "Spring Street (Little Italy), Manhattan [[2, STREET, 3.000, 43.76 km]]",
"Spring Street, Nelsonville", "Spring Street, Maybrook [[2, STREET, 3.000, 43.78 km]]",
"Spring Street, Goshen", "West Spring Street, Maybrook [[2, STREET, 3.000, 43.83 km]]",
"Spring Street (Little Italy), Manhattan", "Spring Street, South Salem [[2, STREET, 3.000, 44.74 km]]",
"Spring Street, Maybrook", "Spring Street, Groveville [[2, STREET, 3.000, 45.81 km]]",
"West Spring Street, Maybrook", "Spring Street, East Middletown [[2, STREET, 3.000, 47.95 km]]",
"Spring Street, South Salem", "Spring Street, Montgomery [[2, STREET, 3.000, 48.53 km]]",
"Spring Street, Groveville", "Spring Street, Chelsea [[2, STREET, 3.000, 49.19 km]]",
"Spring Street, East Middletown", "Spring Street, Wappingers Falls [[2, STREET, 3.000, 55.17 km]]",
"Spring Street, Montgomery", "Spring Street, Cold Spring Harbor [[2, STREET, 3.000, 56.10 km]]",
"Spring Street, Chelsea", "Spring Street, Staten Island [[2, STREET, 3.000, 56.86 km]]",
"Spring Street, Wappingers Falls", "Spring Street, East Meadow [[2, STREET, 3.000, 59.81 km]]",
"Spring Street, Cold Spring Harbor", "Spring Street, Inwood [[2, STREET, 3.000, 60.63 km]]",
"Spring Street, Staten Island", "Spring Street, Port Jervis [[2, STREET, 3.000, 61.24 km]]",
"Spring Street, East Meadow", "Spring Street, Roosevelt [[2, STREET, 3.000, 61.89 km]]",
"Spring Street, Inwood", "Spring Street, Pawling [[2, STREET, 3.000, 62.39 km]]",
"Spring Street, Port Jervis", "Spring Street, Fairview [[2, STREET, 3.000, 68.69 km]]",
"Spring Street, Roosevelt", "Spring Street (Wyandanch), Wheatley Heights [[2, STREET, 3.000, 69.75 km]]",
"Spring Street, Pawling", "Spring Street, Wyandanch [[2, STREET, 3.000, 69.95 km]]",
"Spring Street, Fairview", "Spring Street, East Massapequa [[2, STREET, 3.000, 71.81 km]]",
"Spring Street (Wyandanch), Wheatley Heights", "Spring Street, Ellenville [[2, STREET, 3.000, 73.53 km]]",
"Spring Street, Wyandanch", "Spring Street, Monticello [[2, STREET, 3.000, 79.96 km]]",
"Spring Street, East Massapequa", "Spring Street, Tillson [[2, STREET, 3.000, 80.56 km]]",
"Spring Street, Ellenville", "Spring Street, Port Jefferson [[2, STREET, 3.000, 84.37 km]]",
"Spring Street, Monticello", "Spring Street (Smallwood), Bethel [[2, STREET, 3.000, 88.85 km]]",
"Spring Street, Tillson", "Spring Street, Liberty [[2, STREET, 3.000, 95.92 km]]",
"Spring Street, Port Jefferson", "Spring Street (Livingston Manor), Rockland [[2, STREET, 3.000, 108.88 km]]",
"Spring Street (Smallwood), Bethel", "Spring Street, Livingston Manor [[2, STREET, 3.000, 108.88 km]]",
"Spring Street, Liberty", "Spring Street Salt Shed [[2, POI, 2.000, 43.18 km]]",
"Spring Street (Livingston Manor), Rockland", "6th Avenue & Spring Street [[2, POI, 2.000, 43.25 km]]",
"Spring Street, Livingston Manor", "Spring Street [[2, POI, 2.000, 43.25 km]]",
"Market Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.25 km]]",
"New Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.31 km]]",
"West Street, Cold Spring", "Spring Street Park [[2, POI, 2.000, 43.32 km]]",
"Fish Street, Cold Spring", "Broadway & Spring Street [[2, POI, 2.000, 43.60 km]]",
"North Street, Cold Spring", "Broadway/Spring Street [[2, POI, 2.000, 43.61 km]]",
"Rock Street, Cold Spring", "Spring Street Station (6) - Downtown [[2, POI, 2.000, 43.65 km]]",
"Stone Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.67 km]]",
"Wall Street, Cold Spring", "Spring Street Station (6) - Uptown & The Bronx [[2, POI, 2.000, 43.68 km]]",
"Cross Street, Cold Spring", "Richmond Road & Spring Street [[2, POI, 2.000, 56.88 km]]",
"Main Street, Cold Spring", "Spring Street [[2, POI, 2.000, 183.80 km]]",
"Chestnut Street, Cold Spring", "West Spring Street School [[2, POI, 2.000, 204.27 km]]",
"Furnace Street, Cold Spring", "Spring Street [[2, POI, 2.000, 208.18 km]]",
"Garden Street, Cold Spring", "Spring Street [[2, POI, 2.000, 217.24 km]]",
"Church Street, Cold Spring", "Spring Street Gallery [[2, POI, 2.000, 219.70 km]]",
"Oak Street, Cold Spring", "Spring Street [[2, POI, 2.000, 220.16 km]]",
"Cherry Street, Cold Spring", "Spring Street [[2, POI, 2.000, 252.77 km]]",
"High Street, Cold Spring", "Spring Street [[2, POI, 2.000, 267.17 km]]",
"Academy Street, Cold Spring", "Spring Street Apartments [[2, POI, 2.000, 279.20 km]]",
"Haldane Street, Cold Spring", "Spring Street [[2, POI, 2.000, 414.96 km]]",
"West Bank Street, Cold Spring", "Spring Street Salt Shed [[2, POI, 2.000, 43.18 km]]",
"B Street, Cold Spring", "6th Avenue & Spring Street [[2, POI, 2.000, 43.25 km]]",
"West Belvedere Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.25 km]]",
"Parrot Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.25 km]]",
"Bank Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.31 km]]",
"Orchard Street, Cold Spring", "Spring Street Park [[2, POI, 2.000, 43.32 km]]",
"East Belvedere Street, Cold Spring", "Broadway & Spring Street [[2, POI, 2.000, 43.60 km]]",
"Pine Street, Cold Spring", "Broadway/Spring Street [[2, POI, 2.000, 43.61 km]]",
"Parsonage Street, Cold Spring", "Spring Street Station (6) - Downtown [[2, POI, 2.000, 43.65 km]]",
"Hamilton Street, Cold Spring", "Spring Street [[2, POI, 2.000, 43.67 km]]",
"Fair Street, Cold Spring", "Spring Street Station (6) - Uptown & The Bronx [[2, POI, 2.000, 43.68 km]]",
"Cedar Street, Cold Spring", "Richmond Road & Spring Street [[2, POI, 2.000, 56.88 km]]",
"Flora Street, Cold Spring Harbor", "Spring Street [[2, POI, 2.000, 183.80 km]]",
"West Main Street, Cold Spring Harbor", "West Spring Street School [[2, POI, 2.000, 204.27 km]]",
"Grove Street, Cold Spring Harbor", "Spring Street [[2, POI, 2.000, 208.18 km]]",
"Midland Street, Cold Spring Harbor", "Spring Street [[2, POI, 2.000, 217.24 km]]",
"Rusco Street, Cold Spring Harbor", "Spring Street Gallery [[2, POI, 2.000, 219.70 km]]",
"Main Street, Cold Spring Harbor", "Spring Street [[2, POI, 2.000, 220.16 km]]",
"Chestnut Street, Cold Spring Harbor", "Spring Street [[2, POI, 2.000, 252.77 km]]",
"Spring Street", "Spring Street [[2, POI, 2.000, 267.17 km]]",
"Spring Street", "Spring Street Apartments [[2, POI, 2.000, 279.20 km]]",
"Spring Street", "Spring Street [[2, POI, 2.000, 414.96 km]]",
"Spring Street", "Academy Street, Cold Spring [[2, STREET, 0.310, 35.00 km]]",
"Spring Street", "Bank Street, Cold Spring [[2, STREET, 0.310, 35.19 km]]",
"Spring Street", "B Street, Cold Spring [[2, STREET, 0.310, 35.11 km]]",
"Spring Street", "Cedar Street, Cold Spring [[2, STREET, 0.310, 35.36 km]]",
"Spring Street", "Cherry Street, Cold Spring [[2, STREET, 0.310, 34.92 km]]",
"Spring Street", "Chestnut Street, Cold Spring [[2, STREET, 0.310, 34.79 km]]",
"Spring Street", "Church Street, Cold Spring [[2, STREET, 0.310, 34.84 km]]",
"Spring Street", "Cross Street, Cold Spring [[2, STREET, 0.310, 34.75 km]]",
"Academy Street, Cold Spring", "East Belvedere Street, Cold Spring [[2, STREET, 0.310, 35.24 km]]",
"Bank Street, Cold Spring", "Fair Street, Cold Spring [[2, STREET, 0.310, 35.35 km]]",
"B Street, Cold Spring", "Fish Street, Cold Spring [[2, STREET, 0.310, 34.51 km]]",
"Cedar Street, Cold Spring", "Furnace Street, Cold Spring [[2, STREET, 0.310, 34.81 km]]",
"Cherry Street, Cold Spring", "Garden Street, Cold Spring [[2, STREET, 0.310, 34.84 km]]",
"Chestnut Street, Cold Spring", "Haldane Street, Cold Spring [[2, STREET, 0.310, 35.00 km]]",
"Church Street, Cold Spring", "Hamilton Street, Cold Spring [[2, STREET, 0.310, 35.31 km]]",
"Cross Street, Cold Spring", "High Street, Cold Spring [[2, STREET, 0.310, 34.95 km]]",
"East Belvedere Street, Cold Spring", "Main Street, Cold Spring [[2, STREET, 0.310, 34.78 km]]",
"Fair Street, Cold Spring", "Market Street, Cold Spring [[2, STREET, 0.310, 34.29 km]]",
"Fish Street, Cold Spring", "New Street, Cold Spring [[2, STREET, 0.310, 34.40 km]]",
"Furnace Street, Cold Spring", "North Street, Cold Spring [[2, STREET, 0.310, 34.51 km]]",
"Garden Street, Cold Spring", "Oak Street, Cold Spring [[2, STREET, 0.310, 34.89 km]]",
"Haldane Street, Cold Spring", "Orchard Street, Cold Spring [[2, STREET, 0.310, 35.20 km]]",
"Hamilton Street, Cold Spring", "Parrot Street, Cold Spring [[2, STREET, 0.310, 35.18 km]]",
"High Street, Cold Spring", "Parsonage Street, Cold Spring [[2, STREET, 0.310, 35.31 km]]",
"Main Street, Cold Spring", "Pine Street, Cold Spring [[2, STREET, 0.310, 35.28 km]]",
"Market Street, Cold Spring", "Rock Street, Cold Spring [[2, STREET, 0.310, 34.63 km]]",
"New Street, Cold Spring", "Stone Street, Cold Spring [[2, STREET, 0.310, 34.67 km]]",
"North Street, Cold Spring", "Wall Street, Cold Spring [[2, STREET, 0.310, 34.74 km]]",
"Oak Street, Cold Spring", "West Bank Street, Cold Spring [[2, STREET, 0.310, 35.05 km]]",
"Orchard Street, Cold Spring", "West Belvedere Street, Cold Spring [[2, STREET, 0.310, 35.15 km]]",
"Parrot Street, Cold Spring", "West Street, Cold Spring [[2, STREET, 0.310, 34.48 km]]",
"Parsonage Street, Cold Spring", "Chestnut Street, Cold Spring Harbor [[2, STREET, 0.310, 58.45 km]]",
"Pine Street, Cold Spring", "Flora Street, Cold Spring Harbor [[2, STREET, 0.310, 56.16 km]]",
"Rock Street, Cold Spring", "Grove Street, Cold Spring Harbor [[2, STREET, 0.310, 56.67 km]]",
"Stone Street, Cold Spring", "Main Street, Cold Spring Harbor [[2, STREET, 0.310, 58.23 km]]",
"Wall Street, Cold Spring", "Midland Street, Cold Spring Harbor [[2, STREET, 0.310, 57.04 km]]",
"West Bank Street, Cold Spring", "Rusco Street, Cold Spring Harbor [[2, STREET, 0.310, 57.95 km]]",
"West Belvedere Street, Cold Spring", "Spring Street, Cold Spring Harbor [[2, STREET, 0.310, 56.10 km]]",
"West Street, Cold Spring", "West Main Street, Cold Spring Harbor [[2, STREET, 0.310, 56.26 km]]",
"Chestnut Street, Cold Spring Harbor", "Kraw Street, Spring Glen [[2, STREET, 0.310, 69.40 km]]",
"Flora Street, Cold Spring Harbor", "Munro Street, Cold Spring [[2, STREET, 0.310, 292.27 km]]",
"Grove Street, Cold Spring Harbor", "State Street, Cold Spring [[2, STREET, 0.310, 292.31 km]]",
"Main Street, Cold Spring Harbor", "Market Street, Cold Spring [[2, STREET, 0.310, 34.29 km]]",
"Midland Street, Cold Spring Harbor", "New Street, Cold Spring [[2, STREET, 0.310, 34.40 km]]",
"Rusco Street, Cold Spring Harbor", "Fish Street, Cold Spring [[2, STREET, 0.310, 34.51 km]]",
"Spring Street, Cold Spring Harbor", "North Street, Cold Spring [[2, STREET, 0.310, 34.51 km]]",
"West Main Street, Cold Spring Harbor", "Rock Street, Cold Spring [[2, STREET, 0.310, 34.63 km]]",
"Kraw Street, Spring Glen", "Stone Street, Cold Spring [[2, STREET, 0.310, 34.67 km]]",
"Munro Street, Cold Spring", "Wall Street, Cold Spring [[2, STREET, 0.310, 34.74 km]]",
"State Street, Cold Spring", "Cross Street, Cold Spring [[2, STREET, 0.310, 34.75 km]]",
"Spring Street Salt Shed", "Main Street, Cold Spring [[2, STREET, 0.310, 34.78 km]]",
"6th Avenue & Spring Street", "Chestnut Street, Cold Spring [[2, STREET, 0.310, 34.79 km]]",
"Spring Street Park", "Furnace Street, Cold Spring [[2, STREET, 0.310, 34.81 km]]",
"Broadway & Spring Street", "Garden Street, Cold Spring [[2, STREET, 0.310, 34.84 km]]",
"Broadway/Spring Street", "Church Street, Cold Spring [[2, STREET, 0.310, 34.84 km]]",
"Spring Street Station (6) - Downtown", "Oak Street, Cold Spring [[2, STREET, 0.310, 34.89 km]]",
"Spring Street Station (6) - Uptown & The Bronx", "Cherry Street, Cold Spring [[2, STREET, 0.310, 34.92 km]]",
"Richmond Road & Spring Street", "High Street, Cold Spring [[2, STREET, 0.310, 34.95 km]]",
"West Spring Street School", "Academy Street, Cold Spring [[2, STREET, 0.310, 35.00 km]]",
"Spring Street Gallery", "Haldane Street, Cold Spring [[2, STREET, 0.310, 35.00 km]]",
"Spring Street Apartments", "West Bank Street, Cold Spring [[2, STREET, 0.310, 35.05 km]]",
"Spring Street", "B Street, Cold Spring [[2, STREET, 0.310, 35.11 km]]",
"Spring Street", "West Belvedere Street, Cold Spring [[2, STREET, 0.310, 35.15 km]]",
"Spring Street", "Parrot Street, Cold Spring [[2, STREET, 0.310, 35.18 km]]",
"Spring Street", "Bank Street, Cold Spring [[2, STREET, 0.310, 35.19 km]]",
"Spring Street", "Orchard Street, Cold Spring [[2, STREET, 0.310, 35.20 km]]",
"Spring Street", "East Belvedere Street, Cold Spring [[2, STREET, 0.310, 35.24 km]]",
"Spring Street", "Pine Street, Cold Spring [[2, STREET, 0.310, 35.28 km]]",
"Spring Street", "Parsonage Street, Cold Spring [[2, STREET, 0.310, 35.31 km]]",
"Spring Street", "Hamilton Street, Cold Spring [[2, STREET, 0.310, 35.31 km]]",
"Spring Street", "Fair Street, Cold Spring [[2, STREET, 0.310, 35.35 km]]",
"Spring Street", "Cedar Street, Cold Spring [[2, STREET, 0.310, 35.36 km]]",
"Flora Street, Cold Spring Harbor [[2, STREET, 0.310, 56.16 km]]",
"West Main Street, Cold Spring Harbor [[2, STREET, 0.310, 56.26 km]]",
"Grove Street, Cold Spring Harbor [[2, STREET, 0.310, 56.67 km]]",
"Midland Street, Cold Spring Harbor [[2, STREET, 0.310, 57.04 km]]",
"Rusco Street, Cold Spring Harbor [[2, STREET, 0.310, 57.95 km]]",
"Main Street, Cold Spring Harbor [[2, STREET, 0.310, 58.23 km]]",
"Chestnut Street, Cold Spring Harbor [[2, STREET, 0.310, 58.45 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,241 +11,286 @@
}, },
"phrase": "starbucks coffee", "phrase": "starbucks coffee",
"results": [ "results": [
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 1.74 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 3.47 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 3.47 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 92.61 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 92.61 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 212.95 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 212.95 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 263.64 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 263.65 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 263.67 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 263.75 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 263.75 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 264.13 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 264.13 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 268.90 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 268.90 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 285.39 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 285.39 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 285.43 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 285.43 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 336.54 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 336.54 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 337.99 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 337.99 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 374.87 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 374.87 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 376.98 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 376.98 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 388.39 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 388.39 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 388.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 388.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.07 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.07 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.13 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.13 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.68 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.68 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.91 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 389.91 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 406.19 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 406.19 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 416.04 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 416.04 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 417.21 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 417.21 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 435.35 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 435.35 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 449.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 449.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 454.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 454.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.16 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.16 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.29 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.29 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.45 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 458.45 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 459.18 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 459.18 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 461.51 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 461.51 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 462.03 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 462.03 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 462.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 462.97 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.01 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.01 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.11 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.11 km]]",
"Starbucks Coffee", "Starbucks Coffee สาขา The X-Place [[2, POI, 2.000, 464.70 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.75 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 464.75 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.93 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.93 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.99 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 466.99 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.24 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.24 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.36 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.36 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.58 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.58 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.75 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 467.75 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.46 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.46 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.53 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.53 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 468.69 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 468.69 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 468.95 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 468.95 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.96 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 468.96 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.17 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.17 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 469.19 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.27 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.27 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.27 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.54 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.54 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 469.55 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.59 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.59 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.70 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.70 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.72 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.72 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 469.72 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.78 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.78 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.84 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.84 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.90 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 469.90 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.05 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.05 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 470.32 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.35 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.35 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.54 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.54 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 470.57 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 470.64 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 470.66 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 470.77 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.83 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 470.83 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 470.83 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.00 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.04 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.04 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.06 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.13 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.13 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.15 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.24 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.25 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.26 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.33 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.47 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.59 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.62 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.62 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.66 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.66 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.67 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.69 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.69 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.69 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.70 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.75 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.75 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.75 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.75 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.83 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.83 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.84 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.85 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.89 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.89 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.90 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 471.91 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 471.94 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 471.97 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.01 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.03 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.03 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.03 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 472.06 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.17 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.24 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.24 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.32 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.39 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.39 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.40 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.40 km]]",
"Starbucks Coffee", "สตาร์บัคส์ [[2, POI, 2.000, 472.45 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.69 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.69 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.76 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.76 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 472.90 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.92 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 472.93 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 473.14 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 473.14 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 473.53 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 473.53 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 473.55 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 474.53 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 474.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 474.60 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 474.63 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 474.63 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 474.73 km]]",
"Starbucks coffee", "Starbucks Coffee [[2, POI, 2.000, 474.73 km]]",
"STARBUCKS COFFEE", "Starbucks [[2, POI, 2.000, 475.43 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 475.64 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 475.68 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 475.68 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 475.83 km]]",
"Starbucks Coffee", "Starbucks [[2, POI, 2.000, 476.09 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 476.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 476.89 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 477.21 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 477.21 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.00 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.00 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.29 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.29 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.96 km]]",
"Starbucks Coffee", "Starbucks Coffee [[2, POI, 2.000, 479.96 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 480.08 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 480.08 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 480.20 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 480.20 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 481.18 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 481.18 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 481.20 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 481.20 km]]",
"Starbucks", "Starbucks Coffee [[2, POI, 2.000, 481.33 km]]",
"Starbucks Coffee สาขา The X-Place", "Starbucks Coffee [[2, POI, 2.000, 481.33 km]]",
"Starbucks" "Starbucks Coffee [[2, POI, 2.000, 482.21 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.21 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.55 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.55 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.59 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.59 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.73 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.73 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.80 km]]",
"Starbucks Coffee [[2, POI, 2.000, 482.80 km]]",
"Starbucks Coffee [[2, POI, 2.000, 484.02 km]]",
"Starbucks Coffee [[2, POI, 2.000, 484.02 km]]",
"Starbucks Coffee [[2, POI, 2.000, 486.63 km]]",
"Starbucks Coffee [[2, POI, 2.000, 486.63 km]]",
"Starbucks Coffee [[2, POI, 2.000, 486.83 km]]",
"Starbucks Coffee [[2, POI, 2.000, 486.83 km]]",
"Starbucks Coffee [[2, POI, 2.000, 487.90 km]]",
"Starbucks Coffee [[2, POI, 2.000, 487.90 km]]",
"Starbucks Coffee [[2, POI, 2.000, 488.50 km]]",
"Starbucks Coffee [[2, POI, 2.000, 488.50 km]]",
"Starbucks Coffee [[2, POI, 2.000, 489.17 km]]",
"Starbucks Coffee [[2, POI, 2.000, 489.17 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.48 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.48 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.58 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.62 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.62 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.64 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.64 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.67 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.77 km]]",
"Starbucks Coffee [[2, POI, 2.000, 490.77 km]]",
"Starbucks Coffee [[2, POI, 2.000, 491.42 km]]",
"Starbucks Coffee [[2, POI, 2.000, 491.42 km]]",
"Starbucks Coffee [[2, POI, 2.000, 491.69 km]]",
"Starbucks Coffee [[2, POI, 2.000, 491.69 km]]",
"Starbucks coffee [[2, POI, 2.000, 508.65 km]]",
"STARBUCKS COFFEE [[2, POI, 2.000, 508.65 km]]",
"Starbucks Coffee [[2, POI, 2.000, 537.88 km]]",
"Starbucks Coffee [[2, POI, 2.000, 645.39 km]]",
"Starbucks Coffee [[2, POI, 2.000, 645.39 km]]",
"Starbucks [[2, POI, 2.000, 825.00 km]]",
"Starbucks [[2, POI, 2.000, 924.99 km]]",
"Starbucks [[2, POI, 2.000, 925.57 km]]",
"Starbucks Coffee [[2, POI, 2.000, 972.63 km]]",
"Starbucks Coffee [[2, POI, 2.000, 972.63 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,13 +11,18 @@
}, },
"phrase": "комсомольская", "phrase": "комсомольская",
"results": [ "results": [
"Комсомольская улица, Заинск", "Комсомольская улица, Заинск [[1, STREET, 3.000, 0.77 km]]",
"Комсомольская улица, Чукмарлы", "Комсомольская улица, Чукмарлы [[1, STREET, 3.000, 26.83 km]]",
"Комсомольская улица, Русский Акташ", "Комсомольская улица, Русский Акташ [[1, STREET, 3.000, 28.18 km]]",
"Комсомольская улица, Альметьевск", "Комсомольская улица, Альметьевск [[1, STREET, 3.000, 46.40 km]]",
"Комсомольская набережная, Набережные Челны", "Комсомольская набережная, Набережные Челны [[1, STREET, 3.000, 48.55 km]]",
"Комсомольская улица, Новое Надырово", "Комсомольская улица, Новое Надырово [[1, STREET, 3.000, 52.30 km]]",
"Комсомольская улица, Тарловка" "Комсомольская улица, Тарловка [[1, STREET, 3.000, 55.76 km]]",
"Комсомольская улица, Мамадыш [[1, STREET, 3.000, 61.75 km]]",
"Комсомольская улица, Кузкеево [[1, STREET, 3.000, 73.57 km]]",
"Комсомольская улица, Актюбинский [[1, STREET, 3.000, 73.90 km]]",
"улица Комсомольская, Малтабарово [[1, STREET, 3.000, 74.71 km]]",
"Комсомольская улица, Карабаш [[1, STREET, 3.000, 75.32 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,15 +11,71 @@
}, },
"phrase": "ленина 30", "phrase": "ленина 30",
"results": [ "results": [
"30А, улица Ленина, Заинск", "30А, улица Ленина, Заинск [[2, HOUSE, 0.430, 1.33 km]]",
"30Б, улица Ленина, Заинск", "30Б, улица Ленина, Заинск [[2, HOUSE, 0.430, 1.25 km]]",
"30, улица Ленина, Сарманово", "30, улица Ленина, Сарманово [[2, HOUSE, 0.430, 37.20 km]]",
"30, улица Ленина, Большое Афанасово", "30, улица Ленина, Большое Афанасово [[2, HOUSE, 0.430, 38.21 km]]",
"30, улица Ленина, Альметьевск", "30, улица Ленина, Альметьевск [[2, HOUSE, 0.430, 46.58 km]]",
"30А, улица Ленина, Альметьевск", "30А, улица Ленина, Альметьевск [[2, HOUSE, 0.430, 46.52 km]]",
"улица Ленина, Заинск", "улица Ленина, Заинск [[1, STREET, 3.000, 0.42 km]]",
"улица Ленина, Аксарино", "улица Ленина, Аксарино [[1, STREET, 3.000, 8.83 km]]",
"улица Ленина, Светлое Озеро" "улица Ленина, Светлое Озеро [[1, STREET, 3.000, 11.98 km]]",
"улица Ленина, Старый Токмак [[1, STREET, 3.000, 12.32 km]]",
"улица Ленина, Имянлебаш [[1, STREET, 3.000, 13.62 km]]",
"улица Ленина, Верхняя Уратьма [[1, STREET, 3.000, 16.97 km]]",
"улица Ленина, Красная Кадка [[1, STREET, 3.000, 19.92 km]]",
"улица Ленина, Большие Аты [[1, STREET, 3.000, 20.94 km]]",
"улица Ленина, Бегишево [[1, STREET, 3.000, 22.37 km]]",
"улица Ленина, Туба [[1, STREET, 3.000, 26.21 km]]",
"улица Ленина, Русский Акташ [[1, STREET, 3.000, 27.38 km]]",
"улица Ленина, Шингальчи [[1, STREET, 3.000, 27.74 km]]",
"улица Ленина, Болгар [[1, STREET, 3.000, 29.55 km]]",
"улица Ленина, Петровский Завод [[1, STREET, 3.000, 31.18 km]]",
"улица Ленина, Мусабай-Завод [[1, STREET, 3.000, 35.32 km]]",
"улица Ленина, Сарманово [[1, STREET, 3.000, 36.68 km]]",
"улица Ленина, Большое Афанасово [[1, STREET, 3.000, 38.36 km]]",
"улица Ленина, Старое Клянчино [[1, STREET, 3.000, 38.42 km]]",
"улица Ленина, Подгорный Дрюш [[1, STREET, 3.000, 41.91 km]]",
"Ленина, Альметьевск [[1, STREET, 3.000, 44.87 km]]",
"улица Ленина, Альметьевск [[1, STREET, 3.000, 46.35 km]]",
"улица Ленина, Старые Челны [[1, STREET, 3.000, 49.78 km]]",
"улица Ленина, Набережные Челны [[1, STREET, 3.000, 49.78 km]]",
"улица Ленина, Маметьево [[1, STREET, 3.000, 52.24 km]]",
"улица Ленина, Кармалы [[1, STREET, 3.000, 52.25 km]]",
"улица Ленина, Орловка [[1, STREET, 3.000, 53.37 km]]",
"улица Ленина, Буденовец [[1, STREET, 3.000, 54.44 km]]",
"улица Ленина, Джалиль [[1, STREET, 3.000, 54.97 km]]",
"улица Ленина, Чупаево [[1, STREET, 3.000, 55.17 km]]",
"улица Ленина, Новошешминск [[1, STREET, 3.000, 55.87 km]]",
"улица Ленина, Саклов-Баш [[1, STREET, 3.000, 56.28 km]]",
"улица В. И. Ленина, Мамадыш [[1, STREET, 3.000, 60.36 km]]",
"улица Ленина, Красная Горка [[1, STREET, 3.000, 61.68 km]]",
"улица Ленина, Малая Шильна [[1, STREET, 3.000, 66.26 km]]",
"улица Ленина, Актюбинский [[1, STREET, 3.000, 73.22 km]]",
"улица Ленина, Карабаш [[1, STREET, 3.000, 75.67 km]]",
"совхоза имени Ленина [[1, POI, 2.000, 899.76 km]]",
"Леніна [[1, POI, 2.000, 1163.27 km]]",
"улица Ленина [[1, POI, 2.000, 16.46 km]]",
"улица Ленина [[1, POI, 2.000, 27.74 km]]",
"улица Ленина [[1, POI, 2.000, 46.74 km]]",
"улица Ленина [[1, POI, 2.000, 46.74 km]]",
"Ул Ленина [[1, POI, 2.000, 74.29 km]]",
"улица Ленина [[1, POI, 2.000, 108.41 km]]",
"улица Ленина [[1, POI, 2.000, 120.26 km]]",
"Парк Ленина [[1, POI, 2.000, 122.09 km]]",
"улица Ленина [[1, POI, 2.000, 130.70 km]]",
"улица Ленина [[1, POI, 2.000, 138.27 km]]",
"улица Ленина [[1, POI, 2.000, 149.67 km]]",
"Ленина 148 [[1, POI, 2.000, 161.65 km]]",
"Дом-музей В.И.Ленина [[1, POI, 2.000, 188.81 km]]",
"Культурно-досуговый комплекс им. В.И.Ленина [[1, POI, 2.000, 194.07 km]]",
"ДК им.Ленина [[1, POI, 2.000, 194.10 km]]",
"ДК им.Ленина [[1, POI, 2.000, 194.16 km]]",
"НПО им. Ленина [[1, POI, 2.000, 207.90 km]]",
"НПО им. Ленина [[1, POI, 2.000, 207.94 km]]",
"Ленина [[1, POI, 2.000, 218.83 km]]",
"улица Ленина [[1, POI, 2.000, 230.77 km]]",
"Санаторий имени В.И. Ленина [[1, POI, 2.000, 242.65 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,18 +11,140 @@
}, },
"phrase": "rue émile", "phrase": "rue émile",
"results": [ "results": [
"Rue Émile Gérard, Liège", "Rue Émile Gérard, Liège [[2, STREET, 3.000, 1.42 km]]",
"Rue Emile Vandervelde, Liège", "Rue Emile Vandervelde, Liège [[2, STREET, 3.000, 1.66 km]]",
"Rue Emile Vandervelde - Rue Sainte-Marguerite, Liège", "Rue Emile Vandervelde - Rue Sainte-Marguerite, Liège [[2, STREET, 3.000, 1.74 km]]",
"Rue Émile Zola (Laveu), Liège", "Rue Émile Zola (Laveu), Liège [[2, STREET, 3.000, 1.98 km]]",
"Rue Émile Collard, Liège", "Rue Émile Collard, Liège [[2, STREET, 3.000, 2.49 km]]",
"Rue Emile Vandervelde, Vottem", "Rue Emile Vandervelde, Vottem [[2, STREET, 3.000, 3.22 km]]",
"Rue Emile Vandervelde (Vottem), Herstal", "Rue Emile Vandervelde (Vottem), Herstal [[2, STREET, 3.000, 3.23 km]]",
"Rue Émile Verhaeren, Liège", "Rue Émile Verhaeren, Liège [[2, STREET, 3.000, 3.58 km]]",
"Rue Émile Jeanne, Saint-Nicolas", "Rue Émile Jeanne, Saint-Nicolas [[2, STREET, 3.000, 4.03 km]]",
"Rue Emile Muraille, Herstal", "Rue Emile Muraille, Herstal [[2, STREET, 3.000, 4.70 km]]",
"Rue Emile Verhaeren, Grâce-Hollogne", "Rue Emile Verhaeren, Grâce-Hollogne [[2, STREET, 3.000, 4.71 km]]",
"Rue Emile Vinck, Herstal" "Rue Emile Vinck, Herstal [[2, STREET, 3.000, 4.72 km]]",
"Rue Emile Wiket, Grâce-Hollogne [[2, STREET, 3.000, 4.74 km]]",
"Rue Émile Zola, Grâce-Berleur [[2, STREET, 3.000, 5.15 km]]",
"Rue Émile Zola (Grâce-Berleur), Grâce-Hollogne [[2, STREET, 3.000, 5.15 km]]",
"Rue Emile Vandervelde (Loncin), Ans [[2, STREET, 3.000, 5.17 km]]",
"Rue Emile Tilman, Herstal [[2, STREET, 3.000, 5.19 km]]",
"Rue Émile Lerousseau, Liers [[2, STREET, 3.000, 5.45 km]]",
"Rue du Couvent - Rue Emile Vandervelde, Liège [[2, STREET, 3.000, 5.74 km]]",
"Rue Émile Lerousseau (Liers), Herstal [[2, STREET, 3.000, 5.85 km]]",
"Rue Émile Vandervelde (Vaux-sous-Chèvremont), Chaudfontaine [[2, STREET, 3.000, 6.60 km]]",
"Rue Emile Royer (Jemeppe-Sur-Meuse), Seraing [[2, STREET, 3.000, 6.76 km]]",
"Rue Emile Vandervelde, Queue-du-Bois [[2, STREET, 3.000, 7.32 km]]",
"Rue Paul Emile Janson, Awans [[2, STREET, 3.000, 7.33 km]]",
"Rue Emile Vandevelde, Fléron [[2, STREET, 3.000, 7.52 km]]",
"Rue Paul-Emile Janson, Flémalle [[2, STREET, 3.000, 8.25 km]]",
"Rue Emile Vandervelde (Vivegnis), Oupeye [[2, STREET, 3.000, 8.34 km]]",
"Rue Emile Vinck, Oupeye [[2, STREET, 3.000, 8.53 km]]",
"Rue Emile Vandervelde, Flémalle [[2, STREET, 3.000, 8.67 km]]",
"Rue Émile Zola, Seraing [[2, STREET, 3.000, 8.76 km]]",
"Rue Emile de Laveleye, Hermalle-sous-Argenteau [[2, STREET, 3.000, 9.67 km]]",
"Rue Emile de Laveleye, Oupeye [[2, STREET, 3.000, 9.84 km]]",
"Rue Emile Grisard, Juprelle [[2, STREET, 3.000, 10.19 km]]",
"Rue Emile Verhaeren, Visé [[2, STREET, 3.000, 13.02 km]]",
"Rue Emile Delcour, Saint-Georges-sur-Meuse [[2, STREET, 3.000, 14.96 km]]",
"Rue Émile Fairon, Pepinster [[2, STREET, 3.000, 18.91 km]]",
"Rue Emile Vandervelde, Comblain-au-Pont [[2, STREET, 3.000, 19.17 km]]",
"Rue Emile Vandervelde (Wegnez), Pepinster [[2, STREET, 3.000, 19.34 km]]",
"Rue Emile Vandervelde, Amay [[2, STREET, 3.000, 20.84 km]]",
"Rue Emile Lelarge, Verviers [[2, STREET, 3.000, 22.80 km]]",
"Rue Émile Vandervelde, Borlez [[2, STREET, 3.000, 23.23 km]]",
"Rue Emile Hallet, Waremme [[2, STREET, 3.000, 23.40 km]]",
"Rue Docteur Emile Neuville, Villers-le-Bouillet [[2, STREET, 3.000, 23.80 km]]",
"Rue Emile Marchoul, Waremme [[2, STREET, 3.000, 24.21 km]]",
"Rue Emile Vandervelde (Vinalmont), Wanze [[2, STREET, 3.000, 25.91 km]]",
"Rue Émile Colette, Limbourg [[2, STREET, 3.000, 25.94 km]]",
"Rue Emile Vandervelde, Vinalmont [[2, STREET, 3.000, 25.97 km]]",
"Rue Émile Muselle, Berloz [[2, STREET, 3.000, 26.33 km]]",
"Rue Emile Delperée, Huy [[2, STREET, 3.000, 26.70 km]]",
"Rue Emile Rorive, Wanze [[2, STREET, 3.000, 27.17 km]]",
"Rue Emile Lejeune, Geer [[2, STREET, 3.000, 28.34 km]]",
"Rue Emile Schmuck, Baelen [[2, STREET, 3.000, 28.49 km]]",
"Rue Emile Roder, Hannut [[2, STREET, 3.000, 31.34 km]]",
"Rue Emile Vandervelde, Marchin [[2, STREET, 3.000, 31.59 km]]",
"Rue Emile Vandervelde, Gives [[2, STREET, 3.000, 33.42 km]]",
"Rue Emile Vandervelde (Gives), Huy [[2, STREET, 3.000, 33.42 km]]",
"Rue Emile Goedert, Francorchamps [[2, STREET, 3.000, 34.14 km]]",
"Rue Emile Martin, Hannut [[2, STREET, 3.000, 34.89 km]]",
"Rue Emile Godfrind, Andenne [[2, STREET, 3.000, 38.07 km]]",
"Rue Emile Godfrind, Seilles [[2, STREET, 3.000, 38.35 km]]",
"Rue Emile Duchesne, Grand-Hallet [[2, STREET, 3.000, 38.66 km]]",
"Rue Emile Looze (Maret), Orp-Jauche [[2, STREET, 3.000, 41.20 km]]",
"Rue Emile Looze (Pellaines), Lincent [[2, STREET, 3.000, 41.24 km]]",
"Rue Emile Tromme, Vielsalm [[2, STREET, 3.000, 42.94 km]]",
"Rue Emile Landeut, Orp-Jauche [[2, STREET, 3.000, 43.71 km]]",
"Rue Emile Parfonry, Hotton [[2, STREET, 3.000, 43.75 km]]",
"Rue Emile Vandervelde (Namêche), Andenne [[2, STREET, 3.000, 44.87 km]]",
"Rue Emile Dupont, Rendeux [[2, STREET, 3.000, 45.98 km]]",
"Rue Émile Demelenne, Marche-en-Famenne [[2, STREET, 3.000, 48.54 km]]",
"Rue Emile Marnach, Vedrin [[2, STREET, 3.000, 52.19 km]]",
"Rue Emile Masset, Perwez [[2, STREET, 3.000, 53.07 km]]",
"Rue Émile Crebeyck, Perwez [[2, STREET, 3.000, 53.41 km]]",
"Rue Emile de Brabant, Perwez [[2, STREET, 3.000, 53.59 km]]",
"Rue Émile Cuvelier, Namur [[2, STREET, 3.000, 53.92 km]]",
"Rue Emile Melchior, Saint-Servais [[2, STREET, 3.000, 55.31 km]]",
"Rue Emile Herman, Marche-en-Famenne [[2, STREET, 3.000, 56.87 km]]",
"Rue Emile Dessenius, Namur [[2, STREET, 3.000, 57.52 km]]",
"Rue Emile Vandervelde (Flawinne), Namur [[2, STREET, 3.000, 58.18 km]]",
"Rue Emile Vandervelde, Flawinne [[2, STREET, 3.000, 58.18 km]]",
"Rue Emile Mazy (Flawinne), Namur [[2, STREET, 3.000, 58.85 km]]",
"Rue Emile Mazy, Flawinne [[2, STREET, 3.000, 58.85 km]]",
"Rue Emile Mahaux, Bois-de-Villers [[2, STREET, 3.000, 60.14 km]]",
"Rue Emile Mahaux, Profondeville [[2, STREET, 3.000, 60.14 km]]",
"Rue Emile Dewez (Beuzet), Gembloux [[2, STREET, 3.000, 60.65 km]]",
"Rue Emile Mazy (Bois-de-Villers), Profondeville [[2, STREET, 3.000, 61.08 km]]",
"Rue Emile Mazy, Bois-de-Villers [[2, STREET, 3.000, 61.08 km]]",
"Rue Emile Marchal, Isnes [[2, STREET, 3.000, 62.58 km]]",
"Rue Émile Lorent, Floreffe [[2, STREET, 3.000, 62.66 km]]",
"Rue Emile Lessire, Floreffe [[2, STREET, 3.000, 62.67 km]]",
"Rue Emile Vandervelde, Nethen [[2, STREET, 3.000, 64.04 km]]",
"Rue Emile Vandervelde (Nethen), Grez-Doiceau [[2, STREET, 3.000, 64.04 km]]",
"Rue Émile Somville, Grand-Manil [[2, STREET, 3.000, 64.11 km]]",
"Rue Émile Labarre, Ernage [[2, STREET, 3.000, 64.11 km]]",
"Rue Emile Tréfois, Mornimont [[2, STREET, 3.000, 64.86 km]]",
"Rue Emile Tréfois, Jemeppe-sur-Sambre [[2, STREET, 3.000, 64.86 km]]",
"Rue Émile Pirson, Mazy [[2, STREET, 3.000, 65.34 km]]",
"Rue Émile Pirson, Gembloux [[2, STREET, 3.000, 65.34 km]]",
"Rue Emile Wauthy, Dinant [[2, STREET, 3.000, 65.92 km]]",
"Rue Emile Matelart (Saint-Martin), Jemeppe-sur-Sambre [[2, STREET, 3.000, 67.02 km]]",
"Rue Emile Francqui, Corbais [[2, STREET, 3.000, 67.03 km]]",
"Rue Emile Francqui (Corbais), Mont-Saint-Guibert [[2, STREET, 3.000, 67.03 km]]",
"Rue Emile Matelart, Saint-Martin [[2, STREET, 3.000, 67.18 km]]",
"Rue Emile Vandervelde, Ham-sur-Sambre [[2, STREET, 3.000, 67.22 km]]",
"Rue Émile Goes (Biéreau), Louvain-la-Neuve [[2, STREET, 3.000, 67.43 km]]",
"Rue Emile Pirson, Sombreffe [[2, STREET, 3.000, 68.64 km]]",
"Rue Émile Mathéi, Limelette [[2, STREET, 3.000, 70.90 km]]",
"Rue Émile Mathéi, Ottignies-Louvain-la-Neuve [[2, STREET, 3.000, 70.90 km]]",
"Rue Émile Henricot, Court-Saint-Etienne [[2, STREET, 3.000, 70.99 km]]",
"Rue Emile Toussaint, Onhaye [[2, STREET, 3.000, 71.25 km]]",
"Rue Emile Toussaint, Serville [[2, STREET, 3.000, 71.25 km]]",
"Rue Emile Duculot, Sambreville [[2, STREET, 3.000, 72.06 km]]",
"Rue Emile Duculot, Tamines [[2, STREET, 3.000, 72.06 km]]",
"Rue Émile Zola (Keumiée), Sambreville [[2, STREET, 3.000, 72.35 km]]",
"Rue Émile Vandervelde (Ligny), Sombreffe [[2, STREET, 3.000, 72.64 km]]",
"Rue Emile Collard, Onhaye [[2, STREET, 3.000, 73.26 km]]",
"Rue Emile Collard, Anthée [[2, STREET, 3.000, 73.26 km]]",
"Rue Émile Vandervelde (Moignelée), Sambreville [[2, STREET, 3.000, 73.61 km]]",
"Rue Emile Leger, Villers-la-Ville [[2, STREET, 3.000, 74.22 km]]",
"Rue Emile Vandervelde, Fleurus [[2, STREET, 3.000, 74.70 km]]",
"Rue Emile Hautem, Fleurus [[2, STREET, 3.000, 74.81 km]]",
"Rue Emile Hautem, Lambusart [[2, STREET, 3.000, 74.81 km]]",
"rue Emile de Clercq, Mettet [[2, STREET, 3.000, 76.79 km]]",
"Rue Émile Vandervelde (Pironchamps), Farciennes [[2, STREET, 3.000, 77.70 km]]",
"Rue Emile Genard, Gerpinnes [[2, STREET, 3.000, 81.14 km]]",
"Rue Émile Montreuil, Gedinne [[2, STREET, 3.000, 87.18 km]]",
"Rue Émile Montreuil, Rienne [[2, STREET, 3.000, 87.42 km]]",
"Glain Rue Emile Vandervelde [[2, POI, 2.000, 1.81 km]]",
"Rue Emile Vandervelde [[2, POI, 2.000, 2.03 km]]",
"Orp-le-Grand Rue Emile Vandervelde [[2, POI, 2.000, 41.51 km]]",
"Namur Rue Émile Cuvelier [[2, POI, 2.000, 53.85 km]]",
"Soye Rue Émile Lorent 252 [[2, POI, 2.000, 62.77 km]]",
"Soye Rue Émile Lorent 252 [[2, POI, 2.000, 62.81 km]]",
"Rue Émile Pirson [[2, POI, 2.000, 65.74 km]]",
"Fleurus Rue Emile Vandervelde [[2, POI, 2.000, 74.90 km]]"
], ],
"amenities": [ "amenities": [
{ {

View file

@ -11,29 +11,60 @@
}, },
"phrase": "santa clara", "phrase": "santa clara",
"results": [ "results": [
"Carrer de Santa Clara, Sant Pol de Mar", "Carrer de Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.03 km]]",
"Santa Clara, Sant Pol de Mar", "Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.06 km]]",
"Carrer Santa Clara, Sant Pol de Mar", "Carrer Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.12 km]]",
"Plaça Santa Clara, Santa Coloma de Farners", "Plaça Santa Clara, Santa Coloma de Farners [[2, STREET, 3.000, 29.76 km]]",
"Carrer del Comte de Santa Clara, Barcelona", "Carrer del Comte de Santa Clara, Barcelona [[2, STREET, 3.000, 43.84 km]]",
"Carrer del Comte de Santa Clara, la Barceloneta", "Carrer del Comte de Santa Clara, la Barceloneta [[2, STREET, 3.000, 43.84 km]]",
"Passatge de Santa Clara, Barcelona", "Passatge de Santa Clara, Barcelona [[2, STREET, 3.000, 44.32 km]]",
"Passatge de Santa Clara, Barri Gòtic", "Passatge de Santa Clara, Barri Gòtic [[2, STREET, 3.000, 44.32 km]]",
"Baixada de Santa Clara, Barcelona", "Baixada de Santa Clara, Barcelona [[2, STREET, 3.000, 44.33 km]]",
"Baixada de Santa Clara, Barri Gòtic", "Baixada de Santa Clara, Barri Gòtic [[2, STREET, 3.000, 44.33 km]]",
"Carrer de Santa Clara, Girona", "Carrer de Santa Clara, Girona [[2, STREET, 3.000, 45.73 km]]",
"Plaça de Santa Clara, Vic", "Plaça de Santa Clara, Vic [[2, STREET, 3.000, 47.62 km]]",
"Carrer de Santa Clara, Poble Nou", "Carrer de Santa Clara, Poble Nou [[2, STREET, 3.000, 56.25 km]]",
"Carrer de Santa Clara (Poble Nou), Sant Vicenç dels Horts", "Carrer de Santa Clara (Poble Nou), Sant Vicenç dels Horts [[2, STREET, 3.000, 56.25 km]]",
"Carrer Vell de Santa Clara, Manresa", "Carrer Vell de Santa Clara, Manresa [[2, STREET, 3.000, 66.96 km]]",
"Carrer Nou de Santa Clara, Centre Històric", "Carrer Nou de Santa Clara, Centre Històric [[2, STREET, 3.000, 67.15 km]]",
"Carrer Nou de Santa Clara (Les Escodines), Manresa", "Carrer Nou de Santa Clara (Les Escodines), Manresa [[2, STREET, 3.000, 67.15 km]]",
"Carrer de Santa Clara, Masquefa", "Carrer de Santa Clara, Masquefa [[2, STREET, 3.000, 68.25 km]]",
"Carrer Santa Clara, Castelló d'Empúries", "Carrer Santa Clara, Castelló d'Empúries [[2, STREET, 3.000, 81.65 km]]",
"Carrer de Santa Clara, Vilafranca del Penedès", "Carrer de Santa Clara, Vilafranca del Penedès [[2, STREET, 3.000, 81.86 km]]",
"Carrer de Santa Clara, Castelló d'Empúries", "Carrer de Santa Clara, Castelló d'Empúries [[2, STREET, 3.000, 81.93 km]]",
"Carrer Clara Campoamor, Santa Coloma de Gramenet" "Santa Clara [[2, POI, 2.000, 7784.16 km]]",
"Santa Clara [[2, POI, 2.000, 30.97 km]]",
"Santa Clara [[2, POI, 2.000, 8583.12 km]]",
"Santa Clara [[2, POI, 2.000, 44.32 km]]",
"Pastisseria Santa Clara [[2, POI, 2.000, 44.34 km]]",
"Escola Santa Clara [[2, POI, 2.000, 44.69 km]]",
"Santa Clara [[2, POI, 2.000, 45.45 km]]",
"L11 - Santa Clara [[2, POI, 2.000, 45.52 km]]",
"Santa Clara [[2, POI, 2.000, 9114.25 km]]",
"CAP SANTA CLARA [[2, POI, 2.000, 45.64 km]]",
"CAP Santa Clara [[2, POI, 2.000, 45.64 km]]",
"L11 - Santa Clara [[2, POI, 2.000, 45.74 km]]",
"Plaça de Santa Clara [[2, POI, 2.000, 47.62 km]]",
"Pl. Santa Clara [[2, POI, 2.000, 47.62 km]]",
"Santa Clara de Olimar [[2, POI, 2.000, 10164.87 km]]",
"Claverol / Santa Clara [[2, POI, 2.000, 56.34 km]]",
"Monestir de Santa Clara [[2, POI, 2.000, 66.71 km]]",
"Santa Clara [[2, POI, 2.000, 66.75 km]]",
"La Sínia de Santa Clara [[2, POI, 2.000, 66.81 km]]",
"Restaurant Santa Clara [[2, POI, 2.000, 69.76 km]]",
"Hostal Santa Clara [[2, POI, 2.000, 69.77 km]]",
"Santa Maria del Castell de Claramunt [[2, POI, 2.000, 79.46 km]]",
"Monestir de Santa Clara [[2, POI, 2.000, 81.26 km]]",
"Santa Clara / Muralla de Sant Magí [[2, POI, 2.000, 81.86 km]]",
"Convent de Santa Clara [[2, POI, 2.000, 82.15 km]]",
"Convent de Santa Clara [[2, POI, 2.000, 137.22 km]]",
"Santa Clara del Mullol [[2, POI, 2.000, 137.89 km]]",
"Plaça de la Mare Santa Clara [[2, POI, 2.000, 166.36 km]]",
"Pujada de Santa Clara [[2, POI, 2.000, 196.30 km]]",
"Carrer Nou de Santa Clara [[2, POI, 2.000, 196.39 km]]",
"Carrer Clara Campoamor, Santa Coloma de Gramenet [[2, STREET, 0.310, 39.00 km]]"
], ],
"amenities": [ "amenities": [
{ {
"name": "Pastisseria Santa Clara", "name": "Pastisseria Santa Clara",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1316,7 +1316,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
int iconId = menu.getRightIconId(); int iconId = menu.getRightIconId();
int sizeId = menu.isBigRightIcon() ? R.dimen.context_menu_big_icon_size : R.dimen.standard_icon_size; int sizeId = menu.isBigRightIcon() ? R.dimen.context_menu_big_icon_size : R.dimen.standard_icon_size;
if (menu.getPointDescription().isFavorite() || menu.getPointDescription().isWpt()) { if (menu.getPointDescription().isFavorite() || menu.getPointDescription().isWpt()) {
sizeId = R.dimen.favorites_icon_size; sizeId = R.dimen.favorites_my_places_icon_size;
} }
int iconViewSize = getResources().getDimensionPixelSize(sizeId); int iconViewSize = getResources().getDimensionPixelSize(sizeId);
ViewGroup.LayoutParams params = iconView.getLayoutParams(); ViewGroup.LayoutParams params = iconView.getLayoutParams();

View file

@ -350,11 +350,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());
@ -368,8 +368,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();
} }
} }
@ -381,8 +381,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;
@ -627,9 +627,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

@ -121,7 +121,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) {
@ -351,7 +351,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

@ -206,7 +206,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
private int getSmallIconId(String layer, int iconId) { private int getSmallIconId(String layer, int iconId) {
String iconName = view.getResources().getResourceEntryName(iconId); String iconName = view.getResources().getResourceEntryName(iconId);
return view.getResources().getIdentifier("map_" + iconName + "_" + layer + "_small" return view.getResources().getIdentifier("ic_" + iconName + "_" + layer + "_small"
, "drawable", view.getContext().getPackageName()); , "drawable", view.getContext().getPackageName());
} }

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 =