From 1106994c014f2c9f9268ab1c20d490e211b092cc Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Fri, 5 Aug 2016 14:33:29 +0300 Subject: [PATCH] Update stable search restuls --- .../src/net/osmand/search/SearchUICore.java | 302 +++++++++++------- .../net/osmand/search/core/SearchPhrase.java | 14 +- .../net/osmand/search/LocationSearchTest.java | 3 +- .../search/QuickSearchDialogFragment.java | 107 +++---- 4 files changed, 249 insertions(+), 177 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/search/SearchUICore.java b/OsmAnd-java/src/net/osmand/search/SearchUICore.java index c34c724d29..eaf6f1ae3d 100644 --- a/OsmAnd-java/src/net/osmand/search/SearchUICore.java +++ b/OsmAnd-java/src/net/osmand/search/SearchUICore.java @@ -1,4 +1,14 @@ package net.osmand.search; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import net.osmand.Collator; import net.osmand.OsmAndCollator; @@ -25,23 +35,12 @@ import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - public class SearchUICore { private static final int TIMEOUT_BETWEEN_CHARS = 200; private static final Log LOG = PlatformUtil.getLog(SearchUICore.class); private SearchPhrase phrase; - private SearchResultCollection currentSearchResult = new SearchResultCollection(); + private SearchResultCollection currentSearchResult; private ThreadPoolExecutor singleThreadedExecutor; private LinkedBlockingQueue taskQueue; @@ -52,7 +51,6 @@ public class SearchUICore { List apis = new ArrayList<>(); private SearchSettings searchSettings; private MapPoiTypes poiTypes; - private Collator collator; public SearchUICore(MapPoiTypes poiTypes, String locale) { @@ -60,31 +58,146 @@ public class SearchUICore { taskQueue = new LinkedBlockingQueue(); searchSettings = new SearchSettings(new ArrayList()); searchSettings = searchSettings.setLang(locale); - phrase = new SearchPhrase(searchSettings); + phrase = new SearchPhrase(searchSettings, OsmAndCollator.primaryCollator()); + currentSearchResult = new SearchResultCollection(phrase); singleThreadedExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, taskQueue); - collator = OsmAndCollator.primaryCollator(); } public static class SearchResultCollection { private List searchResults; private SearchPhrase phrase; - public SearchResultCollection(List requestResults, SearchPhrase phrase) { - searchResults = requestResults; + public SearchResultCollection(SearchPhrase phrase) { + searchResults = new ArrayList<>(); this.phrase = phrase; } - public SearchResultCollection() { - searchResults = new ArrayList<>(); + public SearchResultCollection combineWithCollection(SearchResultCollection collection, boolean resort, boolean removeDuplicates) { + SearchResultCollection src = new SearchResultCollection(phrase); + src.addSearchResults(searchResults, false, false); + src.addSearchResults(collection.searchResults, resort, removeDuplicates); + return src; } - + + + + public void addSearchResults(List sr, boolean resortAll, boolean removeDuplicates) { + if(resortAll) { + this.searchResults.addAll(sr); + sortSearchResults(); + if(removeDuplicates) { + filterSearchDuplicateResults(); + } + } else { + if(removeDuplicates) { + ArrayList addedResults = new ArrayList<>(sr); + SearchResultComparator cmp = new SearchResultComparator(phrase); + Collections.sort(addedResults, cmp); + filterSearchDuplicateResults(addedResults); + int i = 0; + int j = 0; + while(j < addedResults.size()) { + SearchResult addedResult = addedResults.get(j); + if(i >= searchResults.size()) { + if(searchResults.size() == 0 || + !sameSearchResult(addedResult, searchResults.get(searchResults.size() - 1))) { + searchResults.add(addedResult); + } + j++; + continue; + } + SearchResult existingResult = searchResults.get(i); + if(sameSearchResult(addedResult, existingResult)) { + j++; + continue; + } + int compare = cmp.compare(existingResult, addedResult); + if(compare == 0) { + // existingResult == addedResult + j++; + } else if(compare > 0) { + // existingResult > addedResult + this.searchResults.add(addedResults.get(j)); + j++; + } else { + // existingResult < addedResult + i++; + } + } + + } + } + + } + public List getCurrentSearchResults() { - return searchResults; + return Collections.unmodifiableList(searchResults); } public SearchPhrase getPhrase() { return phrase; } + + public void sortSearchResults() { + Collections.sort(searchResults, new SearchResultComparator(phrase)); + } + + public void filterSearchDuplicateResults() { + filterSearchDuplicateResults(searchResults); + } + + private void filterSearchDuplicateResults(List lst) { + Iterator it = lst.iterator(); + SearchResult found = null; + while(it.hasNext()) { + SearchResult r = it.next(); + if(found != null && sameSearchResult(found, r)) { + it.remove(); + } else { + found = r; + } + } + } + + + + public boolean sameSearchResult(SearchResult r1, SearchResult r2) { + if(r1.location != null && r2.location != null) { + Amenity a1 = null; + if(r1.object instanceof Amenity) { + a1 = (Amenity) r1.object; + } + Amenity a2 = null; + if(r2.object instanceof Amenity) { + a2 = (Amenity) r2.object; + } + if (r1.localeName.equals(r2.localeName)) { + double similarityRadius = 30; + if (a1 != null && a2 != null) { + // here 2 points are amenity + String type1 = a1.getType().getKeyName(); + String type2 = a2.getType().getKeyName(); + String subType1 = a1.getSubType(); + String subType2 = a2.getSubType(); + if (!type1.equals(type2)) { + return false; + } + if (type1.equals("natural")) { + similarityRadius = 10000; + } else if (subType1.equals(subType2)) { + if (subType1.contains("cn_ref") || subType1.contains("wn_ref") + || (subType1.startsWith("route_hiking_") && subType1.endsWith("n_poi"))) { + similarityRadius = 10000; + } + } + } else if(ObjectType.isAddress(r1.objectType) && ObjectType.isAddress(r2.objectType)) { + similarityRadius = 100; + } + return MapUtils.getDistance(r1.location, r2.location) < similarityRadius; + } + } + return false; + } } public void setPoiTypes(MapPoiTypes poiTypes) { @@ -111,7 +224,6 @@ public class SearchUICore { public SearchResultCollection shallowSearch(Class cl, String text, final ResultMatcher matcher) throws IOException { - SearchResultCollection quickRes = new SearchResultCollection(); T api = getApiByClass(cl); if(api != null) { SearchPhrase sphrase = this.phrase.generateNewPhrase(text, searchSettings); @@ -120,14 +232,13 @@ public class SearchUICore { SearchResultMatcher rm = new SearchResultMatcher(matcher, ai.get(), ai, totalLimit); api.search(sphrase, rm); - sortSearchResults(sphrase, rm.getRequestResults()); - filterSearchDuplicateResults(sphrase, rm.getRequestResults()); - - LOG.info(">> Shallow Search phrase " + phrase + " " + rm.getRequestResults().size()); - return new SearchResultCollection(rm.getRequestResults(), + SearchResultCollection collection = new SearchResultCollection( sphrase); + collection.addSearchResults(rm.getRequestResults(), true, true); + LOG.info(">> Shallow Search phrase " + phrase + " " + rm.getRequestResults().size()); + return collection; } - return quickRes; + return null; } public void init() { @@ -201,11 +312,10 @@ public class SearchUICore { } public SearchResultCollection search(final String text, final ResultMatcher matcher) { - SearchResultCollection quickRes = new SearchResultCollection(); final int request = requestNumber.incrementAndGet(); final SearchPhrase phrase = this.phrase.generateNewPhrase(text, searchSettings); this.phrase = phrase; - quickRes.phrase = phrase; + SearchResultCollection quickRes = new SearchResultCollection(phrase); filterCurrentResults(quickRes.searchResults, phrase); LOG.info("> Search phrase " + phrase + " " + quickRes.searchResults.size()); singleThreadedExecutor.submit(new Runnable() { @@ -222,12 +332,11 @@ public class SearchUICore { } searchInBackground(phrase, rm); if (!rm.isCancelled()) { - sortSearchResults(phrase, rm.getRequestResults()); - filterSearchDuplicateResults(phrase, rm.getRequestResults()); - LOG.info(">> Search phrase " + phrase + " " + rm.getRequestResults().size()); - SearchResultCollection collection = new SearchResultCollection(rm.getRequestResults(), + SearchResultCollection collection = new SearchResultCollection( phrase); + collection.addSearchResults(rm.getRequestResults(), true, true); + LOG.info(">> Search phrase " + phrase + " " + rm.getRequestResults().size()); currentSearchResult = collection; if (onResultsComplete != null) { onResultsComplete.run(); @@ -267,6 +376,7 @@ public class SearchUICore { } try { api.search(phrase, matcher); + matcher.apiSearchFinished(api, phrase); } catch (Throwable e) { e.printStackTrace(); @@ -284,92 +394,10 @@ public class SearchUICore { phrase.sortFiles(); } - public boolean sameSearchResult(SearchResult r1, SearchResult r2) { - if(r1.location != null && r2.location != null) { - Amenity a1 = null; - if(r1.object instanceof Amenity) { - a1 = (Amenity) r1.object; - } - Amenity a2 = null; - if(r2.object instanceof Amenity) { - a2 = (Amenity) r2.object; - } - if (r1.localeName.equals(r2.localeName)) { - double similarityRadius = 30; - if (a1 != null && a2 != null) { - // here 2 points are amenity - String type1 = a1.getType().getKeyName(); - String type2 = a2.getType().getKeyName(); - String subType1 = a1.getSubType(); - String subType2 = a2.getSubType(); - if (!type1.equals(type2)) { - return false; - } - if (type1.equals("natural")) { - similarityRadius = 10000; - } else if (subType1.equals(subType2)) { - if (subType1.contains("cn_ref") || subType1.contains("wn_ref") - || (subType1.startsWith("route_hiking_") && subType1.endsWith("n_poi"))) { - similarityRadius = 10000; - } - } - } else if(ObjectType.isAddress(r1.objectType) && ObjectType.isAddress(r2.objectType)) { - similarityRadius = 100; - } - return MapUtils.getDistance(r1.location, r2.location) < similarityRadius; - } - } - return false; - } - - public void filterSearchDuplicateResults(SearchPhrase sp, List searchResults) { - Iterator it = searchResults.iterator(); - SearchResult found = null; - while(it.hasNext()) { - SearchResult r = it.next(); - if(found != null && sameSearchResult(found, r)) { - it.remove(); - } else { - found = r; - } - } - } - public void sortSearchResults(SearchPhrase sp, List searchResults) { - // sort SearchResult by 1. searchDistance 2. Name - final LatLon loc = sp.getLastTokenLocation(); - Collections.sort(searchResults, new Comparator() { - - @Override - public int compare(SearchResult o1, SearchResult o2) { - if(o1.getFoundWordCount() != o2.getFoundWordCount()) { - return -Algorithms.compare(o1.getFoundWordCount(), o2.getFoundWordCount()); - } - double s1 = o1.getSearchDistance(loc); - double s2 = o2.getSearchDistance(loc); - int cmp = Double.compare(s1, s2); - if(cmp != 0) { - return cmp; - } - int st1 = Algorithms.extractFirstIntegerNumber(o1.localeName); - int st2 = Algorithms.extractFirstIntegerNumber(o2.localeName); - if(st1 != st2) { - return Algorithms.compare(st1, st2); - } - cmp = collator.compare(o1.localeName, o2.localeName); - if(cmp != 0) { - return cmp; - } - s1 = o1.getSearchDistance(loc, 1); - s2 = o2.getSearchDistance(loc, 1); - return Double.compare(s1, s2); - } - }); - } - public static class SearchResultMatcher - implements ResultMatcher{ + public static class SearchResultMatcher implements ResultMatcher{ private final List requestResults = new ArrayList<>(); private final ResultMatcher matcher; private final int request; @@ -439,5 +467,43 @@ public class SearchUICore { boolean cancelled = request != requestNumber.get(); return cancelled || (matcher != null && matcher.isCancelled()); } - } + } + + public static class SearchResultComparator implements Comparator { + private SearchPhrase sp; + private Collator collator; + private LatLon loc; + + public SearchResultComparator(SearchPhrase sp) { + this.sp = sp; + this.collator = sp.getCollator(); + loc = sp.getLastTokenLocation(); + } + + @Override + public int compare(SearchResult o1, SearchResult o2) { + if(o1.getFoundWordCount() != o2.getFoundWordCount()) { + return -Algorithms.compare(o1.getFoundWordCount(), o2.getFoundWordCount()); + } + double s1 = o1.getSearchDistance(loc); + double s2 = o2.getSearchDistance(loc); + int cmp = Double.compare(s1, s2); + if(cmp != 0) { + return cmp; + } + int st1 = Algorithms.extractFirstIntegerNumber(o1.localeName); + int st2 = Algorithms.extractFirstIntegerNumber(o2.localeName); + if(st1 != st2) { + return Algorithms.compare(st1, st2); + } + cmp = collator.compare(o1.localeName, o2.localeName); + if(cmp != 0) { + return cmp; + } + s1 = o1.getSearchDistance(loc, 1); + s2 = o2.getSearchDistance(loc, 1); + return Double.compare(s1, s2); + } + + } } diff --git a/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java index da4ff11fa4..93d2e7baf3 100644 --- a/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java @@ -9,8 +9,10 @@ import java.util.List; import java.util.TreeSet; import java.util.regex.Pattern; +import net.osmand.Collator; import net.osmand.CollatorStringMatcher; import net.osmand.CollatorStringMatcher.StringMatcherMode; +import net.osmand.OsmAndCollator; import net.osmand.StringMatcher; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; @@ -37,6 +39,7 @@ public class SearchPhrase { private static final String DELIMITER = " "; private static final String ALLDELIMITERS = "\\s|,"; private static final Pattern reg = Pattern.compile(ALLDELIMITERS); + private Collator clt; public enum SearchPhraseDataType { @@ -44,12 +47,17 @@ public class SearchPhrase { } - public SearchPhrase(SearchSettings settings) { + public SearchPhrase(SearchSettings settings, Collator clt) { this.settings = settings; + this.clt = clt; + } + + public Collator getCollator() { + return clt; } public SearchPhrase generateNewPhrase(String text, SearchSettings settings) { - SearchPhrase sp = new SearchPhrase(settings); + SearchPhrase sp = new SearchPhrase(settings, this.clt); String restText = text; List leftWords = this.words; String thisTxt = getText(true); @@ -259,7 +267,7 @@ public class SearchPhrase { } public SearchPhrase selectWord(SearchResult res, List unknownWords, boolean lastComplete) { - SearchPhrase sp = new SearchPhrase(this.settings); + SearchPhrase sp = new SearchPhrase(this.settings, this.clt); addResult(res, sp); SearchResult prnt = res.parentSearchResult; while(prnt != null) { diff --git a/OsmAnd-java/test/java/net/osmand/search/LocationSearchTest.java b/OsmAnd-java/test/java/net/osmand/search/LocationSearchTest.java index d0585b1bcc..a5b07f1f08 100644 --- a/OsmAnd-java/test/java/net/osmand/search/LocationSearchTest.java +++ b/OsmAnd-java/test/java/net/osmand/search/LocationSearchTest.java @@ -2,6 +2,7 @@ package net.osmand.search; import java.io.IOException; +import net.osmand.OsmAndCollator; import net.osmand.data.LatLon; import net.osmand.search.SearchUICore.SearchResultMatcher; import net.osmand.search.core.SearchCoreFactory; @@ -16,7 +17,7 @@ public class LocationSearchTest { private void search(String string, LatLon latLon) throws IOException { SearchResultMatcher srm = new SearchUICore.SearchResultMatcher(null, 0, null, 100); new SearchCoreFactory.SearchLocationAndUrlAPI(). - search(new SearchPhrase(null).generateNewPhrase(string, null), srm); + search(new SearchPhrase(null, OsmAndCollator.primaryCollator()).generateNewPhrase(string, null), srm); Assert.assertEquals(1, srm.getRequestResults().size()); Assert.assertEquals(latLon, srm.getRequestResults().get(0).location); } diff --git a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java index 2a0c6869cb..12901fbf70 100644 --- a/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/search/QuickSearchDialogFragment.java @@ -1,5 +1,45 @@ package net.osmand.plus.search; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.osmand.AndroidUtils; +import net.osmand.Location; +import net.osmand.OsmAndCollator; +import net.osmand.ResultMatcher; +import net.osmand.data.LatLon; +import net.osmand.data.PointDescription; +import net.osmand.osm.AbstractPoiType; +import net.osmand.plus.AppInitializer; +import net.osmand.plus.AppInitializer.AppInitializeListener; +import net.osmand.plus.GPXUtilities; +import net.osmand.plus.GPXUtilities.GPXFile; +import net.osmand.plus.GPXUtilities.WptPt; +import net.osmand.plus.LockableViewPager; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.OsmAndLocationProvider.OsmAndCompassListener; +import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandSettings; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.helpers.SearchHistoryHelper; +import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; +import net.osmand.plus.poi.PoiUIFilter; +import net.osmand.plus.search.QuickSearchHelper.SearchHistoryAPI; +import net.osmand.search.SearchUICore; +import net.osmand.search.SearchUICore.SearchResultCollection; +import net.osmand.search.core.ObjectType; +import net.osmand.search.core.SearchCoreAPI; +import net.osmand.search.core.SearchCoreFactory.SearchAmenityTypesAPI; +import net.osmand.search.core.SearchPhrase; +import net.osmand.search.core.SearchResult; +import net.osmand.search.core.SearchSettings; +import net.osmand.search.core.SearchWord; +import net.osmand.util.Algorithms; +import net.osmand.util.MapUtils; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.DialogInterface; @@ -34,46 +74,6 @@ import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; -import net.osmand.AndroidUtils; -import net.osmand.Location; -import net.osmand.ResultMatcher; -import net.osmand.data.LatLon; -import net.osmand.data.PointDescription; -import net.osmand.osm.AbstractPoiType; -import net.osmand.plus.AppInitializer; -import net.osmand.plus.AppInitializer.AppInitializeListener; -import net.osmand.plus.GPXUtilities; -import net.osmand.plus.GPXUtilities.GPXFile; -import net.osmand.plus.GPXUtilities.WptPt; -import net.osmand.plus.LockableViewPager; -import net.osmand.plus.OsmAndFormatter; -import net.osmand.plus.OsmAndLocationProvider.OsmAndCompassListener; -import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.OsmandSettings; -import net.osmand.plus.R; -import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.helpers.SearchHistoryHelper; -import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry; -import net.osmand.plus.poi.PoiUIFilter; -import net.osmand.plus.search.QuickSearchHelper.SearchHistoryAPI; -import net.osmand.search.SearchUICore; -import net.osmand.search.SearchUICore.SearchResultCollection; -import net.osmand.search.core.ObjectType; -import net.osmand.search.core.SearchCoreAPI; -import net.osmand.search.core.SearchCoreFactory.SearchAmenityTypesAPI; -import net.osmand.search.core.SearchPhrase; -import net.osmand.search.core.SearchResult; -import net.osmand.search.core.SearchSettings; -import net.osmand.search.core.SearchWord; -import net.osmand.util.Algorithms; -import net.osmand.util.MapUtils; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - public class QuickSearchDialogFragment extends DialogFragment implements OsmAndCompassListener, OsmAndLocationListener { public static final String TAG = "QuickSearchDialogFragment"; @@ -697,13 +697,13 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC try { SearchResultCollection res = searchUICore.shallowSearch(SearchHistoryAPI.class, "", null); + List rows = new ArrayList<>(); if (res != null) { - List rows = new ArrayList<>(); for (SearchResult sr : res.getCurrentSearchResults()) { rows.add(new QuickSearchListItem(app, sr)); } - historySearchFragment.updateListAdapter(rows, false); } + historySearchFragment.updateListAdapter(rows, false); } catch (IOException e) { e.printStackTrace(); app.showToastMessage(e.getMessage()); @@ -764,7 +764,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC if (paused) { if (results.size() > 0) { - getResultCollection().getCurrentSearchResults().addAll(results); + getResultCollection().addSearchResults(results, true, true); } return false; } @@ -783,7 +783,6 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC apiResults = regionCollection.getCurrentSearchResults(); } else { apiResults = results; - searchUICore.sortSearchResults(phrase, apiResults); } regionResultApi = null; @@ -796,9 +795,12 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC if (!paused) { boolean appended = false; if (getResultCollection() == null || getResultCollection().getPhrase() != phrase) { - setResultCollection(new SearchResultCollection(apiResults, phrase)); + SearchResultCollection resCollection = + new SearchResultCollection(phrase); + resCollection.addSearchResults(results, true, true); + setResultCollection(resCollection); } else { - getResultCollection().getCurrentSearchResults().addAll(apiResults); + getResultCollection().addSearchResults(apiResults, false, true ); appended = true; } if (!hasRegionCollection) { @@ -810,22 +812,17 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC break; case SEARCH_API_REGION_FINISHED: regionResultApi = (SearchCoreAPI) object.object; - - final List regionResults = new ArrayList<>(results); final SearchPhrase regionPhrase = object.requiredSearchPhrase; - searchUICore.sortSearchResults(regionPhrase, regionResults); - + regionResultCollection = new SearchResultCollection(regionPhrase); + regionResultCollection.addSearchResults(results, true, true); app.runInUIThread(new Runnable() { @Override public void run() { if (!paused) { boolean appended = getResultCollection() != null && getResultCollection().getPhrase() == regionPhrase; - regionResultCollection = new SearchResultCollection(regionResults, regionPhrase); if (appended) { - List res = new ArrayList<>(getResultCollection().getCurrentSearchResults()); - res.addAll(regionResults); - SearchResultCollection resCollection = new SearchResultCollection(res, regionPhrase); - searchUICore.filterSearchDuplicateResults(regionPhrase, resCollection.getCurrentSearchResults()); + SearchResultCollection resCollection = + getResultCollection().combineWithCollection(regionResultCollection, false, true); updateSearchResult(resCollection, true); } else { updateSearchResult(regionResultCollection, false);