Initial commit address search refactoring

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

View file

@ -17,12 +17,20 @@ public class CollatorStringMatcher implements StringMatcher {
private final String part;
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,
// TO DO: make a separate method
// trims part to make shorter then full text and tests only first word as base starts with part
TRIM_AND_CHECK_ONLY_STARTS_WITH,
// simple collator contains in any part of the base
CHECK_CONTAINS,
CHECK_ONLY_STARTS_WITH_TRIM,
// simple collator equals
CHECK_EQUALS,
}
@ -42,22 +50,25 @@ public class CollatorStringMatcher implements StringMatcher {
}
public static boolean cmatches(Collator collator, String base, String part, StringMatcherMode mode){
public static boolean cmatches(Collator collator, String fullName, String part, StringMatcherMode mode){
switch (mode) {
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 TRIM_AND_CHECK_ONLY_STARTS_WITH:
if (part.length() > fullName.length()) {
part = part.substring(0, fullName.length());
}
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 +127,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();
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,17 @@ public class SearchUICore {
@Override
public boolean publish(SearchResult object) {
if (phrase != null && object.otherNames != null && !phrase.getNameStringMatcher().matches(object.localeName)) {
// TODO first , other?
if (phrase != null && object.otherNames != null && !phrase.getFirstUnknownNameStringMatcher().matches(object.localeName)) {
for (String s : object.otherNames) {
if (phrase.getNameStringMatcher().matches(s)) {
if (phrase.getFirstUnknownNameStringMatcher().matches(s)) {
object.alternateName = s;
break;
}
}
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;
}
@ -815,7 +815,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) {
@ -963,14 +963,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

@ -140,20 +140,18 @@ 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();
phrase.countUnknownWordsMatchMainResult(res);
// TODO select word & delete found words
List<String> ws = phrase.getUnknownSearchWords(res.otherWordsMatch);
if (!res.firstUnknownWordMatches) {
ws.add(phrase.getUnknownSearchWord());
ws.add(phrase.getFirstUnknownSearchWord());
}
// publish result to set parentSearchResult before search
resultMatcher.publish(res);
if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) {
SearchPhrase nphrase = phrase.selectWord(res, ws,
phrase.isLastUnknownSearchWordComplete());
SearchPhrase nphrase = phrase.selectWord(res, ws, phrase.isLastUnknownSearchWordComplete());
resultMatcher.setParentSearchResult(res);
api.search(nphrase, resultMatcher);
resultMatcher.setParentSearchResult(res.parentSearchResult);
@ -166,8 +164,6 @@ public class SearchCoreFactory {
}
}
public static class SearchRegionByNameAPI extends SearchBaseAPI {
public SearchRegionByNameAPI() {
@ -186,9 +182,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 +206,6 @@ public class SearchCoreFactory {
}
}
private static String stripBraces(String localeName) {
int i = localeName.indexOf('(');
String retName = localeName;
if (i > -1) {
retName = localeName.substring(0, i);
int j = localeName.indexOf(')', i);
if (j > -1) {
retName = retName.trim() + ' ' + localeName.substring(j);
}
}
return retName;
}
public static class SearchAddressByNameAPI extends SearchBaseAPI {
private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000;
@ -310,10 +293,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 +315,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 +326,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 +370,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 +439,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,8 +453,6 @@ 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,
@ -510,35 +484,34 @@ public class SearchCoreFactory {
if (!phrase.isUnknownSearchWordPresent()) {
return false;
}
boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent()
&& phrase.isUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes();
// TODO
// consider 'bar' - 'Hospital 512'
if (!phrase.isNoSelectedType()) {
// don't search by name when type is selected or poi type is part of name
return false;
}
// boolean hasUnselectedType = phrase.isNoSelectedType() && phrase.isUnknownSearchWordPresent()
// && phrase.isMainUnknownSearchWordComplete() && phrase.hasUnknownSearchWordPoiTypes();
// Check feedback before it was searching exact match of whole phrase.getUnknownSearchPhrase()
final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1];
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 +520,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())) {
return false;
}
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 +539,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 +548,7 @@ public class SearchCoreFactory {
@Override
public boolean isCancelled() {
return resultMatcher.isCancelled() && (limit < LIMIT) ;
return resultMatcher.isCancelled() && (limit < LIMIT);
}
});
@ -633,9 +601,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 +611,123 @@ 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);
}
public void setFilterOrders(List<String> filterOrders) {
this.filterOrders = filterOrders;
}
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) throws IOException {
if (translatedNames.isEmpty()) {
translatedNames = types.getAllTranslatedNames(false);
topVisibleFilters = types.getTopVisibleFilters();
categories = types.getCategories(false);
if (priority > 0) {
this.activePoiFilters.put(poiFilter.getFilterId(), priority);
}
}
public void setActivePoiFiltersByOrder(List<String> filterOrder) {
for (int i = 0; i < filterOrder.size(); i++) {
this.activePoiFilters.put(filterOrder.get(i), i);
}
}
public List<AbstractPoiType> getPoiTypeResults(NameStringMatcher nm, boolean includeAdditionals) {
List<AbstractPoiType> results = new ArrayList<AbstractPoiType>();
List<AbstractPoiType> searchWordTypes = new ArrayList<AbstractPoiType>();
NameStringMatcher nm;
String unknownSearchPhrase = phrase.getUnknownSearchPhrase();
boolean showTopFiltersOnly = !phrase.isUnknownSearchWordPresent();
if (phrase.getUnknownSearchWord().length() < unknownSearchPhrase.length()) {
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_ONLY_STARTS_WITH_TRIM);
} else {
nm = new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
}
for (AbstractPoiType pf : topVisibleFilters) {
if (showTopFiltersOnly
|| nm.matches(pf.getTranslation())
|| nm.matches(pf.getEnTranslation())
if (nm.matches(pf.getTranslation()) || nm.matches(pf.getEnTranslation())
|| nm.matches(pf.getSynonyms())) {
results.add(pf);
searchWordTypes.add(pf);
}
}
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);
}
for (PoiCategory c : categories) {
if (!results.contains(c) && (nm.matches(c.getTranslation()) || nm.matches(c.getEnTranslation())
|| nm.matches(c.getSynonyms()))) {
results.add(c);
}
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);
}
List<PoiType> additionals = pt.getPoiAdditionals();
if (additionals != null) {
for (PoiType a : additionals) {
if (!results.contains(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);
}
}
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);
}
List<PoiType> additionals = pt.getPoiAdditionals();
if (additionals != null && includeAdditionals) {
for (PoiType a : additionals) {
if (!results.contains(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);
}
}
}
}
}
}
phrase.setUnknownSearchWordPoiTypes(searchWordTypes);
return results;
}
if (resultMatcher != null) {
String word = phrase.getUnknownSearchWord();
NameStringMatcher startMatch = new NameStringMatcher(word, StringMatcherMode.CHECK_ONLY_STARTS_WITH);
for (AbstractPoiType pt : results) {
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.getFullUnknownNameMatcher();
initPoiTypes();
List<AbstractPoiType> poiTypes = topVisibleFilters;
if (!showTopFiltersOnly) {
poiTypes = getPoiTypeResults(nm, true);
}
for (AbstractPoiType pt : poiTypes) {
SearchResult res = new SearchResult(phrase);
res.localeName = pt.getTranslation();
res.object = pt;
addPoiTypeResult(phrase, resultMatcher, showTopFiltersOnly, getStandardFilterId(pt), res);
}
for (int i = 0; i < customPoiFilters.size(); i++) {
CustomSearchPoiFilter csf = customPoiFilters.get(i);
if (showTopFiltersOnly || nm.matches(csf.getName())) {
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);
}
} else {
res.priority = SEARCH_AMENITY_TYPE_PRIORITY;
resultMatcher.publish(res);
}
}
for (int i = 0; i < customPoiFilters.size(); i++) {
CustomSearchPoiFilter csf = customPoiFilters.get(i);
if (!phrase.isUnknownSearchWordPresent() || 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);
}
}
res.localeName = csf.getName();
res.object = csf;
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();
}
@ -842,68 +806,67 @@ public class SearchCoreFactory {
@Override
public boolean search(final SearchPhrase phrase, final SearchResultMatcher resultMatcher) throws IOException {
SearchPoiTypeFilter poiTypeFilter = null;
String nameFilter = null;
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);
}
NameStringMatcher nm = phrase.getFullUnknownNameMatcher();
searchAmenityTypesAPI.initPoiTypes();
List<AbstractPoiType> presentPoiTypes = searchAmenityTypesAPI.getPoiTypeResults(nm, false);
// TODO get first ?
AbstractPoiType poiType = phrase.getUnknownSearchWordPoiType();
if (poiType != null) {
SearchPoiTypeFilter ptf = getPoiTypeFilter(poiType);
String customName = phrase.getPoiNameFilter(poiType);
if (customName != null) {
poiTypeFilter = getPoiTypeFilter(poiType);
nameFilter = phrase.getPoiNameFilter(poiType);
if (nameFilter != null) {
phrase.setUnknownSearchWordPoiType(poiType);
searchPoi(phrase, resultMatcher, null, customName.length() == 0 ? null : customName, ptf);
}
}
}
if (poiTypeFilter != null) {
QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS);
List<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes();
Set<String> searchedPois = new TreeSet<>();
for (BinaryMapIndexReader r : offlineIndexes) {
ResultMatcher<Amenity> rm = getResultMatcher(phrase, resultMatcher, nameFilter, r, searchedPois);
if (poiTypeFilter instanceof CustomSearchPoiFilter) {
rm = ((CustomSearchPoiFilter) poiTypeFilter).wrapResultMatcher(rm);
}
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest((int) bbox.left,
(int) bbox.right, (int) bbox.top, (int) bbox.bottom, -1, poiTypeFilter, rm);
r.searchPoi(req);
resultMatcher.apiSearchRegionFinished(this, r, phrase);
}
}
return true;
}
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 String nameFilter, 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;
}
// TODO
// 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);
final boolean hasCustomName = !Algorithms.isEmpty(nameFilter);
if (hasCustomName) {
ns = phrase.getNameStringMatcher(customName, phrase.isLastUnknownSearchWordComplete());
ns = phrase.getNameStringMatcher(nameFilter, phrase.isLastUnknownSearchWordComplete());
} else {
ns = phrase.getNameStringMatcher();
ns = phrase.getFirstUnknownNameStringMatcher();
}
return new ResultMatcher<Amenity>() {
@ -930,13 +893,17 @@ public class SearchCoreFactory {
res.localeName = object.getSubType();
}
}
if (phrase.isUnknownSearchWordPresent()
&& !(ns.matches(res.localeName) || ns.matches(res.otherNames))) {
String ref = object.getTagContent(Amenity.REF, null);
if(ref == null || !ns.matches(ref)) {
return false;
if (phrase.isUnknownSearchWordPresent()) {
if (ns.matches(res.localeName) || ns.matches(res.otherNames)) {
phrase.countUnknownWordsMatchMainResult(res);
} else {
res.localeName += " " + ref;
String ref = object.getTagContent(Amenity.REF, null);
if (ref == null || !ns.matches(ref)) {
return false;
} else {
phrase.countUnknownWordsMatch(res, ref, null);
res.localeName += " " + ref;
}
}
}
@ -946,6 +913,7 @@ 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();
@ -969,7 +937,6 @@ public class SearchCoreFactory {
}
private SearchPoiTypeFilter getPoiTypeFilter(AbstractPoiType pt) {
acceptedTypes.clear();
poiAdditionals.clear();
updateTypesToAccept(pt);
@ -1045,16 +1012,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 +1026,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 +1055,6 @@ public class SearchCoreFactory {
}
public static boolean isLastWordCityGroup(SearchPhrase p ) {
return p.isLastWord(ObjectType.CITY) || p.isLastWord(ObjectType.POSTCODE) ||
p.isLastWord(ObjectType.VILLAGE);
}
public static class SearchBuildingAndIntersectionsByStreetAPI extends SearchBaseAPI {
Street cacheBuilding;
@ -1179,7 +1127,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 +1142,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 +1157,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 +1167,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 +1354,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;
@ -10,6 +10,7 @@ import net.osmand.binary.CommonWords;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.osm.AbstractPoiType;
import net.osmand.search.core.SearchPhrase.NameStringMatcher;
import net.osmand.util.Algorithms;
import net.osmand.util.LocationParser;
import net.osmand.util.MapUtils;
@ -27,31 +28,39 @@ 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 = " ";
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 of 2 parts
private List<SearchWord> words = new ArrayList<>();
private String firstUnknownSearchWord = "";
private List<String> otherUnknownWords = new ArrayList<>();
private boolean lastUnknownSearchWordComplete;
// Main unknown word used for search
private String mainUnknownWordToSearch = null;
private boolean mainUnknownSearchWordComplete;
// Name Searchers
private NameStringMatcher firstUnknownNameStringMatcher;
private NameStringMatcher mainUnknownNameStringMatcher;
private List<NameStringMatcher> unknownWordsMatcher = new ArrayList<>();
private QuadRect cache1kmRect;
static {
// 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,83 +158,160 @@ 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;
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())) {
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 == ';';
}
sp.lastUnknownSearchWordComplete = isTextComplete(fullText) ;
return sp;
}
public SearchPhrase selectWord(SearchResult res, List<String> unknownWords, boolean lastComplete) {
SearchPhrase sp = new SearchPhrase(this.settings, this.clt);
addResult(res, sp);
SearchResult prnt = res.parentSearchResult;
while (prnt != null) {
addResult(prnt, sp);
prnt = prnt.parentSearchResult;
}
sp.words.addAll(0, this.words);
if (unknownWords != null) {
sp.lastUnknownSearchWordComplete = lastComplete;
StringBuilder genUnknownSearchPhrase = new StringBuilder();
for (int i = 0; i < unknownWords.size(); i++) {
if (i == 0) {
sp.firstUnknownSearchWord = unknownWords.get(0);
} else {
sp.otherUnknownWords.add(unknownWords.get(i));
}
genUnknownSearchPhrase.append(unknownWords.get(i)).append(" ");
}
sp.fullTextSearchPhrase = fullTextSearchPhrase;
sp.unknownSearchPhrase = genUnknownSearchPhrase.toString().trim();
}
return sp;
}
private void calcMainUnknownWordToSearch() {
if (mainUnknownWordToSearch != null) {
return;
}
List<String> unknownSearchWords = otherUnknownWords;
mainUnknownWordToSearch = firstUnknownSearchWord;
mainUnknownSearchWordComplete = lastUnknownSearchWordComplete;
if (unknownSearchWords.size() > 0) {
mainUnknownSearchWordComplete = true;
List<String> searchWords = new ArrayList<>(unknownSearchWords);
searchWords.add(0, getFirstUnknownSearchWord());
Collections.sort(searchWords, commonWordsComparator);
for (String s : searchWords) {
if (s.length() > 0 && !Character.isDigit(s.charAt(0)) && !LocationParser.isValidOLC(s)) {
mainUnknownWordToSearch = s.trim();
int unknownInd = unknownSearchWords.indexOf(s);
if (!lastUnknownSearchWordComplete && unknownSearchWords.size() - 1 == unknownInd) {
mainUnknownSearchWordComplete = false;
}
break;
}
}
}
}
public List<SearchWord> getWords() {
return words;
}
public boolean isUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete || unknownWords.size() > 0 || unknownSearchWordPoiType != null;
public boolean isMainUnknownSearchWordComplete() {
// return lastUnknownSearchWordComplete || otherUnknownWords.size() > 0 || unknownSearchWordPoiType != null;
// TODO unknownSearchWordPoiType != null;!!!
return mainUnknownSearchWordComplete;
}
public boolean isLastUnknownSearchWordComplete() {
return lastUnknownSearchWordComplete;
}
public NameStringMatcher getFullUnknownNameMatcher() {
// TODO investigate diesel 95
if (isLastUnknownSearchWordComplete() || hasMoreThanOneUnknownSearchWord()) {
return new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.TRIM_AND_CHECK_ONLY_STARTS_WITH);
} else {
return new NameStringMatcher(unknownSearchPhrase, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
}
}
public List<String> getUnknownSearchWords() {
return unknownWords;
public boolean hasMoreThanOneUnknownSearchWord() {
return otherUnknownWords.size() > 0;
}
public List<String> getUnknownSearchWords(Collection<String> exclude) {
if(exclude == null || unknownWords.size() == 0 || exclude.size() == 0) {
return unknownWords;
if(exclude == null || otherUnknownWords.size() == 0 || exclude.size() == 0) {
return otherUnknownWords;
}
List<String> l = new ArrayList<>();
for(String uw : unknownWords) {
for(String uw : otherUnknownWords) {
if(exclude == null || !exclude.contains(uw)) {
l.add(uw);
}
@ -234,12 +320,12 @@ public class SearchPhrase {
}
public String getUnknownSearchWord() {
return unknownSearchWordTrim;
public String getFirstUnknownSearchWord() {
return firstUnknownSearchWord;
}
public String getRawUnknownSearchPhrase() {
return rawUnknownSearchPhrase;
public String getFullSearchPhrase() {
return fullTextSearchPhrase;
}
public String getUnknownSearchPhrase() {
@ -247,64 +333,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 +488,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 +517,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() - 1;
boolean completeMatch = ind < otherUnknownWords.size() - 1 || isLastUnknownSearchWordComplete();
unknownWordsMatcher.add(getNameStringMatcher(otherUnknownWords.get(ind), completeMatch));
}
return unknownWordsMatcher.get(i);
}
public NameStringMatcher getNameStringMatcher(String word, boolean complete) {
private NameStringMatcher getNameStringMatcher(String word, boolean complete) {
return new NameStringMatcher(word,
(complete ?
StringMatcherMode.CHECK_EQUALS_FROM_SPACE :
@ -544,12 +564,12 @@ public class SearchPhrase {
}
}
public String getText(boolean includeLastWord) {
public String getText(boolean includeUnknownPart) {
StringBuilder sb = new StringBuilder();
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 +578,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 +725,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 +748,32 @@ public class SearchPhrase {
}
public void countUnknownWordsMatch(SearchResult sr) {
public void countUnknownWordsMatchMainResult(SearchResult sr) {
countUnknownWordsMatch(sr, sr.localeName, sr.otherNames);
}
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));
}
NameStringMatcher ms = unknownWordsMatcher.get(i);
if (otherUnknownWords.size() > 0) {
for (int i = 0; i < otherUnknownWords.size(); i++) {
NameStringMatcher ms = getUnknownNameStringMatcher(i);
if (ms.matches(localeName) || ms.matches(otherNames)) {
if (sr.otherWordsMatch == null) {
sr.otherWordsMatch = new TreeSet<>();
}
sr.otherWordsMatch.add(unknownWords.get(i));
sr.otherWordsMatch.add(otherUnknownWords.get(i));
}
}
}
if(!sr.firstUnknownWordMatches) {
sr.firstUnknownWordMatches = localeName.equals(getUnknownSearchWord()) ||
getNameStringMatcher().matches(localeName) ||
getNameStringMatcher().matches(otherNames);
sr.firstUnknownWordMatches = localeName.equals(getFirstUnknownSearchWord()) ||
getFirstUnknownNameStringMatcher().matches(localeName) ||
getFirstUnknownNameStringMatcher().matches(otherNames);
}
}
public int getRadiusSearch(int meters, int radiusLevel) {
int res = meters;
for(int k = 0; k < radiusLevel; k++) {
@ -777,18 +794,39 @@ public class SearchPhrase {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
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;
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 getUnknownSearchWord();
return 0;
}
public NameStringMatcher getUnknownWordToSearchBuildingNameMatcher() {
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return getUnknownNameStringMatcher(ind - 1);
} else {
return getFirstUnknownNameStringMatcher();
}
}
public String getUnknownWordToSearchBuilding() {
int ind = getUnknownWordToSearchBuildingInd();
if(ind > 0) {
return otherUnknownWords.get(ind - 1);
} else {
return firstUnknownSearchWord;
}
}
private static int lengthWithoutNumbers(String s) {
int len = 0;
for(int k = 0; k < s.length(); k++) {
@ -802,19 +840,18 @@ 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 wordToSearch;
return lastUnknownSearchWordComplete;
}

View file

@ -17,17 +17,32 @@ public class SearchResult {
// search phrase that makes search result valid
public SearchPhrase requiredSearchPhrase;
// internal package fields (used for sorting)
public SearchResult parentSearchResult;
String wordsSpan ;
// TODO
boolean firstUnknownWordMatches = true;
Collection<String> otherWordsMatch = null;
boolean unknownPhraseMatches = false;
public Object object;
public 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;
@ -40,9 +55,14 @@ public class SearchResult {
res = ObjectType.getTypeWeight(objectType);
}
if (parentSearchResult != null) {
// TODO
// 10 > maximum type
// res = Math.max(res,parentSearchResult.getUnknownPhraseMatchWeight()) ;
res += parentSearchResult.getUnknownPhraseMatchWeight() / 10;
// double x = parentSearchResult.getUnknownPhraseMatchWeight();
// if (x == 0) {
// return 0;
// }
// res = Math.max(res, parentSearchResult.getUnknownPhraseMatchWeight());
res += parentSearchResult.getUnknownPhraseMatchWeight() / 10;
}
return res;
}
@ -77,16 +97,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

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

View file

@ -351,11 +351,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());
@ -369,8 +369,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();
}
}
@ -382,8 +382,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;
@ -628,9 +628,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

@ -123,7 +123,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) {
@ -353,7 +353,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

@ -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 =