Update search

This commit is contained in:
Victor Shcherb 2016-07-12 13:44:04 +03:00
parent e9586c50c7
commit 27cd0f7c5a
4 changed files with 81 additions and 41 deletions

View file

@ -56,10 +56,10 @@ public class BinaryMapAddressReaderAdapter {
List<CitiesBlock> cities = new ArrayList<BinaryMapAddressReaderAdapter.CitiesBlock>(); List<CitiesBlock> cities = new ArrayList<BinaryMapAddressReaderAdapter.CitiesBlock>();
LatLon calculatedCenter = null; LatLon calculatedCenter = null;
public int bottom31; int bottom31;
public int top31; int top31;
public int right31; int right31;
public int left31; int left31;
public String getEnName() { public String getEnName() {
return enName; return enName;

View file

@ -26,6 +26,7 @@ import net.osmand.data.City.CityType;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.data.MapObject; import net.osmand.data.MapObject;
import net.osmand.data.QuadRect; import net.osmand.data.QuadRect;
import net.osmand.data.QuadTree;
import net.osmand.data.Street; import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType; import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes; import net.osmand.osm.MapPoiTypes;
@ -40,11 +41,12 @@ import net.osmand.util.MapUtils;
public class SearchCoreFactory { public class SearchCoreFactory {
// TODO display closest city to villages // TODO display closest city to villages (+)
// TODO search only closest file (global bbox) // TODO search only closest file (global bbox) (+)
// TODO limit to one file if city/street/village/poi selected // TODO limit to one file if city/street/village/poi selected
// TODO fix search amenity by type (category/additional) // TODO fix search amenity by type (category/additional/filter)
// TODO streets by city // TODO streets by city
// TODO amenity by name // TODO amenity by name
@ -54,7 +56,8 @@ public class SearchCoreFactory {
// TODO buildings interpolation // TODO buildings interpolation
// TODO show buildings if street is one or default ( <CITY>, CITY (den ilp), 1186RM) // TODO show buildings if street is one or default ( <CITY>, CITY (den ilp), 1186RM)
// TODO exclude duplicate streets/cities... // TODO exclude duplicate streets/cities...
// TODO MED display results momentarily // TODO MED display results momentarily
// TODO MED add full text search with comma // TODO MED add full text search with comma
// TODO MED add full text search without comma // TODO MED add full text search without comma
@ -82,9 +85,6 @@ public class SearchCoreFactory {
@Override @Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) { public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
if(phrase.hasObjectType(ObjectType.REGION)) {
return false;
}
for (BinaryMapIndexReader bmir : phrase.getOfflineIndexes()) { for (BinaryMapIndexReader bmir : phrase.getOfflineIndexes()) {
if (bmir.getRegionCenter() != null) { if (bmir.getRegionCenter() != null) {
SearchResult sr = new SearchResult(phrase); SearchResult sr = new SearchResult(phrase);
@ -107,7 +107,7 @@ public class SearchCoreFactory {
@Override @Override
public int getSearchPriority(SearchPhrase p) { public int getSearchPriority(SearchPhrase p) {
if(p.getWordLocation() != null) { if(!p.isNoSelectedType()) {
return -1; return -1;
} }
return 1; return 1;
@ -116,9 +116,11 @@ public class SearchCoreFactory {
public static class SearchAddressByNameAPI extends SearchBaseAPI { public static class SearchAddressByNameAPI extends SearchBaseAPI {
private static final int DEFAULT_BBOX_RADIUS = 1000*1000; private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 1000*1000;
private static final int LIMIT = 10000; private static final int LIMIT = 10000;
private Map<BinaryMapIndexReader, List<City>> townCities = new LinkedHashMap<>(); private Map<BinaryMapIndexReader, List<City>> townCities = new LinkedHashMap<>();
private QuadTree<City> townCitiesQR = new QuadTree<City>(new QuadRect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE),
8, 0.55f);
public boolean isLastWordPoi(SearchPhrase p) { public boolean isLastWordPoi(SearchPhrase p) {
return p.isLastWord(ObjectType.POI); return p.isLastWord(ObjectType.POI);
@ -141,14 +143,32 @@ public class SearchCoreFactory {
if (phrase.isNoSelectedType() || if (phrase.isNoSelectedType() ||
phrase.isLastWord(ObjectType.CITY, ObjectType.VILLAGE, ObjectType.POSTCODE) || // ? phrase.isLastWord(ObjectType.CITY, ObjectType.VILLAGE, ObjectType.POSTCODE) || // ?
phrase.isLastWord(ObjectType.REGION) || phrase.getRadiusLevel() >= 2) { phrase.isLastWord(ObjectType.REGION) || phrase.getRadiusLevel() >= 2) {
// int letters = phrase.getLastWord().length() / 3 + 1;
final boolean locSpecified = phrase.getLastTokenLocation() != null; final boolean locSpecified = phrase.getLastTokenLocation() != null;
LatLon loc = phrase.getLastTokenLocation(); LatLon loc = phrase.getLastTokenLocation();
final QuadRect streetBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS); final QuadRect streetBbox = getBBoxToSearch(phrase, DEFAULT_ADDRESS_BBOX_RADIUS);
final QuadRect postcodeBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 5); final QuadRect postcodeBbox = getBBoxToSearch(phrase, DEFAULT_ADDRESS_BBOX_RADIUS * 5);
final QuadRect villagesBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 5); final QuadRect villagesBbox = getBBoxToSearch(phrase, DEFAULT_ADDRESS_BBOX_RADIUS * 3);
final QuadRect cityBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 10); final QuadRect cityBbox = getBBoxToSearch(phrase, DEFAULT_ADDRESS_BBOX_RADIUS * 10);
final int priority = isNoSelectedType(phrase) ? 1 : 3; final int priority = isNoSelectedType(phrase) ? 1 : 3;
Iterator<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes(DEFAULT_ADDRESS_BBOX_RADIUS * 10 *
phrase.getRadiusLevel(), SearchPhraseDataType.ADDRESS);
while(offlineIndexes.hasNext()) {
BinaryMapIndexReader r = offlineIndexes.next();
if(!townCities.containsKey(r)) {
BinaryMapIndexReader.buildAddressRequest(null);
List<City> l = r.getCities(null, BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE);
townCities.put(r, l);
for(City c : l) {
LatLon cl = c.getLocation();
int y = MapUtils.get31TileNumberY(cl.getLatitude());
int x = MapUtils.get31TileNumberX(cl.getLongitude());
QuadRect qr = new QuadRect(x, y, x, y);
townCitiesQR.insert(c, qr);
}
}
}
final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1]; final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1];
ResultMatcher<MapObject> rm = new ResultMatcher<MapObject>() { ResultMatcher<MapObject> rm = new ResultMatcher<MapObject>() {
int limit = 0; int limit = 0;
@ -162,18 +182,19 @@ public class SearchCoreFactory {
sr.file = currentFile[0]; sr.file = currentFile[0];
sr.localeName = object.getName(phrase.getSettings().getLang(), true); sr.localeName = object.getName(phrase.getSettings().getLang(), true);
sr.otherNames = object.getAllNames(true); sr.otherNames = object.getAllNames(true);
sr.localeOtherName = sr.file.getRegionName(); sr.localeRelatedObjectName = sr.file.getRegionName();
sr.location = object.getLocation(); sr.location = object.getLocation();
sr.priorityDistance = 1; sr.priorityDistance = 1;
sr.priority = priority; sr.priority = priority;
int y = MapUtils.get31TileNumberY(object.getLocation().getLatitude()); int y = MapUtils.get31TileNumberY(object.getLocation().getLatitude());
int x = MapUtils.get31TileNumberX(object.getLocation().getLongitude()); int x = MapUtils.get31TileNumberX(object.getLocation().getLongitude());
List<City> closestCities = null;
if (object instanceof Street) { if (object instanceof Street) {
if(locSpecified && !streetBbox.contains(x, y, x, y)) { if(locSpecified && !streetBbox.contains(x, y, x, y)) {
return false; return false;
} }
sr.objectType = ObjectType.STREET; sr.objectType = ObjectType.STREET;
sr.localeOtherName = ((Street)object).getCity().getName(phrase.getSettings().getLang(), true); sr.localeRelatedObjectName = ((Street)object).getCity().getName(phrase.getSettings().getLang(), true);
} else if (object instanceof City) { } else if (object instanceof City) {
CityType type = ((City)object).getType(); CityType type = ((City)object).getType();
if (type == CityType.CITY || type == CityType.TOWN) { if (type == CityType.CITY || type == CityType.TOWN) {
@ -191,6 +212,22 @@ public class SearchCoreFactory {
if (locSpecified && !villagesBbox.contains(x, y, x, y)) { if (locSpecified && !villagesBbox.contains(x, y, x, y)) {
return false; return false;
} }
City c = null;
if(closestCities == null) {
closestCities = townCitiesQR.queryInBox(villagesBbox, new ArrayList<City>());
}
double minDist = -1;
for(City s : closestCities) {
double ll = MapUtils.getDistance(s.getLocation(), object.getLocation());
if(minDist == -1 || ll < minDist) {
c = s;
minDist = ll;
}
}
if(c != null) {
sr.localeRelatedObjectName = c.getName(phrase.getSettings().getLang(), true);
sr.distRelatedObjectName = minDist;
}
sr.objectType = ObjectType.VILLAGE; sr.objectType = ObjectType.VILLAGE;
} }
} else { } else {
@ -207,24 +244,20 @@ public class SearchCoreFactory {
resultMatcher.isCancelled(); resultMatcher.isCancelled();
} }
}; };
Iterator<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes(DEFAULT_BBOX_RADIUS * 10, SearchPhraseDataType.ADDRESS);
while(offlineIndexes.hasNext()) {
BinaryMapIndexReader r = offlineIndexes.next();
if(!townCities.containsKey(r)) {
BinaryMapIndexReader.buildAddressRequest(null);
List<City> l = r.getCities(null, BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE);
townCities.put(r, l);
}
}
for(BinaryMapIndexReader r : phrase.getOfflineIndexes()) { if(phrase.getRadiusLevel() > 1 || phrase.getLastWord().length() > 2) {
currentFile[0] = r; Iterator<BinaryMapIndexReader> offlineIterator = phrase.getOfflineIndexes(DEFAULT_ADDRESS_BBOX_RADIUS * 10 *
SearchRequest<MapObject> req = BinaryMapIndexReader.buildAddressByNameRequest(rm, phrase.getRadiusLevel(), SearchPhraseDataType.ADDRESS);
phrase.getLastWord().toLowerCase(), StringMatcherMode.CHECK_STARTS_FROM_SPACE); while (offlineIterator.hasNext()) {
if(locSpecified) { BinaryMapIndexReader r = offlineIterator.next();
req.setBBoxRadius(loc.getLatitude(), loc.getLongitude(), DEFAULT_BBOX_RADIUS * 20); currentFile[0] = r;
SearchRequest<MapObject> req = BinaryMapIndexReader.buildAddressByNameRequest(rm, phrase
.getLastWord().toLowerCase(), StringMatcherMode.CHECK_STARTS_FROM_SPACE);
if (locSpecified) {
req.setBBoxRadius(loc.getLatitude(), loc.getLongitude(), DEFAULT_ADDRESS_BBOX_RADIUS * 10 * phrase.getRadiusLevel());
}
r.searchAddressDataByName(req);
} }
r.searchAddressDataByName(req);
} }
} }
return true; return true;

View file

@ -133,19 +133,21 @@ public class SearchPhrase {
next = lit.next(); next = lit.next();
if(rect != null) { if(rect != null) {
if(dt == SearchPhraseDataType.POI) { if(dt == SearchPhraseDataType.POI) {
if(next.containsPoiData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom)) { if(next.containsPoiData((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom)) {
return true; return true;
} }
} else if(dt == SearchPhraseDataType.ADDRESS) { } else if(dt == SearchPhraseDataType.ADDRESS) {
if(next.containsAddressData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom)) { // containsAddressData not all maps supported
if(next.containsPoiData((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom) &&
next.containsAddressData()) {
return true; return true;
} }
} else if(dt == SearchPhraseDataType.ROUTING) { } else if(dt == SearchPhraseDataType.ROUTING) {
if(next.containsRouteData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom, 15)) { if(next.containsRouteData((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom, 15)) {
return true; return true;
} }
} else { } else {
if(next.containsMapData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom, 15)) { if(next.containsMapData((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom, 15)) {
return true; return true;
} }
} }

View file

@ -31,8 +31,13 @@ public class SearchResult {
public LatLon location; public LatLon location;
public int preferredZoom = 15; public int preferredZoom = 15;
public String localeName; public String localeName;
public String localeOtherName;
public Collection<String> otherNames; public Collection<String> otherNames;
public String localeRelatedObjectName;
public double distRelatedObjectName;
} }