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;
public static enum StringMatcherMode {
// tests only first word as base starts with part
CHECK_ONLY_STARTS_WITH,
// tests all words (split by space) and one of word should start with a given part
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,
// tests all words (split by space) and one of word should be equal to part
CHECK_EQUALS_FROM_SPACE,
// simple collator contains in any part of the base
CHECK_CONTAINS,
CHECK_ONLY_STARTS_WITH_TRIM,
// simple collator 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) {
case CHECK_CONTAINS:
return ccontains(collator, base, part);
return ccontains(collator, fullName, part);
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:
return cstartsWith(collator, base, part, true, true, false, false);
return cstartsWith(collator, fullName, part, true, true, false);
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:
return cstartsWith(collator, base, part, true, false, false, false);
case CHECK_ONLY_STARTS_WITH_TRIM:
return cstartsWith(collator, base, part, true, false, false, true);
return cstartsWith(collator, fullName, part, true, false, false);
case CHECK_EQUALS:
return cstartsWith(collator, base, part, false, false, true, false);
return cstartsWith(collator, fullName, part, false, false, true);
}
return false;
}
@ -116,21 +119,14 @@ public class CollatorStringMatcher implements StringMatcher {
* Special check try to find as well in the middle of name
*
* @param collator
* @param searchInParam
* @param fullText
* @param theStart
* @param trim - trim theStart to searchInParam length if searchInParam non empty
* @return true if searchIn starts with token
*/
public static boolean cstartsWith(Collator collator, String searchInParam, String theStart,
boolean checkBeginning, boolean checkSpaces, boolean equals, boolean trim) {
String searchIn = searchInParam.toLowerCase(Locale.getDefault());
if (trim && searchIn.length() > 0) {
searchIn += " ";
}
public static boolean cstartsWith(Collator collator, String fullText, String theStart,
boolean checkBeginning, boolean checkSpaces, boolean equals) {
String searchIn = fullText.toLowerCase(Locale.getDefault());
int searchInLength = searchIn.length();
if (trim && searchInLength > 0 && theStart.length() > searchInLength) {
theStart = theStart.substring(0, searchInLength);
}
int startLength = theStart.length();
if (startLength == 0) {
return true;

View file

@ -13,10 +13,6 @@ public class CommonWords {
frequentlyUsedWordsDictionary.put(string, frequentlyUsedWordsDictionary.size());
}
public static int getCommon(String name) {
// if(true) {
// // not ready for old versions yet
// return -1;
// }
Integer i = commonWordsDictionary.get(name);
return i == null ? -1 : i.intValue();
}
@ -28,7 +24,15 @@ public class CommonWords {
public static int getCommonSearch(String 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) {

View file

@ -1,7 +1,6 @@
package net.osmand.search;
import net.osmand.Collator;
import net.osmand.OsmAndCollator;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
@ -72,7 +71,7 @@ public class SearchUICore {
taskQueue = new LinkedBlockingQueue<Runnable>();
searchSettings = new SearchSettings(new ArrayList<BinaryMapIndexReader>());
searchSettings = searchSettings.setLang(locale, transliterate);
phrase = new SearchPhrase(searchSettings, OsmAndCollator.primaryCollator());
phrase = SearchPhrase.emptyPhrase(searchSettings);
currentSearchResult = new SearchResultCollection(phrase);
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) {
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) {
NameStringMatcher nameStringMatcher = phrase.getNameStringMatcher();
NameStringMatcher nameStringMatcher = phrase.getFirstUnknownNameStringMatcher();
return nameStringMatcher.matches(object.localeName) || nameStringMatcher.matches(object.otherNames);
}
@ -714,16 +713,18 @@ public class SearchUICore {
@Override
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) {
if (phrase.getNameStringMatcher().matches(s)) {
if (phrase.getFirstUnknownNameStringMatcher().matches(s)) {
object.alternateName = s;
break;
}
}
// TODO
if (Algorithms.isEmpty(object.alternateName) && object.object instanceof Amenity) {
for (String value : ((Amenity) object.object).getAdditionalInfo().values()) {
if (phrase.getNameStringMatcher().matches(value)) {
if (phrase.getFirstUnknownNameStringMatcher().matches(value)) {
object.alternateName = value;
break;
}
@ -816,7 +817,7 @@ public class SearchUICore {
SearchExportSettings exportSettings = phrase.getSettings().getExportSettings();
json.put("settings", phrase.getSettings().toJSON());
json.put("phrase", phrase.getRawUnknownSearchPhrase());
json.put("phrase", phrase.getFullSearchPhrase());
if (searchResult.searchResults != null && searchResult.searchResults.size() > 0) {
JSONArray resultsArr = new JSONArray();
for (SearchResult r : searchResult.searchResults) {
@ -857,8 +858,8 @@ public class SearchUICore {
private enum ResultCompareStep {
TOP_VISIBLE,
FOUND_WORD_COUNT,
UNKNOWN_PHRASE_MATCH_WEIGHT,
FOUND_WORD_COUNT, // more is better (top)
UNKNOWN_PHRASE_MATCH_WEIGHT, // more is better (top)
SEARCH_DISTANCE_IF_NOT_BY_NAME,
COMPARE_FIRST_NUMBER_IN_NAME,
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> {
private SearchPhrase sp;
private Collator collator;
private LatLon loc;
private boolean sortByName;
public SearchResultComparator(SearchPhrase sp) {
this.sp = sp;
this.collator = sp.getCollator();
loc = sp.getLastTokenLocation();
sortByName = sp.isSortByName();

View file

@ -1,6 +1,7 @@
package net.osmand.search.core;
import net.osmand.CollatorStringMatcher;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapAddressReaderAdapter;
@ -20,7 +21,6 @@ import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
import net.osmand.search.SearchUICore.SearchResultMatcher;
import net.osmand.search.core.SearchPhrase.NameStringMatcher;
@ -48,8 +48,6 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import gnu.trove.list.array.TIntArrayList;
public class SearchCoreFactory {
@ -140,23 +138,67 @@ public class SearchCoreFactory {
return 0;
}
protected void subSearchApiOrPublish(SearchPhrase phrase,
SearchResultMatcher resultMatcher, SearchResult res, SearchBaseAPI api)
protected void subSearchApiOrPublish(SearchPhrase phrase, SearchResultMatcher resultMatcher, SearchResult res, SearchBaseAPI api)
throws IOException {
phrase.countUnknownWordsMatch(res);
// int cnt = resultMatcher.getCount();
List<String> ws = phrase.getUnknownSearchWords(res.otherWordsMatch);
if (!res.firstUnknownWordMatches) {
ws.add(phrase.getUnknownSearchWord());
phrase.countUnknownWordsMatchMainResult(res);
boolean firstUnknownWordMatches = res.firstUnknownWordMatches;
List<String> leftUnknownSearchWords = new ArrayList<String>(phrase.getUnknownSearchWords());
if(res.otherWordsMatch != null) {
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
if(newParentSearchResult != null) {
SearchResult prev = resultMatcher.setParentSearchResult(newParentSearchResult);
resultMatcher.publish(res);
if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) {
SearchPhrase nphrase = phrase.selectWord(res, ws,
phrase.isLastUnknownSearchWordComplete());
resultMatcher.setParentSearchResult(res);
resultMatcher.setParentSearchResult(prev);
} else {
resultMatcher.publish(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);
resultMatcher.setParentSearchResult(res.parentSearchResult);
resultMatcher.setParentSearchResult(prev);
}
}
@ -166,8 +208,6 @@ public class SearchCoreFactory {
}
}
public static class SearchRegionByNameAPI extends SearchBaseAPI {
public SearchRegionByNameAPI() {
@ -186,9 +226,9 @@ public class SearchCoreFactory {
sr.objectType = ObjectType.REGION;
sr.location = bmir.getRegionCenter();
sr.preferredZoom = 6;
if (phrase.getUnknownSearchWordLength() <= 1 && phrase.isNoSelectedType()) {
if (phrase.getFirstUnknownSearchWord().length() <= 1 && phrase.isNoSelectedType()) {
resultMatcher.publish(sr);
} else if (phrase.getNameStringMatcher().matches(sr.localeName)) {
} else if (phrase.getFirstUnknownNameStringMatcher().matches(sr.localeName)) {
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 {
private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000;
@ -310,10 +337,7 @@ public class SearchCoreFactory {
if (phrase.isNoSelectedType() && bbox != null
&& (phrase.isUnknownSearchWordPresent() || phrase.isEmptyQueryAllowed())
&& phrase.isSearchTypeAllowed(ObjectType.CITY)) {
String word = phrase.getUnknownWordToSearch();
NameStringMatcher nm = phrase.getNameStringMatcher(word, phrase.isUnknownSearchWordComplete());
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(word, true);
boolean firstUnknownWordMatches = word.equals(phrase.getUnknownSearchWord());
NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
resArray.clear();
resArray = townCitiesQR.queryInBox(bbox, resArray);
int limit = 0;
@ -335,8 +359,6 @@ public class SearchCoreFactory {
if (phrase.isEmptyQueryAllowed() && phrase.isEmpty()) {
resultMatcher.publish(res);
} else if (nm.matches(res.localeName) || nm.matches(res.otherNames)) {
res.firstUnknownWordMatches = firstUnknownWordMatches;
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
subSearchApiOrPublish(phrase, resultMatcher, res, cityApi);
}
if (limit++ > LIMIT * phrase.getRadiusLevel()) {
@ -348,7 +370,8 @@ public class SearchCoreFactory {
private void searchByName(final SearchPhrase phrase, final SearchResultMatcher resultMatcher)
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;
LatLon loc = phrase.getLastTokenLocation();
final List<SearchResult> immediateResults = new ArrayList<>();
@ -391,7 +414,7 @@ public class SearchCoreFactory {
if (object.getName().startsWith("<")) {
return false;
}
if (!phrase.getNameStringMatcher().matches(stripBraces(sr.localeName))) {
if (!phrase.getFirstUnknownNameStringMatcher().matches(stripBraces(sr.localeName))) {
sr.priorityDistance = 5;
}
sr.objectType = ObjectType.STREET;
@ -460,16 +483,13 @@ public class SearchCoreFactory {
};
Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(DEFAULT_ADDRESS_BBOX_RADIUS * 5,
SearchPhraseDataType.ADDRESS);
String wordToSearch = phrase.getUnknownWordToSearch();
NameStringMatcher wordEqualsMatcher = phrase.getNameStringMatcher(wordToSearch, true);
boolean firstUnknownWordMatches = wordToSearch.equals(phrase.getUnknownSearchWord());
while (offlineIterator.hasNext() && wordToSearch.length() > 0) {
BinaryMapIndexReader r = offlineIterator.next();
currentFile[0] = r;
immediateResults.clear();
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);
if (locSpecified) {
req.setBBoxRadius(loc.getLatitude(), loc.getLongitude(),
@ -477,13 +497,7 @@ public class SearchCoreFactory {
}
r.searchAddressDataByName(req);
for (SearchResult res : immediateResults) {
res.firstUnknownWordMatches = firstUnknownWordMatches;
res.unknownPhraseMatches = wordEqualsMatcher.matches(res.localeName);
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);
} else {
subSearchApiOrPublish(phrase, resultMatcher, res, cityApi);
@ -510,35 +524,31 @@ public class SearchCoreFactory {
if (!phrase.isUnknownSearchWordPresent()) {
return false;
}
boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent()
&& phrase.isUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes();
if (!phrase.isNoSelectedType()) {
// 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];
Iterator<BinaryMapIndexReader> offlineIterator = phrase.getRadiusOfflineIndexes(BBOX_RADIUS,
SearchPhraseDataType.POI);
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim();
String searchWord = hasUnselectedType ? unknownSearchPhrase : phrase.getUnknownWordToSearch();
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;
}
String searchWord = phrase.getUnknownWordToSearch();
final NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS_INSIDE);
final Set<String> ids = new HashSet<String>();
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
(int)bbox.centerX(), (int)bbox.centerY(),
searchWord,
(int)bbox.left, (int)bbox.right,
(int)bbox.top, (int)bbox.bottom,
new ResultMatcher<Amenity>() {
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest((int) bbox.centerX(),
(int) bbox.centerY(), searchWord, (int) bbox.left, (int) bbox.right, (int) bbox.top,
(int) bbox.bottom, new ResultMatcher<Amenity>() {
int limit = 0;
@Override
public boolean publish(Amenity object) {
if (phrase.getSettings().isExportObjects()) {
resultMatcher.exportObject(object);
}
if (limit ++ > LIMIT) {
if (limit++ > LIMIT) {
return false;
}
String poiID = object.getType().getKeyName() + "_" + object.getId();
@ -547,19 +557,17 @@ public class SearchCoreFactory {
}
SearchResult sr = new SearchResult(phrase);
sr.otherNames = object.getAllNames(true);
sr.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
if (phrase.isUnknownSearchWordComplete()) {
if(!nm.matches(sr.localeName) && !nm.matches(sr.otherNames) &&
!nm.matches(object.getAdditionalInfo().values())) {
sr.localeName = object.getName(phrase.getSettings().getLang(),
phrase.getSettings().isTransliterate());
if (!nm.matches(sr.localeName) && !nm.matches(sr.otherNames)
&& !nm.matches(object.getAdditionalInfo().values())) {
return false;
}
}
sr.object = object;
sr.preferredZoom = 17;
sr.file = currentFile[0];
sr.location = object.getLocation();
if (object.getSubType().equals("city") ||
object.getSubType().equals("country")) {
if (object.getSubType().equals("city") || object.getSubType().equals("country")) {
sr.priorityDistance = SEARCH_AMENITY_BY_NAME_CITY_PRIORITY_DISTANCE;
sr.preferredZoom = object.getSubType().equals("country") ? 7 : 13;
} else if (object.getSubType().equals("town")) {
@ -568,10 +576,7 @@ public class SearchCoreFactory {
sr.priorityDistance = 1;
}
sr.priority = SEARCH_AMENITY_BY_NAME_PRIORITY;
if (phraseMatcher != null) {
sr.unknownPhraseMatches = phraseMatcher.matches(sr.localeName);
}
phrase.countUnknownWordsMatch(sr);
phrase.countUnknownWordsMatchMainResult(sr);
sr.objectType = ObjectType.POI;
resultMatcher.publish(sr);
ids.add(poiID);
@ -580,7 +585,7 @@ public class SearchCoreFactory {
@Override
public boolean isCancelled() {
return resultMatcher.isCancelled() && (limit < LIMIT) ;
return resultMatcher.isCancelled() && (limit < LIMIT);
}
});
@ -633,9 +638,8 @@ public class SearchCoreFactory {
private List<AbstractPoiType> topVisibleFilters;
private List<PoiCategory> categories;
private List<CustomSearchPoiFilter> customPoiFilters = new ArrayList<>();
private TIntArrayList customPoiFiltersPriorites = new TIntArrayList();
private Map<String, Integer> activePoiFilters = new HashMap<>();
private MapPoiTypes types;
private List<String> filterOrders = new ArrayList<>();
public SearchAmenityTypesAPI(MapPoiTypes types) {
super(ObjectType.POI_TYPE);
@ -644,126 +648,164 @@ public class SearchCoreFactory {
public void clearCustomFilters() {
this.customPoiFilters.clear();
this.customPoiFiltersPriorites.clear();
}
public void addCustomFilter(CustomSearchPoiFilter poiFilter, int priority) {
this.customPoiFilters.add(poiFilter);
this.customPoiFiltersPriorites.add(priority);
if (priority > 0) {
this.activePoiFilters.put(poiFilter.getFilterId(), priority);
}
}
public void setFilterOrders(List<String> filterOrders) {
this.filterOrders = filterOrders;
public void setActivePoiFiltersByOrder(List<String> filterOrder) {
for (int i = 0; i < filterOrder.size(); i++) {
this.activePoiFilters.put(filterOrder.get(i), i);
}
}
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
if (translatedNames.isEmpty()) {
translatedNames = types.getAllTranslatedNames(false);
topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
}
List<AbstractPoiType> results = new ArrayList<AbstractPoiType>();
List<AbstractPoiType> 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);
}
public Map<AbstractPoiType, List<String>> getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) {
Map<AbstractPoiType, List<String>> results = new LinkedHashMap<>();
for (AbstractPoiType pf : topVisibleFilters) {
if (showTopFiltersOnly
|| nm.matches(pf.getTranslation())
|| nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getSynonyms())) {
results.add(pf);
searchWordTypes.add(pf);
checkPoiType(nm, pf, results);
}
}
if (!showTopFiltersOnly) {
for (PoiCategory c : categories) {
if (!results.contains(c)
&& (nm.matches(c.getTranslation())
|| nm.matches(c.getEnTranslation())
|| nm.matches(c.getSynonyms()))) {
results.add(c);
searchWordTypes.add(c);
}
checkPoiType(nm, c, results);
}
Iterator<Entry<String, PoiType>> it = translatedNames.entrySet().iterator();
while (it.hasNext()) {
Entry<String, PoiType> e = it.next();
PoiType pt = e.getValue();
if (pt.getCategory() != types.getOtherMapCategory()) {
if (!results.contains(pt)
&& (nm.matches(pt.getEnTranslation())
|| nm.matches(pt.getTranslation())
|| nm.matches(pt.getSynonyms()))) {
results.add(pt);
searchWordTypes.add(pt);
}
checkPoiType(nm, pt, results);
List<PoiType> additionals = pt.getPoiAdditionals();
if (additionals != null) {
if (additionals != null && includeAdditionals) {
for (PoiType a : additionals) {
if (!results.contains(a)) {
if (!results.containsKey(a)) {
String enTranslation = a.getEnTranslation().toLowerCase();
if (!"yes".equals(enTranslation) && !"no".equals(enTranslation)
&& (nm.matches(enTranslation) || nm.matches(a.getTranslation()) || nm.matches(a.getSynonyms()))) {
results.add(a);
if (!"yes".equals(enTranslation) && !"no".equals(enTranslation)) {
checkPoiType(nm, a, results);
}
}
}
}
}
}
return results;
}
phrase.setUnknownSearchWordPoiTypes(searchWordTypes);
if (resultMatcher != null) {
String word = phrase.getUnknownSearchWord();
NameStringMatcher startMatch = new NameStringMatcher(word, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
for (AbstractPoiType pt : results) {
private void checkPoiType(NameStringMatcher nm, AbstractPoiType pf, Map<AbstractPoiType, List<String>> results) {
List<String> lst = results.get(pf);
boolean nl = lst == null;
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);
res.localeName = pt.getTranslation();
res.object = pt;
res.priorityDistance = 0;
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);
addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(pt), res);
}
} else {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY;
resultMatcher.publish(res);
boolean includeAdditional = !phrase.hasMoreThanOneUnknownSearchWord();
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++) {
CustomSearchPoiFilter csf = customPoiFilters.get(i);
if (!phrase.isUnknownSearchWordPresent() || nm.matches(csf.getName())) {
if (showTopFiltersOnly || nm.matches(csf.getName())) {
SearchResult res = new SearchResult(phrase);
res.localeName = csf.getName();
res.object = csf;
res.objectType = ObjectType.POI_TYPE;
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);
}
}
addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, csf.getFilterId(), res);
}
}
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) {
return STD_POI_FILTER_PREFIX + poi.getKeyName();
}
@ -792,8 +834,10 @@ public class SearchCoreFactory {
public static class SearchAmenityByTypeAPI extends SearchBaseAPI {
private static final int BBOX_RADIUS = 10000;
private SearchAmenityTypesAPI searchAmenityTypesAPI;
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) {
super(ObjectType.POI);
@ -816,95 +860,82 @@ public class SearchCoreFactory {
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) {
pt.putTypes(acceptedTypes);
if (pt instanceof PoiType && ((PoiType) pt).isAdditional() && ((PoiType) pt).getParentType() != null) {
fillPoiAdditionals(((PoiType) pt).getParentType());
} 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);
}
poiAdditionals.put(pt.getKeyName(), (PoiType) pt);
}
}
@Override
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)) {
Object obj = phrase.getLastSelectedWord().getResult().object;
SearchPoiTypeFilter ptf;
if (obj instanceof AbstractPoiType) {
ptf = getPoiTypeFilter((AbstractPoiType) obj);
poiTypeFilter = getPoiTypeFilter((AbstractPoiType) obj);
} else if (obj instanceof SearchPoiTypeFilter) {
ptf = (SearchPoiTypeFilter) obj;
poiTypeFilter = (SearchPoiTypeFilter) obj;
} else {
throw new UnsupportedOperationException();
}
searchPoi(phrase, resultMatcher, obj, null, ptf);
} else if (searchAmenityTypesAPI != null) {
if (phrase.getUnknownSearchWordPoiTypes() == null) {
searchAmenityTypesAPI.search(phrase, null);
nameFilter = phrase.getUnknownSearchPhrase();
} else if (searchAmenityTypesAPI != null && phrase.isFirstUnknownSearchWordComplete()) {
NameStringMatcher nm = phrase.getFirstUnknownNameStringMatcher();
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();
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);
nameFilter += otherSearchWords.get(k);
}
}
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;
}
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,
final String customName, final BinaryMapIndexReader selected,
final Set<String> searchedPois) {
String unknownSearchPhrase = phrase.getUnknownSearchPhrase().trim();
final NameStringMatcher phraseMatcher;
if (!Algorithms.isEmpty(unknownSearchPhrase)) {
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();
}
private ResultMatcher<Amenity> getResultMatcher(final SearchPhrase phrase, final SearchPoiTypeFilter poiTypeFilter,
final SearchResultMatcher resultMatcher, final String nameFilter,
final BinaryMapIndexReader selected, final Set<String> searchedPois,
final int countExtraWords) {
NameStringMatcher ns = nameFilter == null ? null : new NameStringMatcher(nameFilter, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
return new ResultMatcher<Amenity>() {
@Override
@ -914,12 +945,24 @@ public class SearchCoreFactory {
}
SearchResult res = new SearchResult(phrase);
String poiID = object.getType().getKeyName() + "_" + object.getId();
if(!searchedPois.add(poiID)) {
if (!searchedPois.add(poiID)) {
return false;
}
if(object.isClosed()) {
if (object.isClosed()) {
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.otherNames = object.getAllNames(true);
if (Algorithms.isEmpty(res.localeName)) {
@ -930,15 +973,19 @@ public class SearchCoreFactory {
res.localeName = object.getSubType();
}
}
if (phrase.isUnknownSearchWordPresent()
&& !(ns.matches(res.localeName) || ns.matches(res.otherNames))) {
if (ns != null) {
if (ns.matches(res.localeName) || ns.matches(res.otherNames)) {
phrase.countUnknownWordsMatchMainResult(res, countExtraWords);
} else {
String ref = object.getTagContent(Amenity.REF, null);
if(ref == null || !ns.matches(ref)) {
if (ref == null || !ns.matches(ref)) {
return false;
} else {
phrase.countUnknownWordsMatch(res, ref, null, countExtraWords);
res.localeName += " " + ref;
}
}
}
res.object = object;
res.preferredZoom = 17;
@ -946,16 +993,6 @@ public class SearchCoreFactory {
res.location = object.getLocation();
res.priority = SEARCH_AMENITY_BY_TYPE_PRIORITY;
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;
resultMatcher.publish(res);
return false;
@ -969,7 +1006,6 @@ public class SearchCoreFactory {
}
private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt) {
acceptedTypes.clear();
poiAdditionals.clear();
updateTypesToAccept(pt);
@ -1045,16 +1081,8 @@ public class SearchCoreFactory {
sw.getResult().file.preloadStreets(c, null);
}
int limit = 0;
String wordToSearch = phrase.getUnknownWordToSearch();
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);
}
NameStringMatcher nm = phrase.getMainUnknownNameStringMatcher();
for (Street object : c.getStreets()) {
SearchResult res = new SearchResult(phrase);
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))) {
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.object = object;
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 {
Street cacheBuilding;
@ -1179,7 +1196,7 @@ public class SearchCoreFactory {
});
}
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);
for (Building b : s.getBuildings()) {
SearchResult res = new SearchResult(phrase);
@ -1194,6 +1211,7 @@ public class SearchCoreFactory {
res.file = file;
res.priority = priority;
res.priorityDistance = 0;
// TOOO phrase.countUnknownWordsMatchMainResult(res);
res.firstUnknownWordMatches = startMatch.matches(res.localeName);
res.relatedObject = s;
res.localeRelatedObjectName = s.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
@ -1208,7 +1226,7 @@ public class SearchCoreFactory {
resultMatcher.publish(res);
}
String streetIntersection = phrase.getUnknownWordToSearch();
NameStringMatcher streetMatch = phrase.getNameStringMatcher(streetIntersection, phrase.isLastUnknownSearchWordComplete());
NameStringMatcher streetMatch = phrase.getMainUnknownNameStringMatcher();
if (Algorithms.isEmpty(streetIntersection) ||
(!Character.isDigit(streetIntersection.charAt(0)) &&
CommonWords.getCommonSearch(streetIntersection) == -1) ) {
@ -1218,6 +1236,7 @@ public class SearchCoreFactory {
|| !phrase.isSearchTypeAllowed(ObjectType.STREET_INTERSECTION)) {
continue;
}
// TOOO phrase.countUnknownWordsMatchMainResult(res);
res.otherNames = street.getAllNames(true);
res.localeName = street.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate());
res.object = street;
@ -1404,4 +1423,22 @@ public class SearchCoreFactory {
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;
import net.osmand.Collator;
import net.osmand.CollatorStringMatcher;
import net.osmand.CollatorStringMatcher;import net.osmand.OsmAndCollator;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.StringMatcher;
import net.osmand.binary.BinaryMapIndexReader;
@ -9,7 +9,6 @@ import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.CommonWords;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.osm.AbstractPoiType;
import net.osmand.util.Algorithms;
import net.osmand.util.LocationParser;
import net.osmand.util.MapUtils;
@ -27,31 +26,41 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
//immutable object
// Immutable object !
public class SearchPhrase {
private List<SearchWord> words = new ArrayList<>();
private List<String> unknownWords = new ArrayList<>();
private List<NameStringMatcher> unknownWordsMatcher = new ArrayList<>();
private String unknownSearchWordTrim;
private String rawUnknownSearchPhrase = "";
private String unknownSearchPhrase = "";
private AbstractPoiType unknownSearchWordPoiType;
private List<AbstractPoiType> unknownSearchWordPoiTypes = null;
private NameStringMatcher sm;
private SearchSettings settings;
private List<BinaryMapIndexReader> indexes;
private QuadRect cache1kmRect;
private boolean lastUnknownSearchWordComplete;
private static final String DELIMITER = " ";
public static final String DELIMITER = " ";
private static final String ALLDELIMITERS = "\\s|,";
private static final Pattern reg = Pattern.compile(ALLDELIMITERS);
private Collator clt;
private static Comparator<String> commonWordsComparator;
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 {
// 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.clt = clt;
}
@ -149,97 +158,173 @@ public class SearchPhrase {
return clt;
}
public SearchPhrase generateNewPhrase(String text, SearchSettings settings) {
SearchPhrase sp = new SearchPhrase(settings, this.clt);
String restText = text;
String textToSearch = text;
List<SearchWord> leftWords = this.words;
String thisTxt = getText(true);
List<SearchWord> foundWords = new ArrayList<>();
if (text.startsWith(thisTxt)) {
// string is longer
restText = text.substring(getText(false).length());
sp.words = new ArrayList<>(this.words);
textToSearch = text.substring(getText(false).length());
foundWords.addAll(this.words);
leftWords = leftWords.subList(leftWords.size(), leftWords.size());
}
for(SearchWord w : leftWords) {
if(restText.startsWith(w.getWord() + DELIMITER)) {
sp.words.add(w);
restText = restText.substring(w.getWord().length() + DELIMITER.length());
for (SearchWord w : leftWords) {
if (textToSearch.startsWith(w.getWord() + DELIMITER)) {
foundWords.add(w);
textToSearch = textToSearch.substring(w.getWord().length() + DELIMITER.length());
} else {
break;
}
}
sp.rawUnknownSearchPhrase = text;
sp.unknownSearchPhrase = restText;
sp.unknownWords.clear();
sp.unknownWordsMatcher.clear();
SearchPhrase sp = createNewSearchPhrase(settings, text, foundWords, textToSearch);
return sp;
}
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 {
sp.unknownSearchWordTrim = "";
String[] ws = restText.split(ALLDELIMITERS);
sp.firstUnknownSearchWord = "";
String[] ws = textToSearch.split(ALLDELIMITERS);
boolean first = true;
for (int i = 0; i < ws.length ; i++) {
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) {
sp.unknownSearchWordTrim = wd;
sp.firstUnknownSearchWord = wd;
first = false;
} 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;
}
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() {
return words;
}
public boolean isUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete || unknownWords.size() > 0 || unknownSearchWordPoiType != null;
public boolean isMainUnknownSearchWordComplete() {
// return lastUnknownSearchWordComplete || otherUnknownWords.size() > 0 || unknownSearchWordPoiType != null;
return mainUnknownSearchWordComplete;
}
public boolean isLastUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete;
}
public boolean hasMoreThanOneUnknownSearchWord() {
return otherUnknownWords.size() > 0;
}
public List<String> getUnknownSearchWords() {
return unknownWords;
}
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;
return otherUnknownWords;
}
public String getUnknownSearchWord() {
return unknownSearchWordTrim;
public String getFirstUnknownSearchWord() {
return firstUnknownSearchWord;
}
public String getRawUnknownSearchPhrase() {
return rawUnknownSearchPhrase;
public boolean isFirstUnknownSearchWordComplete() {
return hasMoreThanOneUnknownSearchWord() || isLastUnknownSearchWordComplete();
}
public String getFullSearchPhrase() {
return fullTextSearchPhrase;
}
public String getUnknownSearchPhrase() {
@ -247,64 +332,7 @@ public class SearchPhrase {
}
public boolean isUnknownSearchWordPresent() {
return unknownSearchWordTrim.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;
return firstUnknownSearchWord.length() > 0;
}
public QuadRect getRadiusBBoxToSearch(int radius) {
@ -459,31 +487,6 @@ public class SearchPhrase {
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) {
SearchWord sw = new SearchWord(res.wordsSpan != null ? res.wordsSpan : res.localeName.trim(), res);
@ -513,16 +516,32 @@ public class SearchPhrase {
return null;
}
public NameStringMatcher getNameStringMatcher() {
if(sm != null) {
return sm;
public NameStringMatcher getMainUnknownNameStringMatcher() {
calcMainUnknownWordToSearch();
if (mainUnknownNameStringMatcher == null) {
mainUnknownNameStringMatcher = getNameStringMatcher(mainUnknownWordToSearch, mainUnknownSearchWordComplete);
}
sm = getNameStringMatcher(unknownSearchWordTrim, lastUnknownSearchWordComplete);
return sm;
return mainUnknownNameStringMatcher;
}
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,
(complete ?
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();
for(SearchWord s : words) {
sb.append(s.getWord()).append(DELIMITER.trim() + " ");
sb.append(s.getWord()).append(DELIMITER);
}
if(includeLastWord) {
if(includeUnknownPart) {
sb.append(unknownSearchPhrase);
}
return sb.toString();
@ -558,11 +577,11 @@ public class SearchPhrase {
public String getTextWithoutLastWord() {
StringBuilder sb = new StringBuilder();
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);
}
for(SearchWord s : words) {
sb.append(s.getWord()).append(DELIMITER.trim() + " ");
sb.append(s.getWord()).append(DELIMITER);
}
return sb.toString();
}
@ -705,8 +724,8 @@ public class SearchPhrase {
private CollatorStringMatcher sm;
public NameStringMatcher(String lastWordTrim, StringMatcherMode mode) {
sm = new CollatorStringMatcher(lastWordTrim, mode);
public NameStringMatcher(String namePart, StringMatcherMode mode) {
sm = new CollatorStringMatcher(namePart, mode);
}
public boolean matches(Collection<String> map) {
@ -728,35 +747,53 @@ public class SearchPhrase {
}
public void countUnknownWordsMatch(SearchResult sr) {
countUnknownWordsMatch(sr, sr.localeName, sr.otherNames);
public int countUnknownWordsMatchMainResult(SearchResult sr) {
return countUnknownWordsMatch(sr, sr.localeName, sr.otherNames, 0);
}
public void countUnknownWordsMatch(SearchResult sr, String localeName, Collection<String> otherNames) {
if (unknownWords.size() > 0) {
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));
public int countUnknownWordsMatchMainResult(SearchResult sr, int amountMatchingWords) {
return countUnknownWordsMatch(sr, sr.localeName, sr.otherNames, amountMatchingWords);
}
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)) {
match = true;
}
}
if (match) {
if (sr.otherWordsMatch == null) {
sr.otherWordsMatch = new TreeSet<>();
}
sr.otherWordsMatch.add(unknownWords.get(i));
sr.otherWordsMatch.add(otherUnknownWords.get(i));
r++;
}
}
}
if(!sr.firstUnknownWordMatches) {
sr.firstUnknownWordMatches = localeName.equals(getUnknownSearchWord()) ||
getNameStringMatcher().matches(localeName) ||
getNameStringMatcher().matches(otherNames);
if (amountMatchingWords > 0) {
sr.firstUnknownWordMatches = true;
r++;
} 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) {
int res = meters;
for(int k = 0; k < radiusLevel; k++) {
@ -777,17 +814,38 @@ public class SearchPhrase {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
private int getUnknownWordToSearchBuildingInd() {
if (otherUnknownWords.size() > 0 && Algorithms.extractFirstIntegerNumber(getFirstUnknownSearchWord()) == 0) {
int ind = 0;
for (String wrd : otherUnknownWords) {
ind++;
if (Algorithms.extractFirstIntegerNumber(wrd) != 0) {
return ind;
}
}
}
return 0;
}
public NameStringMatcher getUnknownWordToSearchBuildingNameMatcher() {
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return getUnknownNameStringMatcher(ind - 1);
} else {
return getFirstUnknownNameStringMatcher();
}
}
public String getUnknownWordToSearchBuilding() {
List<String> unknownSearchWords = getUnknownSearchWords();
if(unknownSearchWords.size() > 0 && Algorithms.extractFirstIntegerNumber(getUnknownSearchWord()) == 0) {
for(String wrd : unknownSearchWords) {
if(Algorithms.extractFirstIntegerNumber(wrd) != 0) {
return wrd;
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return otherUnknownWords.get(ind - 1);
} else {
return firstUnknownSearchWord;
}
}
}
return getUnknownSearchWord();
}
private static int lengthWithoutNumbers(String s) {
int len = 0;
@ -802,20 +860,21 @@ public class SearchPhrase {
}
public String getUnknownWordToSearch() {
List<String> unknownSearchWords = getUnknownSearchWords();
String wordToSearch = getUnknownSearchWord();
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;
calcMainUnknownWordToSearch();
return mainUnknownWordToSearch;
}
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
public SearchPhrase requiredSearchPhrase;
// internal package fields (used for sorting)
public SearchResult parentSearchResult;
String wordsSpan ;
boolean firstUnknownWordMatches;
Collection<String> otherWordsMatch = null;
public Object object;
public ObjectType objectType;
public BinaryMapIndexReader file;
public double priority;
public double priorityDistance;
public String wordsSpan ;
public SearchResult parentSearchResult;
public Collection<String> otherWordsMatch = null;
public boolean firstUnknownWordMatches = true;
public boolean unknownPhraseMatches = false;
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;
public SearchResult(SearchPhrase sp) {
this.requiredSearchPhrase = sp;
}
private static final double MAX_TYPE_WEIGHT = 10;
// maximum corresponds to the top entry
public double getUnknownPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it highers
double res = 0;
if (unknownPhraseMatches) {
res = ObjectType.getTypeWeight(objectType);
return getSumPhraseMatchWeight() / Math.pow(MAX_TYPE_WEIGHT, getDepth() - 1);
}
public double getSumPhraseMatchWeight() {
// if result is a complete match in the search we prioritize it highers
double res = ObjectType.getTypeWeight(objectType);
if (parentSearchResult != null) {
// 10 > maximum type
// res = Math.max(res,parentSearchResult.getUnknownPhraseMatchWeight()) ;
res += parentSearchResult.getUnknownPhraseMatchWeight() / 10;
res = res + parentSearchResult.getSumPhraseMatchWeight() / MAX_TYPE_WEIGHT;
}
return res;
}
public int getDepth() {
if (parentSearchResult != null) {
return 1 + parentSearchResult.getDepth();
}
return 1;
}
public int getFoundWordCount() {
int inc = 0;
if (firstUnknownWordMatches) {
@ -77,16 +99,6 @@ public class SearchResult {
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
public String toString() {

View file

@ -17,7 +17,7 @@ public class LocationSearchTest {
private void search(String string, LatLon latLon) throws IOException {
SearchResultMatcher srm = new SearchUICore.SearchResultMatcher(null, null, 0, null, 100);
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(latLon, srm.getRequestResults().get(0).location);
}

View file

@ -8,7 +8,6 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import net.osmand.OsmAndCollator;
import net.osmand.data.LatLon;
import net.osmand.search.SearchUICore.SearchResultCollection;
import net.osmand.search.core.SearchPhrase;
@ -29,7 +28,7 @@ public class SearchUICoreGenericTest {
public void testDuplicates() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null);
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);
List<SearchResult> rs = new ArrayList<>();
SearchResult a1 = searchResult(rs, phrase, "a", 100);
@ -47,7 +46,7 @@ public class SearchUICoreGenericTest {
public void testNoResort() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null);
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);
List<SearchResult> rs = new ArrayList<>();
SearchResult a1 = searchResult(rs, phrase, "a", 100);
@ -80,7 +79,7 @@ public class SearchUICoreGenericTest {
public void testNoResortDuplicate() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null);
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);
List<SearchResult> rs = new ArrayList<>();
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.SearchSettings;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
@RunWith(Parameterized.class)
public class SearchUICoreTest {
@ -99,7 +100,20 @@ public class SearchUICoreTest {
BinaryMapIndexReaderTest reader = new BinaryMapIndexReaderTest();
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");
if (sourceJson.has("amenities")) {
JSONArray amenitiesArr = sourceJson.getJSONArray("amenities");
@ -135,26 +149,25 @@ public class SearchUICoreTest {
reader.matchedCities = matchedCities;
reader.streetCities = streetCities;
}
List<String> results = new ArrayList<>();
if (sourceJson.has("results")) {
JSONArray resultsArr = sourceJson.getJSONArray("results");
for (int i = 0; i < resultsArr.length(); i++) {
results.add(resultsArr.getString(i));
List<List<String>> results = new ArrayList<>();
for (int i = 0; i < phrases.size(); i++) {
results.add(new ArrayList<String>());
}
if (sourceJson.has("results")) {
parseResults(sourceJson, "results", results);
}
if (TEST_EXTRA_RESULTS && sourceJson.has("extra-results")) {
JSONArray resultsArr = sourceJson.getJSONArray("extra-results");
for (int i = 0; i < resultsArr.length(); i++) {
results.add(resultsArr.getString(i));
parseResults(sourceJson, "extra-results", results);
}
Assert.assertEquals(phrases.size(), results.size());
if (phrases.size() != results.size()) {
return;
}
SearchSettings s = SearchSettings.parseJSON(settingsJson);
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);
core.init();
@ -169,6 +182,13 @@ public class SearchUICoreTest {
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);
core.searchInternal(phrase, matcher);
@ -176,24 +196,61 @@ public class SearchUICoreTest {
collection.addSearchResults(matcher.getRequestResults(), true, true);
List<SearchResult> searchResults = collection.getCurrentSearchResults();
int i = 0;
for (SearchResult result : searchResults) {
String expected = results.get(i++);
String present = result.toString();
for (SearchResult res : searchResults) {
String expected = result.get(i++);
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)) {
System.out.println(String.format("Mismatch for '%s' != '%s' (%d, %.3f, %s). Result: ", expected,
present, result.getFoundWordCount(), result.getUnknownPhraseMatchWeight(), result.objectType.toString()));
System.out.println(String.format("Phrase: %s", phrase));
System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present));
for (SearchResult r : searchResults) {
// System.out.println(String.format("\t\"%s\",", r.toString()));
System.out.println(String.format("\"%s\", (%d, %.3f, %s),", r.toString(),
r.getFoundWordCount(), r.getUnknownPhraseMatchWeight(), r.objectType.toString()));
System.out.println(String.format("\t\"%s\",", formatResult(false, r, phrase)));
}
}
Assert.assertEquals(expected, present);
if (i >= results.size()) {
if (i >= result.size()) {
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 {

View file

@ -9,14 +9,144 @@
"emptyQueryAllowed": false,
"sortByName": false
},
"phrase": "100 Bridge Street",
"phrases": [ "100 bridge", "100 bridge street", "100 bridge street westbrook" ],
"results": [
"100.0, <input> ",
"100, Bridge Street, Westbrook",
"100, Bridge Street, Yarmouth",
"Bridge Street",
"Bridge Street Dam",
"Bridge Street"
[
"100.0, <input> [[1, PARTIAL_LOCATION, 1.000, 5591.91 km]]",
"100, Bridge Street, Westbrook [[2, HOUSE, 0.430, 11.29 km]]",
"100, Bridge Street, Yarmouth [[2, HOUSE, 0.430, 23.69 km]]"
],
[
"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": [
{

View file

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

View file

@ -11,17 +11,26 @@
},
"phrase": "Burger King",
"results": [
"Burger (Cafe / Cafe and restaurant)",
"Burger (Pub / Food)",
"Burger (Bar / Food)",
"Burger (Restaurant / Cafe and restaurant)",
"Burger (Biergarten / Food)",
"Burger (Fast food / Food)",
"Burger King",
"Burger King",
"Burger King",
"Burger King",
"Burger King"
"Burger King Thiendorf [[2, POI, 2.000, 46.35 km]]",
"Burger King [[2, POI, 2.000, 46.75 km]]",
"Burger King [[2, POI, 2.000, 57.61 km]]",
"Burger King [[2, POI, 2.000, 58.23 km]]",
"Burger King [[2, POI, 2.000, 59.20 km]]",
"Burger King [[2, POI, 2.000, 66.93 km]]",
"Burger King Riesa [[2, POI, 2.000, 78.15 km]]",
"Burger King [[2, POI, 2.000, 118.29 km]]",
"Bürger King Chemnitz [[2, POI, 2.000, 121.13 km]]",
"Burger King Chemnitz [[2, POI, 2.000, 123.17 km]]",
"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": [
{

View file

@ -11,25 +11,70 @@
},
"phrase": "carrer de Vic, Sant Bartomeu del grau",
"results": [
"Carrer de Sant Bartomeu del Grau, Vic",
"Carrer de Vic, Sant Bartomeu del Grau",
"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"
"Carrer de Vic, Sant Bartomeu del Grau [[7, STREET, 0.310, 64.33 km]]",
"Carrer de Sant Bartomeu del Grau, Vic [[7, STREET, 0.310, 61.63 km]]"
],
"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": [
{
"name": "Collada de Sant Bartomeu",

View file

@ -9,24 +9,60 @@
"emptyQueryAllowed": false,
"sortByName": false
},
"phrase": "parking",
"phrase": "parking ",
"results": [
"Parking (Personal transport)",
"Parking entrance (Personal transport)",
"Parking fee (Charging station / Transportation)",
"Parking fee: no (Charging station / Transportation)",
"Parking fee: yes (Charging station / Transportation)",
"Parking lot (Fire hydrant / Emergency infrastructure)",
"Parking space (Personal transport)",
"Parking tickets (Vending machine / Store)",
"Parking tickets (Vending machine / Store)",
"Parking time limit (Parking / Personal transport)",
"Bicycle parking (Bicycle transport)",
"Motorcycle parking (Personal transport)",
"Parking",
"Parking",
"Parking",
"Parking"
"Parking (Personal transport) [[1, POI_TYPE, 1.000, 0.00 km]]",
"для посетителей [[0, POI, 2.000, 0.03 km]]",
"Parking [[0, POI, 2.000, 0.05 km]]",
"Parking [[0, POI, 2.000, 0.11 km]]",
"Parking [[0, POI, 2.000, 0.16 km]]",
"Parking [[0, POI, 2.000, 0.17 km]]",
"Parking [[0, POI, 2.000, 0.23 km]]",
"Parking [[0, POI, 2.000, 0.35 km]]",
"Parking [[0, POI, 2.000, 0.40 km]]",
"Parking [[0, POI, 2.000, 0.48 km]]",
"Parking [[0, POI, 2.000, 0.49 km]]",
"Parking [[0, POI, 2.000, 0.55 km]]",
"Автостоянка №1 [[0, POI, 2.000, 0.56 km]]",
"Parking [[0, POI, 2.000, 0.58 km]]",
"Parking [[0, POI, 2.000, 0.61 km]]",
"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": [
{

View file

@ -11,17 +11,18 @@
},
"phrase": "48 Free Street Portland",
"results": [
"48.0, <input> ",
"48, Free Street (Downtown), Portland"
"48.0, <input> [[0, PARTIAL_LOCATION, 1.000, 5274.99 km]]",
"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": [
"48, Portland Street, North Berwick",
"Free Street (Downtown), Portland",
"Free Street (Ferry Village), South Portland",
"Portland Street",
"Portland Street (Downtown), Portland",
"Portland Street Pier, South Portland",
"Portland Street, Yarmouth"
"Portland Street (Downtown), Portland [[2, STREET, 3.000, 0.62 km]]",
"Portland Street Pier, South Portland [[2, STREET, 3.000, 1.43 km]]",
"Portland Street, Yarmouth [[2, STREET, 3.000, 16.13 km]]",
"Portland Street, North Berwick [[2, STREET, 3.000, 54.37 km]]",
"Portland Street, Berwick [[2, STREET, 3.000, 59.60 km]]"
],
"amenities": [
{

View file

@ -11,9 +11,9 @@
},
"phrase": "Київ Саксаганського вулиця 32",
"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": [
{

View file

@ -11,69 +11,28 @@
},
"phrase": "Calle de las eras 5, Navacerrada",
"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": [
"Calle de las Eras (Uranización Los Corales), Navacerrada",
"Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada",
"Calle del Puerto de Navacerrada, Las Nieves",
"5, Calle Navacerrada (Urb. Las Suertes), Las Suertes",
"50, Calle de Francisco Navacerrada, Salamanca",
"52, Calle de Francisco Navacerrada, Salamanca",
"53, Calle de Francisco Navacerrada, Salamanca",
"54, Calle de Francisco Navacerrada, Salamanca",
"55, Calle de Francisco Navacerrada, Salamanca",
"56, Calle de Francisco Navacerrada, Salamanca",
"57, Calle de Francisco Navacerrada, Salamanca",
"58, Calle de Francisco Navacerrada, Salamanca",
"59, Calle de Francisco Navacerrada, Salamanca",
"Pasaje de las Eras (Uranización Los Corales), Navacerrada",
"Calle Barrio de las Peñas, Navacerrada",
"Calle de las Cruces (Residencial Sanabria), Navacerrada",
"Calle de las Escuelas, Navacerrada",
"Calle de las Huertas (Residencial Sanabria), Navacerrada",
"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»"
"5, Calle Navacerrada (Urb. Las Suertes), Las Suertes [[4, HOUSE, 0.430, 60.50 km]]",
"50, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.37 km]]",
"52, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"53, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.38 km]]",
"54, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"55, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.38 km]]",
"56, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.36 km]]",
"57, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.37 km]]",
"58, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.35 km]]",
"59, Calle de Francisco Navacerrada, Salamanca [[4, HOUSE, 0.430, 26.35 km]]",
"Pasaje de las Eras (Uranización Los Corales), Navacerrada [[4, STREET, 0.310, 70.23 km]]",
"Calle del Puerto de Navacerrada, Las Nieves [[4, STREET, 0.310, 33.80 km]]",
"Calle Barrio de las Peñas, Navacerrada [[4, STREET, 0.310, 70.10 km]]",
"Calle de las Cruces (Residencial Sanabria), Navacerrada [[4, STREET, 0.310, 70.14 km]]",
"Calle de las Escuelas, Navacerrada [[4, STREET, 0.310, 70.17 km]]",
"Calle de las Huertas (Residencial Sanabria), Navacerrada [[4, STREET, 0.310, 70.18 km]]",
"Calle de la Virgen de las Nieves, Puerto de Navacerrada [[4, STREET, 0.310, 74.59 km]]",
"Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada [[4, STREET_INTERSECTION, 0.043, 70.23 km]]"
],
"amenities": [
{

View file

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

View file

@ -9,18 +9,66 @@
"emptyQueryAllowed": false,
"sortByName": false
},
"phrase": "Biergarten",
"phrase": "Biergarten ",
"results": [
"Biergarten (Food)",
"Biergarten Italienisches Dörfchen",
"Biergarten Narrenhäus'l",
"Biergarten Elbsegler",
"Biergarten Elbsegler",
"Biergarten",
"Biergarten",
"Biergarten",
"Biergarten",
"Biergarten"
"Biergarten (Food) [[1, POI_TYPE, 1.000, 0.00 km]]",
"Biergarten Italienisches Dörfchen [[1, POI, 2.000, 0.55 km]]",
"Biergarten Narrenhäus'l [[1, POI, 2.000, 0.84 km]]",
"Biergarten Elbsegler [[1, POI, 2.000, 0.89 km]]",
"Biergarten Elbsegler [[1, POI, 2.000, 0.90 km]]",
"Körnergarten [[1, POI, 2.000, 5.18 km]]",
"Biergarten Goldener Anker [[1, POI, 2.000, 9.78 km]]",
"Palais Bistro [[0, POI, 2.000, 0.29 km]]",
"Augustus Garten am Narrenhäusl [[0, POI, 2.000, 0.88 km]]",
"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": [
{

View file

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

View file

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

View file

@ -11,13 +11,18 @@
},
"phrase": "комсомольская",
"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": [
{

View file

@ -11,15 +11,71 @@
},
"phrase": "ленина 30",
"results": [
"30А, улица Ленина, Заинск",
"30Б, улица Ленина, Заинск",
"30, улица Ленина, Сарманово",
"30, улица Ленина, Большое Афанасово",
"30, улица Ленина, Альметьевск",
"30А, улица Ленина, Альметьевск",
"улица Ленина, Заинск",
"улица Ленина, Аксарино",
"улица Ленина, Светлое Озеро"
"30А, улица Ленина, Заинск [[2, HOUSE, 0.430, 1.33 km]]",
"30Б, улица Ленина, Заинск [[2, HOUSE, 0.430, 1.25 km]]",
"30, улица Ленина, Сарманово [[2, HOUSE, 0.430, 37.20 km]]",
"30, улица Ленина, Большое Афанасово [[2, HOUSE, 0.430, 38.21 km]]",
"30, улица Ленина, Альметьевск [[2, HOUSE, 0.430, 46.58 km]]",
"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": [
{

View file

@ -11,18 +11,140 @@
},
"phrase": "rue émile",
"results": [
"Rue Émile Gérard, Liège",
"Rue Emile Vandervelde, Liège",
"Rue Emile Vandervelde - Rue Sainte-Marguerite, Liège",
"Rue Émile Zola (Laveu), Liège",
"Rue Émile Collard, Liège",
"Rue Emile Vandervelde, Vottem",
"Rue Emile Vandervelde (Vottem), Herstal",
"Rue Émile Verhaeren, Liège",
"Rue Émile Jeanne, Saint-Nicolas",
"Rue Emile Muraille, Herstal",
"Rue Emile Verhaeren, Grâce-Hollogne",
"Rue Emile Vinck, Herstal"
"Rue Émile Gérard, Liège [[2, STREET, 3.000, 1.42 km]]",
"Rue Emile Vandervelde, Liège [[2, STREET, 3.000, 1.66 km]]",
"Rue Emile Vandervelde - Rue Sainte-Marguerite, Liège [[2, STREET, 3.000, 1.74 km]]",
"Rue Émile Zola (Laveu), Liège [[2, STREET, 3.000, 1.98 km]]",
"Rue Émile Collard, Liège [[2, STREET, 3.000, 2.49 km]]",
"Rue Emile Vandervelde, Vottem [[2, STREET, 3.000, 3.22 km]]",
"Rue Emile Vandervelde (Vottem), Herstal [[2, STREET, 3.000, 3.23 km]]",
"Rue Émile Verhaeren, Liège [[2, STREET, 3.000, 3.58 km]]",
"Rue Émile Jeanne, Saint-Nicolas [[2, STREET, 3.000, 4.03 km]]",
"Rue Emile Muraille, Herstal [[2, STREET, 3.000, 4.70 km]]",
"Rue Emile Verhaeren, Grâce-Hollogne [[2, STREET, 3.000, 4.71 km]]",
"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": [
{

View file

@ -11,29 +11,60 @@
},
"phrase": "santa clara",
"results": [
"Carrer de Santa Clara, Sant Pol de Mar",
"Santa Clara, Sant Pol de Mar",
"Carrer Santa Clara, Sant Pol de Mar",
"Plaça Santa Clara, Santa Coloma de Farners",
"Carrer del Comte de Santa Clara, Barcelona",
"Carrer del Comte de Santa Clara, la Barceloneta",
"Passatge de Santa Clara, Barcelona",
"Passatge de Santa Clara, Barri Gòtic",
"Baixada de Santa Clara, Barcelona",
"Baixada de Santa Clara, Barri Gòtic",
"Carrer de Santa Clara, Girona",
"Plaça de Santa Clara, Vic",
"Carrer de Santa Clara, Poble Nou",
"Carrer de Santa Clara (Poble Nou), Sant Vicenç dels Horts",
"Carrer Vell de Santa Clara, Manresa",
"Carrer Nou de Santa Clara, Centre Històric",
"Carrer Nou de Santa Clara (Les Escodines), Manresa",
"Carrer de Santa Clara, Masquefa",
"Carrer Santa Clara, Castelló d'Empúries",
"Carrer de Santa Clara, Vilafranca del Penedès",
"Carrer de Santa Clara, Castelló d'Empúries",
"Carrer Clara Campoamor, Santa Coloma de Gramenet"
"Carrer de Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.03 km]]",
"Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.06 km]]",
"Carrer Santa Clara, Sant Pol de Mar [[2, STREET, 3.000, 0.12 km]]",
"Plaça Santa Clara, Santa Coloma de Farners [[2, STREET, 3.000, 29.76 km]]",
"Carrer del Comte de Santa Clara, Barcelona [[2, STREET, 3.000, 43.84 km]]",
"Carrer del Comte de Santa Clara, la Barceloneta [[2, STREET, 3.000, 43.84 km]]",
"Passatge de Santa Clara, Barcelona [[2, STREET, 3.000, 44.32 km]]",
"Passatge de Santa Clara, Barri Gòtic [[2, STREET, 3.000, 44.32 km]]",
"Baixada de Santa Clara, Barcelona [[2, STREET, 3.000, 44.33 km]]",
"Baixada de Santa Clara, Barri Gòtic [[2, STREET, 3.000, 44.33 km]]",
"Carrer de Santa Clara, Girona [[2, STREET, 3.000, 45.73 km]]",
"Plaça de Santa Clara, Vic [[2, STREET, 3.000, 47.62 km]]",
"Carrer de Santa Clara, Poble Nou [[2, STREET, 3.000, 56.25 km]]",
"Carrer de Santa Clara (Poble Nou), Sant Vicenç dels Horts [[2, STREET, 3.000, 56.25 km]]",
"Carrer Vell de Santa Clara, Manresa [[2, STREET, 3.000, 66.96 km]]",
"Carrer Nou de Santa Clara, Centre Històric [[2, STREET, 3.000, 67.15 km]]",
"Carrer Nou de Santa Clara (Les Escodines), Manresa [[2, STREET, 3.000, 67.15 km]]",
"Carrer de Santa Clara, Masquefa [[2, STREET, 3.000, 68.25 km]]",
"Carrer Santa Clara, Castelló d'Empúries [[2, STREET, 3.000, 81.65 km]]",
"Carrer de Santa Clara, Vilafranca del Penedès [[2, STREET, 3.000, 81.86 km]]",
"Carrer de Santa Clara, Castelló d'Empúries [[2, STREET, 3.000, 81.93 km]]",
"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": [
{
"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 sizeId = menu.isBigRightIcon() ? R.dimen.context_menu_big_icon_size : R.dimen.standard_icon_size;
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);
ViewGroup.LayoutParams params = iconView.getLayoutParams();

View file

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

View file

@ -121,7 +121,7 @@ public class QuickSearchHelper implements ResourceListener {
public void refreshFilterOrders() {
PoiFiltersHelper filtersHelper = app.getPoiFilters();
core.setFilterOrders(filtersHelper.getPoiFilterOrders(true));
core.setActivePoiFiltersByOrder(filtersHelper.getPoiFilterOrders(true));
}
public void setRepositoriesForSearchUICore(final OsmandApplication app) {
@ -351,7 +351,7 @@ public class QuickSearchHelper implements ResourceListener {
public boolean search(SearchPhrase phrase, SearchResultMatcher matcher) throws IOException {
double lat = phrase.getSettings().getOriginalLocation().getLatitude();
double lon = phrase.getSettings().getOriginalLocation().getLongitude();
String text = phrase.getRawUnknownSearchPhrase();
String text = phrase.getFullSearchPhrase();
filter.setFilterByName(text);
publishAmenities(phrase, matcher, filter.initializeNewSearch(lat, lon,
-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) {
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());
}

View file

@ -785,13 +785,6 @@ public class QuickSearchDialogFragment extends DialogFragment implements SampleC
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() {
QuickSearchMoreListItem moreListItem =